EUControlImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Created by: Louis Monier September 26, 1986 7:19:00 pm PDT
Last Edited by: Louis Monier November 15, 1986 2:14:08 am PST
DIRECTORY Boole, BooleCore, CoreCreate, CoreOps, CoreProperties, Dragon, EUInner, EUUtils, PWCore, PWCoreRoute, PWRoute;
EUControlImpl: CEDAR PROGRAM
IMPORTS Boole, BooleCore, CoreCreate, CoreOps, CoreProperties, EUUtils, PWCore
EXPORTS EUInner =
BEGIN OPEN Boole, BooleCore, CoreCreate, EUInner;
-- The whole control: three pieces assembled with two channels
CreateControl: PUBLIC PROC [] RETURNS [ct: CellType] ~ {
ct ← EUUtils.Fetch["Control"];
IF ct=NIL THEN {
ct ← EUUtils.Extract["Control.sch"];
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 [] RETURNS [ct: CellType] ~ {
ct ← EUUtils.Fetch["SCControl"];
IF ct=NIL THEN {
ct ← EUUtils.Extract["SCControl.sch"];
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];
};
};
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 ← EUUtils.AlpsExtract["InputDriver.sch"];
ins ← inputD;
[] ← CoreOps.VisitWire[FindWire[public, wr], AppendOneInput];
};
AppendOutput: PROC [wire: WR, expr: Expression, clock: ROPENIL, outputDrivers: Outputs] RETURNS [Outputs] ~ {
out: CellType ← EUUtils.AlpsExtract[IF clock=NIL THEN "OutputDriver.sch" ELSE "ClockedOutputDriver.sch"];
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],
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;
};
-- 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: ROPENIL] ~ {
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: ROPENIL] ~ {
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: ROPENIL] ~ {
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;
};
END.
GndAndVdd10Met2MinWidth: PUBLIC PWRoute.WireWidthProc = {
wireWidth ← CDSimpleRules.MinWidth[CDSimpleRules.GetLayer[$cmosB, "metal2"]]
*(IF Rope.Equal[netName, "Vdd"] OR Rope.Equal[netName, "Gnd"] THEN 10 ELSE 1);
};