

package cz.karry.dop.core.alu;

import cz.karry.dop.core.Bus;
import cz.karry.dop.core.BusListener;
import cz.karry.dop.core.Controller;
import cz.karry.dop.core.Core;
import cz.karry.dop.core.Signal;
import cz.karry.dop.core.SignalListener;
import cz.karry.dop.core.registers.LoadRegister;
import cz.karry.dop.core.registers.Register;
import cz.karry.dop.core.registers.RegisterListener;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author karry
 */
public class Alu implements
    BusListener,
    RegisterListener,
    SignalListener{
    
    // signals names
    public static final String ENW = "ENW";
    public static final String AUXF = "AUXF";
    public static final String W0 = "W0";
    public static final String SIGN = "SIGN";
    public static final String ZERO = "ZERO";
    public static final String CIN = "CIN";
    public static final String CZM = "CZM";
    public static final String OVERF = "OVERF";
    public static final String CY = "CY";
    
    // bus names
    public static final String SUM_BUS = "SUM";
    public static final String S_BUS = "S";
    public static final String R_BUS = "R";
    
    // registers names
    public static final String W_REG = "W";

    private Signal enw;
    private Signal auxf;
    private Signal w0;
    private Signal sign;
    private Signal zero;
    private Signal cin;
    private Signal czm;
    private Signal overf;
    private Signal cy;
    
    private Bus r;
    private Bus sum;
    private Bus s;    
    
    private Flags flags;
    private Core core;
    private LoadRegister w;
    private Czm czmModule;
    private Adder adder;
    private Blf blf;

    public Alu(Core core) {
        this.core = core;
        
        enw = new Wen(core).getEnw();
        auxf = new Signal(AUXF);
        w0 = new Signal(W0);
        sign = new Signal(SIGN);
        zero = new Signal(ZERO);
        cy = new Signal(CY);
        overf = new Signal(OVERF);
        
        
        sum = new Bus(SUM_BUS);
        sum.addBusListener(this);
        
        s = new Bus(S_BUS);
        r = new Bus(R_BUS);        

        flags = new Flags(core);
        
        try {
            czmModule = new Czm(core.getSignal(Core.RESET), core.getSignal(Core.CLK), core.getSignal(Core.UCF), core.getSignal(Core.ECW), core.getSignal(Core.CI0), core.getSignal(Flags.C_FLAG) );
            czm = czmModule.getCzm();
            cin = czmModule.getCin();
            
            adder = new Adder( r,s, sum, cin, cy, overf);
            
            w = new LoadRegister("W", sum, core.getSignal(Core.RESET), core.getSignal(Core.CLK), enw);
            w.addChangeListener(this);
            
            blf = new Blf(w, core.bus, core.getSignal(Flags.C_FLAG), core.getController().getOPBus(), r );            
            
            core.getSignal(Core.OEW).addSignalListener(this);
            
            core.addSignal(enw);
            core.addSignal(auxf);
            core.addSignal(w0);
            core.addSignal(sign);
            core.addSignal(zero);
            core.addSignal(cin);
            core.addSignal(czm);
            core.addSignal(overf);
            core.addSignal(cy);
        } catch (Exception ex) {
            Logger.getLogger(Core.class.getName()).log(Level.SEVERE, null, ex);            
        }

        core.getController().getOP3Signal().addSignalListener(this);
        core.bus.addBusListener(this);
    }

    public Flags getFlags() {
        return flags;
    }

    public void busChangePerformed(Bus bus, int value) {
        if (bus.getName().equals(Core.BUS)){
            if ((value & 0x8000) == 0x8000){
                auxf.setState(true);
            }else{
                auxf.setState(false);
            }
        }
        
        if (bus == sum){
            if ((sum.getValue() & 0x8000) == 0x8000){
                sign.setState(true);
            }else{
                sign.setState(false);
            }
            
            if (sum.getValue() == 0){
                zero.setState(true);
            }else{
                zero.setState(false);
            }
        }
        
    }

    public Signal getOverf() {
        return overf;
    }

    public Register getWRegister() {
        return w;
    }
    
    public Bus getRBus(){
        return r;
    }
    
    public Bus getSBus(){
        return s;
    }
    
    public Bus getSumBus(){
        return sum;
    }

    public void registerChangePerformed(Register register, int value) {
        try {
            
            if (register.getName().equals(Alu.W_REG)){
                if (core.getSignal(Core.OEW).isActive()) {
                    core.bus.setValue(value);
                }
                if ((w.getValue() & 0x01) == 0x01){
                    w0.setState(true);
                }else{
                    w0.setState(false);
                }
            }
            
        } catch (Exception ex) {
            Logger.getLogger(Core.class.getName()).log(Level.SEVERE, null, ex);      
        }
    }

    public void signalChangePerformed(Signal signal, boolean active) {
        if (signal.getName().equals(Core.OEW) && active){
            core.bus.setValue(w.getValue());
        }
        
        if (signal.getName().equals(Controller.OP3)){
            if (active){
                s.setValue(w.getValue());
            }else{
                s.setValue(0);
            }
        }
    }

}
