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);
}
}