<> <> <> <> <> DIRECTORY Boole, BooleCore, CD, CoreCreate, CoreOps, CoreProperties, Dragon, EUInner, EUUtils, PWCore, PWRoute, Sisyph; EUControlImpl: CEDAR PROGRAM IMPORTS Boole, BooleCore, CoreCreate, CoreOps, CoreProperties, EUUtils, PWCore, Sisyph EXPORTS EUInner = BEGIN OPEN Boole, BooleCore, CoreCreate, EUInner; <<-- The whole control: three pieces assembled with two channels>> CreateControl: PUBLIC PROC [cx: Sisyph.Context] RETURNS [ct: CellType] ~ { ct _ EUUtils.Fetch["Control"]; IF ct=NIL THEN { ct _ Sisyph.ES["Control.sch", cx]; EUUtils.Store["Control", ct]; }; }; <<-- Ram decoder plus a few odds and ends>> CreateRamControl: PUBLIC PROC [] RETURNS [ct: CellType] ~ { ct _ EUUtils.Fetch["RamControl"]; IF ct=NIL THEN { ct _ CreateRamControlFromEquations[]; EUUtils.Store["RamControl", ct]; }; }; <<-- Standard cell block: carry, cc and DBus>> CreateSCControl: PUBLIC PROC [cx: Sisyph.Context] RETURNS [ct: CellType] ~ { ct _ EUUtils.Fetch["SCControl"]; IF ct=NIL THEN { ct _ Sisyph.ES["SCControl.sch", cx]; EUUtils.Store["SCControl", ct]; }; }; <<-- Control for datapath>> CreateDPControl: PUBLIC PROC [] RETURNS [ct: CellType] ~ { ct _ EUUtils.Fetch["DPControl"]; IF ct=NIL THEN { ct _ CreateDPControlFromEquations[]; EUUtils.Store["DPControl", ct]; }; }; GenRegSelWire: PROC [reg: EUUtils.PipeRange] RETURNS [Wire] ~ { RETURN [Seq[EUUtils.sources[reg].nameSel, EUUtils.sources[reg].sizeSel+2]]; --sources+read+write }; ExprProc: TYPE ~ PROC [i: NAT _ 0] RETURNS [Expression]; AppendInput: PROC [public: Wire, wr: WR, inputD: Inputs] RETURNS [ins: Inputs]~ { AppendOneInput: CoreOps.EachWireProc ~ { IF wire.size#0 THEN RETURN; ins _ CONS[[input: wire, driver: inv], ins]}; inv: CellType _ BooleCore.GetCellLibraryCell["InputDriver"]; ins _ inputD; [] _ CoreOps.VisitWire[FindWire[public, wr], AppendOneInput]; }; AppendOutput: PROC [wire: WR, expr: Expression, clock: ROPE _ NIL, outputDrivers: Outputs] RETURNS [Outputs] ~ { out: CellType _ BooleCore.GetCellLibraryCell[IF clock=NIL THEN "OutputDriver" ELSE "ClockedOutputDriver"]; RETURN [CONS[ [driver: out, pas: IF clock=NIL THEN LIST[["VRef", "VRef"]] ELSE LIST[["Clock", clock], ["VRef", "VRef"]], output: wire, expr: expr], outputDrivers]]; }; -- To be generated by Alps (Ave, Serlet, programatori te salutant!) 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], "reject", "hold", "read", "write", Seq["dStateAd", 4], "enWrtIFUPhA", "enWrtIFUPhB", 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; }; <<-- Creates the control for the bottom of the Datapath>> <<-- 716*2737, 28 inputs, and 89 outputs>> 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[GenRegSelWire[EUUtils.leftRow], GenRegSelWire[EUUtils.rightRow], GenRegSelWire[EUUtils.st2ARow], GenRegSelWire[EUUtils.st2BRow], GenRegSelWire[EUUtils.st3ARow], GenRegSelWire[EUUtils.kRegRow], GenRegSelWire[EUUtils.r2BRow], GenRegSelWire[EUUtils.r3ARow], GenRegSelWire[EUUtils.r3BRow], 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]]]}; <> 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, Nand[fetch, nReject]], And[read, EqualInt[dStateAd, EUUtils.r3BRow]]], -- enable Write < 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) )>> <<>> <<-- 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]]]}; <> 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; }; END.