java/ch/wlkl/processor/Proc1.java

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ch.wlkl.processor;

import static ch.wlkl.env.Env.*;
import static ch.wlkl.env.Meta.*;

/**
 *
 * @author walter
 */
public class Proc1 {
    final public static int stop = 1, trace = 2, go = 3, lit = 4, out = 5, load = 6, store = 7, add = 8, eq = 9, goIfT = 10, dup=11, bad1 = 15;
    final public static int wSz = 8, aSz = 9, awSz = wSz < aSz ? wSz : aSz, regs = 4;

    final static String[] opNames = i2Field(Proc1.class, "stop", "bad1");
    public static String opName(int i) {
        return i >= 0 && i < opNames.length && opNames[i] != null ? opNames[i] : "badOp" + i;
    }

    /*-------------------------------
     the 3 phase clock cycle: 
    
     clockOn: from input reg[*], pc and code compute outputs, 
     clockOn&clockStore: store outputs in rNx[*] and pcNx
     clockOff: store rNx[*] into reg[*], pcNx in pc and m[pcNx] in code

     the middle phase is necessary, to avoid the memory iSet being activated before, the address is correct
     of course, when switching clockk off, the inputs of a register store, could chenge before the iSet is switched off, however, it seems currently not to happen
     -------------------------*/

    final Gate clockOn = new Gate() //
            , clockStore = new Gate() //
            , clockOff = new GateNot(clockOn);

// storage
    final Memory m = new Memory(aSz, wSz);

    final Store[] pcNx = Store.newArray(aSz, clockStore) // next pc
            , pc = Store.newArray(aSz, clockOff, pcNx)   // loaded from pcNx
            , code = Store.newArray(wSz, clockOff, m.out);  // load code from memory
   
    final Store[][] reg = new Store[regs][wSz] // the registers
            , rNx = new Store[regs][wSz];      // and the shadow registers for next cycle
 
// logic for pcNext and code
    final GateOr pcFromLit = new GateOr();  // next pc from literal from code
    final GateAnd pcDelt0 = new GateAnd(new GateNot(pcFromLit));  // bit0 to add to pc, +1 is default
    final GateOr pcDelt1 = new GateOr(); // bit1 to add to pc
    final Gate[] pcDelta = {pcDelt0, pcDelt1};
    final GateAdd pcPlus1 = new GateAdd(pc, Gate.cArTrue), pcPlusDelta = new GateAdd(pc, pcDelta);

// register logic: push / pop    
    final GateOr rPop = new GateOr();
    final GateOr rPop2 = new GateOr();
    final GateOr rPush = new GateOr();
    final GateOr r0New = new GateOr();

// arithmetic and logic
    final GateAdd r0plus1;
    final Gate rNeq = new GateOr(); 
// outputs
    Gate doTrace, doStop, doOut;
    final GateOr doBadOp = new GateOr();

    public Proc1() {
        // pc and code
        for (int a = 0; a < aSz; a++) // load m.adr from pcNext at clockOff  
        {
            m.adr[a].addIn(new GateAnd(clockOff, pcNx[a]));
        }
        GateOr pcAdd = new GateOr(pcDelt0, pcDelt1);
        for (int a = 0; a < awSz; a++) // load pcNext from pcPlus or from memory
            ((GateOr) pcNx[a].iVal).addIn(new GateAnd(pcAdd, pcPlusDelta.out[a])).addIn(new GateAnd(pcFromLit, m.out[a]));
        for (int a = 0; a < wSz; a++) // set memory address to pcPlus1, if we want to jump to it
            m.adr[a].addIn(new GateAnd(pcFromLit, clockOn, pcPlus1.out[a]));

        // registers
        for (int r = 0; r < regs; r++) {
            rNx[r] = Store.newArray(wSz, clockStore);
            reg[r] = Store.newArray(wSz, clockOff, rNx[r]); // load reg[r] from rNx[r]
        }
        
        // load rNx[0] from reg[0, 1, 2] if necessary
        Gate f0 = new GateNot(new GateOr(r0New, rPop, rPop2));  // rPush will load from r[0]
        Gate f1 = new GateAnd(new GateNot(r0New), rPop);
        Gate f2 = new GateAnd(new GateNot(r0New), rPop2);
        for (int b = 0; b < wSz; b++) 
            ((GateOr) rNx[0][b].iVal).addIn(new GateAnd(f0, reg[0][b])).addIn(new GateAnd(f1, reg[1][b])).addIn(new GateAnd(f2, reg[2][b]));

        // load rNx[1..] .. from reg -1, 0, +1, +2
        Gate rEq = new GateNot(new GateOr(rPush, rPop, rPop2));
        for (int r = 1; r < regs; r++) { 
            for (int b = 0; b < wSz; b++) {
                ((GateOr) rNx[r][b].iVal).addIn(new GateAnd(rEq, reg[r][b])).addIn(new GateAnd(rPush, reg[r - 1][b]));
                if (r < regs - 1) {
                    ((GateOr) rNx[r][b].iVal).addIn(new GateAnd(rPop, reg[r + 1][b]));
                }
                if (r < regs - 2) {
                    ((GateOr) rNx[r][b].iVal).addIn(new GateAnd(rPop2, reg[r + 2][b]));
                }
            }
        }

        r0plus1 = new GateAdd(reg[0], reg[1]);  // sum r[0] + r[1] ==> r0Plus1
        for (int a = 0; a < wSz; a++) {         // r[0] != r[1] ==> rNeq
            ((GateOr) rNeq).addIn(new GateNot(new GateOr(new GateAnd(reg[0][a], reg[1][a]), new GateNot(new GateOr(reg[0][a], reg[1][a])))));
        }
        

        // build all ops
        // all high bits of code imply bad op
        GateOr bad = new GateOr();
        int b;
        for (b = wSz - 1; 1 << b >= bad1; b--) {
            bad.addIn(code[b]);
        }
        doBadOp.addIn(bad);
        // make ops for lower bits of code
        makeOp(new GateNot(bad), b, 0);
    }

    private void makeOp(Gate gCon, int b, int first) {
        if (b >= 0) {  // recursively binary tree
            makeOp(new GateAnd(gCon, new GateNot(code[b])), b - 1, first);
            makeOp(new GateAnd(gCon, code[b]), b - 1, first + (1 << b));
        } else if (first == stop) {
            doStop = gCon;
        } else if (first == trace) {
            doTrace = gCon;
        } else if (first == out) {
            doOut = gCon;
            rPop.addIn(gCon);
        } else if (first == go) {
            pcFromLit.addIn(gCon);
        } else if (first == goIfT) {
            pcFromLit.addIn(new GateAnd(gCon, reg[0][0]));
            Gate gF = new GateAnd(gCon, new GateNot(reg[0][0]));
            pcDelt0.addIn(new GateNot(gCon));
            pcDelt1.addIn(gF);
            rPop.addIn(gCon);
        } else if (first == lit) {
            pcDelt0.addIn(new GateNot(gCon));
            pcDelt1.addIn(gCon);
            for (int a = 0; a < awSz; a++) 
                m.adr[a].addIn(new GateAnd(gCon, clockOn, pcPlus1.out[a]));
            for (int a = 0; a < wSz; a++) 
                ((GateOr) rNx[0][a].iVal).addIn(new GateAnd(gCon, m.out[a]));
            rPush.addIn(gCon);
            r0New.addIn(gCon);

        } else if (first == load) {
            for (int a = 0; a < awSz; a++) 
                m.adr[a].addIn(new GateAnd(gCon, clockOn, reg[0][a]));
            for (int a = 0; a < wSz; a++) 
                ((GateOr) rNx[0][a].iVal).addIn(new GateAnd(gCon, m.out[a]));
            r0New.addIn(gCon);

        } else if (first == store) {
            GateAnd g1 = new GateAnd(gCon, clockOn);
            for (int a = 0; a < awSz; a++) 
                m.adr[a].addIn(new GateAnd(g1, reg[0][a]));
            for (int a = 0; a < wSz; a++) 
                ((GateOr) m.iVal[a]).addIn(new GateAnd(g1, reg[1][a]));
            ((GateOr) m.iSet).addIn(new GateAnd(clockStore, gCon));
            rPop2.addIn(gCon);
        } else if (first == add) {
            for (int a = 0; a < wSz; a++) {
                ((GateOr) rNx[0][a].iVal).addIn(new GateAnd(gCon, r0plus1.out[a]));
            }
            r0New.addIn(gCon);
            rPop.addIn(gCon);
        } else if (first == eq) {
            ((GateOr) rNx[0][0].iVal).addIn(new GateAnd(gCon, new GateNot(rNeq)));
            r0New.addIn(gCon);
            rPop.addIn(gCon);
         } else if (first == dup) {
             rPush.addIn(gCon);
       } else {
            doBadOp.addIn(gCon);
        }

    }

    public int loadM(int a, int... cd) {
        for (int i : cd) {
            Memory.i2a(i, m.store[a++]);
        }
        return a;
    }

    public String regText() {
        String t = "";
        for (int r = 0; r < reg.length; r++) {
            t += " r" + r + "=" + Memory.a2i(reg[r]);
        }
        return t; // + " m[30]="+ Memory.a2i(m.store[30]) + " m[31]="+ Memory.a2i(m.store[31]);
    }

    public int run(int start) {
        Memory.i2a(start, pcNx);
        debug(0, "run start pc=" + start);
        int c;
        do {
            c = Memory.a2i(code);
            debug(2, "pc=" + Memory.a2i(pc) + " code=" + c + regText());
            clockOn.set(true);
            clockStore.set(true);
             if (doTrace.get()) 
                out("  trace pc=" + Memory.a2i(pc));
            if (doOut.get()) 
                out("out = " + Memory.a2i(reg[0]));
            if (doBadOp.get()) 
                debug(1, "badOp=" + c + " at pc=" + Memory.a2i(pc));
            if (doStop.get())
                break;
            clockStore.set(false);
            clockOn.set(false);
        } while (true);
        debug(0, "run stop pc=" + Memory.a2i(pc));
        return Memory.a2i(pc);
    }

}