CreateRamControlFromEquations:
PROC
RETURNS [cellType: CellType] = {
BEGIN
inputDrivers: Inputs ← NIL;
outputDrivers: Outputs ← NIL;
expr: Expression ← NIL;
selA: Wire ← Seq["selA", EUUtils.nRows]; -- outputs of the y-decoder
selB: Wire ← Seq["selB", EUUtils.nRows];
selC: Wire ← Seq["selC", EUUtils.nRows];
selALow: Wire ← Seq["selALow", 4]; -- outputs of the x-decoder
selBLow: Wire ← Seq["selBLow", 4];
selCLow: Wire ← Seq["selCLow", 4];
selRam: Wire ← WireList[wrs: LIST[selA, selB, selC, selALow, selBLow, selCLow], name: "selRam"];
-- public
public: Wire ← WireList[
LIST[
"Vdd", "Gnd", "VRef", "phA",
selRam,
Seq["ramAdr", 24],
Seq["ramAdr", 3, Wires[Seq["Hi", 6], Seq["Low", 2]]],
"reject", "hold", "read", "write",
Seq["dStateAd", 4], "enWrtIFUPhA", "enWrtIFUPhB",
EUUtils.GenRegSelWire[EUUtils.fieldRow]]]; -- selFieldSrc[0..2)
-- All the wires used as inputs (numbers)
dStateAd: Wire ← FindWire[public, "dStateAd"];
ramAdr: Wire ← FindWire[public, "ramAdr"];
aHi: Wire ← Range[ramAdr, 0, 6];
aLow: Wire ← Range[ramAdr, 6, 2];
bHi: Wire ← Range[ramAdr, 8, 6];
bLow: Wire ← Range[ramAdr, 14, 2];
cHi: Wire ← Range[ramAdr, 16, 6];
cLow: Wire ← Range[ramAdr, 22, 2];
cAdr: Wire ← Range[ramAdr, 16, 8];
-- Expressions (booleans)
read: Variable ← FindWire[public, "read"];
write: Variable ← FindWire[public, "write"];
reject: Variable ← FindWire[public, "reject"];
nReject: Expression ← Not[reject];
hold: Variable ← FindWire[public, "hold"];
nHold: Expression ← Not[hold];
AppendRamDriver:
PROC [output:
WR, expr: Expression] ~ {
outputDrivers ← AppendOutput[output , expr, "phA", outputDrivers];
};
IF aLow.size#2 OR bLow.size#2 OR cLow.size#2 THEN ERROR;
IF aHi.size#6 OR bHi.size#6 OR cHi.size#6 THEN ERROR;
-- Input inverters to the Alps blocks
inputDrivers ← AppendInput[public, "reject", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "hold", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "read", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "write", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "dStateAd", inputDrivers]; -- 4
inputDrivers ← AppendInput[public, ramAdr, inputDrivers]; -- 24
-- Enable Write on the KBus (IFU side); by luck, same timing as ram
outputDrivers ← AppendOutput["enWrtIFUPhA", EqualInt[cAdr, EUUtils.IFUAdr],
NIL, outputDrivers];
-- enWrtIFUPhA ← cAdr=IFUAdr
outputDrivers ← AppendOutput["enWrtIFUPhB", false,
NIL, outputDrivers];
-- enWrtIFUPhB ← false (if no // debug, never used, so could be removed)
-- Output drivers, all of the same type: they follow PhA
FOR i:
INT
IN [0..EUUtils.nRows)
DO
AppendRamDriver[selA[i], EqualInt[aHi, i]];
-- selHi[i][a] ← aAdrH=i
AppendRamDriver[selB[i], EqualInt[bHi, i]];
-- selHi[i][b] ← bAdrH=i
expr ←
IF i=EUUtils.marAdr/4
THEN Or[reject, EqualInt[cHi, i]]
ELSE And[nReject, EqualInt[cHi, i]];
AppendRamDriver[selC[i], expr];
-- selHi[i][c] ← (cAdrH=i).~reject for i#marAdr/4
-- selHi[marAdr/4][c] ← (cAdrH=i)+reject
ENDLOOP;
FOR i:
INT
IN [0..4)
DO
AppendRamDriver[selALow[i], EqualInt[aLow, i]];
-- selLow[i][a] ← aAdrL=i
AppendRamDriver[selBLow[i], EqualInt[bLow, i]];
-- selLow[i][b] ← bAdrL=i
expr ←
IF i=EUUtils.marAdr
MOD 4
THEN Or[reject, EqualInt[cLow, i]]
ELSE And[nReject, EqualInt[cLow, i]];
AppendRamDriver[selCLow[i], expr];
-- selLow[i][c] ← (cAdrL=i).~reject for i#marAdr MOD 4
-- selHi[marAdr MOD 4][c] ← (cAdrL=i)+reject
ENDLOOP;
-- Control for Field register; located here because it requires cAdr; also same timing as ram
outputDrivers ← AppendOutput["selFieldSrc[0]",
And[nReject, nHold, EqualInt[cAdr, EUUtils.fieldAdr]], "phA", outputDrivers];
-- selFieldSrc[0] ← (cAdr=fieldAdr).~reject.~hold.PhA
outputDrivers ← AppendOutput["selFieldSrc[1]",
And[write, EqualInt[dStateAd, EUUtils.fieldRow]], NIL, outputDrivers];
-- selFieldSrc[1] ← (dStateAd=field).write
outputDrivers ← AppendOutput["selFieldSrc[2]",
And[read, EqualInt[dStateAd, EUUtils.fieldRow]], NIL, outputDrivers];
-- selFieldSrc[2] ← (dStateAd=field).read
cellType ← AlpsCell[
name: "RamControl",
public: public,
inputs: inputDrivers,
outputs: outputDrivers,
props: CoreProperties.Props[[$ContactPolyMetal2, NEW[INT ← 20]]]
];
END;
};
CreateDPControlFromEquations:
PROC
RETURNS [cellType: CellType] = {
BEGIN
-- Control of input muxes for pipeline registers, and their DBus
MakeRegSelExpr:
PROC [reg: EUUtils.PipeRange, exprProc: ExprProc, clock:
ROPE ←
NIL] ~ {
size: NAT ← EUUtils.sources[reg].sizeSel;
FOR i:
INT
IN [0..size)
DO
outputDrivers ← AppendOutput[
wire: Index[EUUtils.sources[reg].nameSel, i],
expr: exprProc[i],
clock: clock,
outputDrivers: outputDrivers];
ENDLOOP;
outputDrivers ← AppendOutput[
wire: Index[EUUtils.sources[reg].nameSel, size],
expr: And[write, EqualInt[dStateAd, reg]],
clock: NIL,
outputDrivers: outputDrivers];
outputDrivers ← AppendOutput[
wire: Index[EUUtils.sources[reg].nameSel, size+1],
expr: And[read, EqualInt[dStateAd, reg]],
clock: NIL,
outputDrivers: outputDrivers];
};
MakeTristateSelExpr:
PROC [reg: EUUtils.PipeRange, exprProc: ExprProc, clock, enWClock:
ROPE ←
NIL] ~ {
size: NAT ← EUUtils.sources[reg].sizeSel;
FOR i:
INT
IN [0..size)
DO
outputDrivers ← AppendOutput[
wire: Index[EUUtils.sources[reg].nameSel, i],
expr: exprProc[i],
clock: clock,
outputDrivers: outputDrivers];
ENDLOOP;
outputDrivers ← AppendOutput[
wire: Index[EUUtils.sources[reg].nameSel, size], -- read cBus during debugging
expr: exprProc[size],
clock: clock,
outputDrivers: outputDrivers];
outputDrivers ← AppendOutput[
wire: Index[EUUtils.sources[reg].nameSel, size+1], -- enable write on cBus
expr: exprProc[size+1],
clock: enWClock,
outputDrivers: outputDrivers];
};
MakeSelExpr:
PROC [reg: EUUtils.PipeRange, exprProc: ExprProc, clock, enWClock:
ROPE ←
NIL] ~ {
IF EUUtils.sources[reg].tristate
THEN MakeTristateSelExpr[reg, exprProc, clock, enWClock]
ELSE MakeRegSelExpr[reg, exprProc, clock];
};
inputDrivers: Inputs ← NIL;
outputDrivers: Outputs ← NIL;
public: Wire ← Union[
WireList[LIST["Vdd", "Gnd", "phA", "phB", "nPhB", Seq["selCarry", 5], "enWrtPBusPhA", "enWrtPBusPhB", Seq["ctrl8", 8], "writePBus", "res3BisP", "reject", Seq["aluOp", 4], "hold", "read", "write", Seq["dStateAd", 4], "VRef", Seq["op", 5] ]],
Wires[EUUtils.GenRegSelWire[EUUtils.leftRow],
EUUtils.GenRegSelWire[EUUtils.rightRow],
EUUtils.GenRegSelWire[EUUtils.st2ARow],
EUUtils.GenRegSelWire[EUUtils.st2BRow],
EUUtils.GenRegSelWire[EUUtils.st3ARow],
EUUtils.GenRegSelWire[EUUtils.kRegRow],
EUUtils.GenRegSelWire[EUUtils.r2BRow],
EUUtils.GenRegSelWire[EUUtils.r3ARow],
EUUtils.GenRegSelWire[EUUtils.r3BRow],
EUUtils.GenRegSelWire[EUUtils.dataInRow]],
Wires[Seq["shift", 6], Seq["sh", 33]]];
-- All the wires used as inputs (numbers)
ctrl8: Wire ← FindWire[public, "ctrl8"];
leftSrc: Wire ← Range[ctrl8, 1, 2];
rightSrc: Wire ← Range[ctrl8, 3, 3];
st2ASrc: Wire ← Range[ctrl8, 6, 2];
shift: Wire ← FindWire[public, "shift"];
aluOp: Wire ← FindWire[public, "aluOp"];
dStateAd: Wire ← FindWire[public, "dStateAd"];
-- Expressions (booleans)
reject: Variable ← FindWire[public, "reject"]; -- latched on PhB in the pad
nReject: Expression ← Not[reject];
read: Variable ← FindWire[public, "read"];
write: Variable ← FindWire[public, "write"];
hold: Variable ← FindWire[public, "hold"];
nHold: Expression ← Not[hold];
fetch: Variable ← FindWire[public, "res3BisP"];
store: Variable ← FindWire[public, "writePBus"];
st3AisC: Variable ← FindWire[public, ctrl8[0]];
-- PhA latches
LeftExpr: ExprProc = {
RETURN[And[nReject, nHold, EqualInt[leftSrc, i]]]};
selLeftSrc[i] ← PhA . (leftSrc=i) . ~reject . ~hold
RightExpr: ExprProc = {
RETURN[And[nReject, nHold, EqualInt[rightSrc, i]]]};
-- selRightSrc[i] ← PhA . (rightSrc=i) . ~reject . ~hold
St2AExpr: ExprProc = {
RETURN[And[nReject, nHold, EqualInt[st2ASrc, i]]]};
-- selSt2ASrc[i] ← PhA . (st2ASrc=i) . ~reject . ~hold
R3AExpr: ExprProc = {
RETURN[And[nReject, nHold]]};
-- selRes3ABSrc ← PhA . ~reject . ~hold
St3AExpr: ExprProc = {
RETURN[
SELECT i
FROM
0 => And[nReject, nHold, Not[st3AisC]],
1 => And[nReject, nHold, st3AisC],
ENDCASE => ERROR]};
-- selSt3ABSrc[st2B] ← PhA . ~st3AisC . ~reject . ~hold
-- selSt3ABSrc[cBus] ← PhA . st3AisC . ~reject . ~hold
-- PhB latches
KRegExpr: ExprProc = {
RETURN[nHold]};
-- selKRegAdr ← PhB . ~hold
R2BExpr: ExprProc = {
RETURN[
SELECT i
FROM
0 => And[nHold, Nor[OpIs[FOP], OpIs[BndChk]]], -- aluOut
1 => And[nHold, OpIs[FOP]], -- fuOut
2 => And[nHold, OpIs[BndChk]], -- left
ENDCASE => ERROR]};
-- selRes2BASrc[aluOut] ← PhB . ~hold . (aluOp#FOP AND aluOp#BndChk)
-- selRes2BASrc[fuOut] ← PhB . ~hold . (aluOp=FOP)
-- selRes2BASrc[left] ← PhB . ~hold . (aluOp=BndChk)
St2BExpr: ExprProc = {
RETURN[nHold]};
-- selSt2BASrc ← PhB . ~hold
R3BExpr: ExprProc = {
RETURN[
SELECT i
FROM
0 => nHold, -- input
1 => And[write, EqualInt[dStateAd, EUUtils.r3BRow]], -- read cBus
2 => Or[And[nHold, Nor[fetch, nReject]], And[read, EqualInt[dStateAd, EUUtils.r3BRow]]], -- enable Write
ENDCASE => ERROR]};
-- selRes3BASrc[0] ← PhB . ~hold
-- selRes3BASrc[1] ← PhB . write . (dStateAd=r3B)
-- selRes3BASrc[enW] ← nPhB . ( ~hold.(~fetch+reject) + read.(dStateAd=r3B) )
DataInExpr: ExprProc = {
RETURN[
SELECT i
FROM
0 => nHold, -- input
1 => And[write, EqualInt[dStateAd, EUUtils.dataInRow]], -- read cBus
2 => Or[And[nHold, fetch, nReject], And[read, EqualInt[dStateAd, EUUtils.dataInRow]]], -- enable Write
ENDCASE => ERROR]};
-- selDataInSrc[0] ← PhB . ~hold
-- selDataInSrc[enW] ← nPhB . ( ~hold.fetch.~reject + read.(dStateAd=dataIn) )
-- Special guys
CBusExpr: ExprProc = {RETURN[ -- use the non-latched reject and a simple driver, no clock!!!
SELECT i FROM
0 => Nand[nReject, store, fetch], -- r3B
1 => And[nReject, nHold, fetch], -- dataIn
2 => Or[EqualInt[dStateAd, EUUtils.cBusRow], Not[read]],
ENDCASE => ERROR]};
-- selCBusSrc[r3B] ← (reject + ~fetch + ~store)
-- selCBusSrc[dataIn] ← ~reject . ~hold . fetch
-- selCBusSrc[enW] ← (dStAd=cBus) + ~read
-- Field Unit
ShExpr: ExprProc = {
RETURN[EqualInt[shift, i]]};
-- sh[i] ← (shift=i)
-- ALU
CINisCABExpr: ExprProc = {RETURN[Or[OpIs[SAdd], OpIs[SSub], OpIs[UAdd], OpIs[USub]]]};
InvertCINExpr: ExprProc = {RETURN[Or[OpIs[VSub], OpIs[LSub], OpIs[BndChk], OpIs[SSub], OpIs[USub]]]};
CBAisZeroExpr: ExprProc = {RETURN[Or[OpIs[SAdd], OpIs[SSub], OpIs[LAdd], OpIs[LSub]]]};
CBAisCoutExpr: ExprProc = {RETURN[Or[OpIs[UAdd], OpIs[USub]]]};
InvertCoutExpr: ExprProc = {RETURN[Or[OpIs[VSub], OpIs[LSub], OpIs[BndChk], OpIs[SSub], OpIs[USub]]]};
InvertCoutExpr: ExprProc = {RETURN[OpIs[USub]]};
OpExpr: ExprProc = {
RETURN[
SELECT i
FROM
-- add sub xor or and
0 => Not[InSet[sub]], -- 1 0 1 1 1
1 => InSet[sub, and], -- 0 1 0 0 1
2 => InSet[add, xor], -- 1 0 1 0 0
3 => Not[InSet[add]], -- 0 1 1 1 1
4 => Not[InSet[sub]], -- 1 0 1 1 1
ENDCASE => ERROR];
};
OpType: TYPE = {add, sub, xor, or, and, none};
OpIs:
PROC [op: Dragon.ALUOps]
RETURNS [expr: Expression] ~ {
expr ← EqualInt[aluOp, Dragon.ALUOps[op].ORD];
};
InSet:
PROC [t1, t2: OpType ← none]
RETURNS [expr: Expression] ~ {
AddMatchType:
PROC [op: OpType]
RETURNS [expr: Expression]~ {
expr ←
SELECT op
FROM
add => Or[OpIs[VAdd2], OpIs[SAdd], OpIs[LAdd], OpIs[VAdd], OpIs[UAdd]],
sub => Or[OpIs[BndChk], OpIs[SSub], OpIs[LSub], OpIs[VSub], OpIs[USub]],
xor => OpIs[Xor],
or => Or[OpIs[Or], OpIs[FOP]],
and => OpIs[And],
ENDCASE => ERROR;
};
expr ← AddMatchType[t1];
IF t2#none THEN expr ← Or[expr, AddMatchType[t2]];
};
WrPBusPhAExpr: ExprProc = {
RETURN[And[nReject, nHold]]};
-- enWrtPBusPhA ← ~reject AND ~hold
WrPBusPhBExpr: ExprProc = {
RETURN[And[store, nHold]]};
-- enWrtPBusPhB ← store AND ~hold
-- Inputs from right to left (away from driver)
-- Input Drivers for the (few) signals coming straight from the pads
inputDrivers ← AppendInput[public, "reject", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "hold", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "write", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "read", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "res3BisP", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "writePBus", inputDrivers]; -- 1
inputDrivers ← AppendInput[public, "aluOp", inputDrivers]; -- 4
inputDrivers ← AppendInput[public, "dStateAd", inputDrivers]; -- 4
-- Input Drivers for the signals coming from the Data Path
inputDrivers ← AppendInput[public, "ctrl8", inputDrivers]; -- 8
inputDrivers ← AppendInput[public, "shift", inputDrivers]; -- 6
-- Outputs from bottom to top
-- To pad frame
outputDrivers ← AppendOutput["enWrtPBusPhA", WrPBusPhAExpr[], , outputDrivers];
outputDrivers ← AppendOutput["enWrtPBusPhB", WrPBusPhBExpr[], , outputDrivers];
-- Bottom Registers
MakeSelExpr[EUUtils.dataInRow, DataInExpr, "phB", "nPhB"];
MakeSelExpr[EUUtils.r3BRow, R3BExpr, "phB", "nPhB"];
MakeSelExpr[EUUtils.r3ARow, R3AExpr, "phA"];
MakeSelExpr[EUUtils.st3ARow, St3AExpr, "phA"];
MakeSelExpr[EUUtils.st2BRow, St2BExpr, "phB"];
-- Field unit control
FOR i:
NAT
DECREASING
IN [0..33)
DO
outputDrivers ← AppendOutput[Index["sh", i], ShExpr[i], NIL, outputDrivers];
ENDLOOP;
-- res2BA Register
MakeSelExpr[EUUtils.r2BRow, R2BExpr, "phB"];
-- ALU control
FOR i:
NAT
IN [0..5)
DO
outputDrivers ← AppendOutput[Index["op", i], OpExpr[i], NIL, outputDrivers];
ENDLOOP;
-- Top Registers
MakeSelExpr[EUUtils.st2ARow, St2AExpr, "phA"];
MakeSelExpr[EUUtils.leftRow, LeftExpr, "phA"];
MakeSelExpr[EUUtils.rightRow, RightExpr, "phA"];
MakeSelExpr[EUUtils.kRegRow, KRegExpr, "phB"];
-- Carry
outputDrivers ← AppendOutput[Index["selCarry", 0], CBAisZeroExpr[],, outputDrivers];
outputDrivers ← AppendOutput[Index["selCarry", 1], CBAisCoutExpr[],, outputDrivers];
outputDrivers ← AppendOutput[Index["selCarry", 2], InvertCoutExpr[],, outputDrivers];
outputDrivers ← AppendOutput[Index["selCarry", 3], CINisCABExpr[],, outputDrivers];
outputDrivers ← AppendOutput[Index["selCarry", 4], InvertCINExpr[],, outputDrivers];
-- Generate the block Alps
cellType ← PWCore.RotateCellType[
AlpsCell[name: "UpsideDownDPControl",
public: public, inputs: inputDrivers, outputs: outputDrivers,
props: CoreProperties.Props[[$ContactPolyMetal2, NEW[INT ← 20]]]],
$FlipY];
[] ← CoreOps.SetCellTypeName[cellType, "DPControl"];
END;
};