
package cz.karry.dop.core;

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 MemoryInterface implements 
        SignalListener,
        RegisterListener{
    
    public final static String DOL = "DOL";
    public final static String DOH = "DOH";
    public final static String DIL = "DIL";
    public final static String DIH = "DIH";
    
    private Core core;
    private Signal oeab;
    private LoadRegister dol;
    private LoadRegister doh;
    private LoadRegister dil;
    private LoadRegister dih;
    private EightBitLoBus bus8bLo;
    private EightBitHiBus bus8bHi;
    private Signal lhSignal;
    private Signal oewrSignal;
    
    MemoryInterface(Core core){
        this.core = core;
        
        bus8bLo = new EightBitLoBus(core.bus, "BUS<0:7>");
        bus8bHi = new EightBitHiBus(core.bus, "BUS<8:15>");
        
        try{
            Signal reset = core.getSignal(Core.RESET);
            Signal clk = core.getSignal(Core.CLK);
            
            dol = new LoadRegister(DOL, bus8bLo, reset, clk, core.getSignal(Core.ECOUTWR));
            doh = new LoadRegister(DOH, bus8bHi, reset, clk, core.getSignal(Core.ECOUTWR));

            dil = new LoadRegister(DIL, core.db_bus, reset, clk, core.getSignal(Core.ECINL));
            dih = new LoadRegister(DIH, core.db_bus, reset, clk, core.getSignal(Core.ECINH));
            dil.addChangeListener(this);
            dih.addChangeListener(this);
            
            oeab = core.getSignal(Core.OEAB);
            oeab.addSignalListener(this);

            lhSignal = core.getSignal(Core.LH);
            lhSignal.addSignalListener(this);
            oewrSignal = core.getSignal(Core.OEWR);
            oewrSignal.addSignalListener(this);
            
            core.getSignal(Core.OEINLH).addSignalListener(this);
            core.getSignal(Core.OEINSE).addSignalListener(this);
            core.getSignal(Core.OEINZE).addSignalListener(this);
            
        } catch (Exception ex) {
            Logger.getLogger(Core.class.getName()).log(Level.SEVERE, null, ex);
        }
            
    }

    public Register getDIL() {
        return dil;
    }

    public Register getDIH() {
        return dih;
    }

    public Register getDOL() {
        return dol;
    }

    public Register getDOH() {
        return doh;
    }

    public void signalChangePerformed(Signal signal, boolean active) {
        if (signal.getName().equals(Core.OEAB)){
            if (active){
                core.ab_bus.setValue(core.bus.getValue());
            }else{
                core.ab_bus.setValue(0xffff);
            }
        }
        
        if (signal.getName().equals(Core.OEWR) || signal.getName().equals(Core.LH)){
            if (oewrSignal.isActive()){
                if (lhSignal.isActive()){
                    core.db_bus.setValue(doh.getValue());
                }else{
                    core.db_bus.setValue(dol.getValue());                    
                }
            }else{
                core.db_bus.setValue(0xff);
            }
        }
        
//            core.getSignal(Core.OEINLH).addSignalListener(this);
//            core.getSignal(Core.OEINSE).addSignalListener(this);
//            core.getSignal(Core.OEINZE).addSignalListener(this);        
        if (signal.getName().equals(Core.OEINLH) || 
                signal.getName().equals(Core.OEINSE) ||
                signal.getName().equals(Core.OEINZE)
                ){
            inputChangePerformed();
        }
    }

    public void registerChangePerformed(Register register, int value) {
        if (register.getName().equals(DIL) || register.getName().equals(DIH)){
            inputChangePerformed();
        }
    }

    private void inputChangePerformed() {
        try{
            if (core.getSignal(Core.OEINLH).isActive()){
                // bus = DIH(7:0) DIL(7:0)
                core.bus.setValue(dil.getValue() | (dih.getValue() << 8));
            }else if(core.getSignal(Core.OEINSE).isActive()){
                // Sign extended DIL
                int extend = 0;
                if ((dil.getValue() & 0x80) == 0x80){
                    extend = 0xff00;
                }
                core.bus.setValue(dil.getValue() | extend);
            }else if(core.getSignal(Core.OEINZE).isActive()){
                // Zero extended DIL
                core.bus.setValue(dil.getValue());
            }
        } catch (Exception ex) {
            Logger.getLogger(Core.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


}
