BICImpl.mesa
Copyright 1987 by Xerox Corporation. All rights reserved.
Louis Monier March 30, 1988 5:22:12 pm PST
DIRECTORY BIC, BitOps, CoreClasses, CoreCreate, CoreIO, CoreFlat, CoreProperties, IO, Ports, Rope, Rosemary, TerminalIO;
BICImpl: CEDAR PROGRAM
IMPORTS BitOps, CoreClasses, CoreCreate, CoreIO, CoreFlat, CoreProperties, IO, Ports, Rosemary, TerminalIO
EXPORTS BIC
=
BEGIN OPEN CoreCreate;
BICName: ROPE = Rosemary.Register[roseClassName: "BIC", init: BICInit, evalSimple: BICSimple, scheduleIfClockEval: TRUE];
InitializeTester: PUBLIC PROC [tester: CellType] = {
Ports.InitTesterDrives[tester, drive, "nEClock", "Clock", "ChipCKIn", "ExtCKIn", "ChipCKOut", "ExtCKOut", "LocCKOut", "nDInB", "nBInB"];
Ports.InitTesterDrives[tester, expect, "nRqOutB", "nDOutB", "nBOutB", "nOrOutB"];
Ports.InitTesterDrives[tester, drive, "DInH", "BInH", "RqIn", "OrInH", "nSStop", "DOEn", "Name", "DBusIn", "Send"];
Ports.InitTesterDrives[tester, expect, "DOutH", "BOutH", "DBusOut", "DCS"];
[] ← Rosemary.SetFixedWire[FindWire[tester.public, "Vdd"], H];
[] ← Rosemary.SetFixedWire[FindWire[tester.public, "CKRecAdj"], H];
[] ← Rosemary.SetFixedWire[FindWire[tester.public, "RecAdj"], H];
[] ← Rosemary.SetFixedWire[FindWire[tester.public, "Gnd"], L];
[] ← Rosemary.SetFixedWire[FindWire[tester.public, "Gnd2V"], L];
};
DecorateCT: PROC [ct: CellType, v: NAT ← 0] = {
CoreProperties.PutCellTypeProp[ct, $VersionNumber, NEW[NAT ← v]];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: BICName];
[] ← CoreFlat.CellTypeCutLabels[ct, "BIC"];
-- new syntax
Ports.SetPorts[ct.public,
LIST["Vdd", "CKRecAdj", "RecAdj", "Gnd", "Gnd2V",
"nEClock", "Clock", "ChipCKIn", "ExtCKIn", "ChipCKOut", "ExtCKOut", "LocCKOut",
"nDInB", "nBInB",
"DInH", "BInH", "RqIn", "OrInH",
"DOutH", "BOutH",
"nSStop", "DOEn", "Name", "DBusIn", "Send", "DBusOut", "DCS"],
ls];
Ports.SetPorts[ct.public,
LIST["nRqOutB", "nDOutB", "nBOutB", "nOrOutB"],
ls, separate];
};
CreateBIC: PUBLIC PROC [fromFile: BOOLFALSE, v: NAT ← 0] RETURNS [ct: CellType ] = {
IF fromFile THEN ct ← CoreIO.RestoreCellType["BIC", NIL]
ELSE {
-- this public conforms to BICForSim.icon in BIC.dale
public: Wire ← WireList[LIST[
-- power
"Vdd", "Gnd", "Gnd2V", "CKRecAdj", "RecAdj",
-- clocks
"nEClock", "Clock", "ChipCKIn", "ExtCKIn",
"ChipCKOut", "ExtCKOut", "LocCKOut",
-- board side
Seq["nDInB", 3], Seq["nBInB", 24],
Seq["nRqOutB", 2], Seq["nDOutB", 3], Seq["nBOutB", 24], "nOrOutB",
-- hybrid side
Seq["DInH", 3], Seq["BInH", 24], Seq["RqIn", 2], Seq["OrInH", 4],
Seq["DOutH", 3], Seq["BOutH", 24],
-- DBus et al.
"nSStop", "DOEn", Seq["Name", 3], Seq["DBusIn", 7], Seq["Send", 4],
"DBusOut", Seq["DCS", 3]
]];
ct ← CoreClasses.CreateUnspecified[public, BICName];
};
CoreProperties.PutCellTypeProp[ct, $VersionNumber, NEW[NAT ← v]];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: BICName];
[] ← CoreFlat.CellTypeCutLabels[ct, "BIC"];
-- new syntax
Ports.SetPorts[ct.public,
LIST["Vdd", "CKRecAdj", "RecAdj", "Gnd", "Gnd2V",
"nEClock", "Clock", "ChipCKIn", "ExtCKIn", "ChipCKOut", "ExtCKOut", "LocCKOut",
"nDInB", "nBInB",
"DInH", "BInH", "RqIn", "OrInH",
"DOutH", "BOutH",
"nSStop", "DOEn", "Name", "DBusIn", "Send", "DBusOut", "DCS"],
ls];
Ports.SetPorts[ct.public,
LIST["nRqOutB", "nDOutB", "nBOutB", "nOrOutB"],
ls, separate];
};
BICState: TYPE = REF BICStateRec;
BICStateRec: TYPE = RECORD[
ports: BIC.BICPorts ← NIL,
resetM, normalM, freezeM, shiftM, normal, freeze, shift, reset: BOOLFALSE,
-- from hybrid to board
bMaster, bSlave: CARD ← 0,      -- 24
orMaster, orSlave: BOOLFALSE,    -- 1
rqMaster, rqSlave: CARD ← 0,      -- 2
-- from board to hybrid
nBMaster, nBSlave: CARD ← 0,     -- 24
nOrFMaster, nOrFSlave: BOOLFALSE,  -- 1
nRqFMaster, nRqFSlave: CARD ← 0,    -- 2
-- control
r1M, r2M, er1M, f1M, f2M, s1M, s2M, s3M, e1M, e2M: BOOLFALSE,
r1S, r2S, er1S, f1S, f2S, s1S, s2S, s3S, e1S, e2S: BOOLFALSE,
deviceIdM, deviceIdS: CARD ← 0, -- 8 bits
chipIdM, chipIdS: CARD ← 0, -- 16 bits
extCkM, extCkS: CARD ← 0, -- 4 bits
intCkM, intCkS: CARD ← 0, -- 4 bits
grantM, grantS: BOOLFALSE,
version: NAT ← 0
];
BICBind: PUBLIC PROC [public: Wire, p: Ports.Port] RETURNS [bicPorts: BIC.BICPorts] ~ {
bicPorts ← NEW[BIC.BICPortsRec];
{OPEN bicPorts;
[Vdd, Gnd, Gnd2V, CKRecAdj, RecAdj] ←
Ports.BindPorts[public, p, "Vdd", "Gnd", "Gnd2V", "CKRecAdj", "RecAdj"];
[nEClock, Clock, ChipCKIn, ExtCKIn] ←
Ports.BindPorts[public, p, "nEClock", "Clock", "ChipCKIn", "ExtCKIn"];
[ChipCKOut, ExtCKOut, LocCKOut] ←
Ports.BindPorts[public, p, "ChipCKOut", "ExtCKOut", "LocCKOut"];
[nDInB, nBInB] ←
Ports.BindPorts[public, p, "nDInB", "nBInB"];
[nRqOutB, nDOutB, nBOutB, nOrOutB] ←
Ports.BindPorts[public, p, "nRqOutB", "nDOutB", "nBOutB", "nOrOutB"];
[DInH, BInH, RqIn, OrInH] ←
Ports.BindPorts[public, p, "DInH", "BInH", "RqIn", "OrInH"];
[DOutH, BOutH] ←
Ports.BindPorts[public, p, "DOutH", "BOutH"];
[nSStop, DOEn, Name, DBusIn, Send] ←
Ports.BindPorts[public, p, "nSStop", "DOEn", "Name", "DBusIn", "Send"];
[DBusOut, DCS] ←
Ports.BindPorts[public, p, "DBusOut", "DCS"];
};
};
BICInit: Rosemary.InitProc = {
state: BICState ← NEW[BICStateRec];
state.ports ← BICBind[cellType.public, p];
{OPEN state.ports;
Ports.PD[ChipCKOut, drive];
Ports.PD[ExtCKOut, drive];
Ports.PD[LocCKOut, drive];
Ports.PD[DOutH, drive];
Ports.PD[BOutH, drive];
Ports.PD[DBusOut, drive];
Ports.PD[DCS, drive];
state.version ← NARROW[CoreProperties.GetCellTypeProp[cellType, $VersionNumber], REF NAT]^;
};
stateAny ← state;
};
debug: BOOLFALSE;
targetVersion: INT ← 0;
BtoR: PROC [b: BOOL, nameIfTrue: ROPE] RETURNS [ROPE] ~ {
RETURN[IF b THEN nameIfTrue ELSE " "];
};
LtoR: PROC [l: Ports.Level] RETURNS [ROPE] ~ {
RETURN[SELECT l FROM L => "L", H => "H", ENDCASE => "X"];
};
AssertionFailed: SIGNAL [message: ROPE] = CODE;
BICSimple: Rosemary.EvalProc = {
ShiftOneLeft: PROC [from: CARD, size: NAT, lsb: BOOL] RETURNS [CARD] ~ {
RETURN[BitOps.DShift[from, 1, size]+(IF lsb THEN 1 ELSE 0)];
};
Decoder: PROC [ad: CARD, en: BOOL, s: NAT] RETURNS [sel: CARD] ~ {
sel ← IF ~en THEN 0 ELSE BitOps.TwoToThe[s-1-ad]
};
Assert: PROC [condition: BOOL, message: ROPENIL] =
{IF NOT condition THEN SIGNAL AssertionFailed[message]};
MoreThanOne: PROC [a, b, c, d: BOOLFALSE] RETURNS [BOOLFALSE] ~ {
BtoN: PROC [b: BOOL] RETURNS [NAT] ~ {RETURN[IF b THEN 1 ELSE 0]};
RETURN[BtoN[a]+BtoN[b]+BtoN[c]+BtoN[d]>1];
};
MyGB: PROC [p: Ports.Port] RETURNS [v: BOOL] ~ {
SELECT Ports.GL[p] FROM
L, X => v ← FALSE; -- a hack; see Rick for a real fix in Ports
H => v ← TRUE;
ENDCASE => ERROR;
};
MyGBS: PROC [p: Ports.Port, i: NAT] RETURNS [v: BOOL] ~ {
SELECT Ports.GLS[p, i] FROM
L, X => v ← FALSE; -- a hack; see Rick for a real fix in Ports
H => v ← TRUE;
ENDCASE => ERROR;
};
MyGDW: PROC [p: Ports.Port] RETURNS [v: BitOps.BitDWord] ~ {
size: NAT ← Ports.Size[p];
IF NOT Ports.AnyX[p] THEN RETURN[Ports.GDW[p]];
v ← 0;
FOR i: NAT IN [0..size) DO
bit: BOOLSELECT Ports.GLS[p, i] FROM
H => TRUE,
ENDCASE => FALSE;
v ← BitOps.IBID[bit, v, i, size];
ENDLOOP;
};
MyNot: PROC [from: CARD, to: Ports.Port] ~ {
Ports.PDW[to, BitOps.DNOT[from, Ports.Size[to]]];
};
-- address on 8 bits, id = cid[3] cs[2] rs[3]
ExplodeAddress: PROC [id: CARD] RETURNS [cid, cs, rs: CARDINAL] ~ { 
IF id NOT IN [0..256) THEN ERROR;
cid ← BitOps.ECFD[id, 0, 3, 8]; -- 3 high-order bits: compare to Name
cs ← BitOps.ECFD[id, 3, 2, 8]; -- next 2 bits: this BIC or a client circuit
rs ← BitOps.ECFD[id, 5, 3, 8]; -- 3 low-order bits: scan path in BIC
};
-- set the drive according to the value
OpenCollector: PROC [p: Ports.Port] ~ {
FOR i: NAT IN [0..Ports.Size[p]) DO
SELECT Ports.GLS[p, i] FROM
L, X => Ports.PDS[p, i, drive];
H => Ports.PDS[p, i, driveWeak];
ENDCASE => ERROR;
ENDLOOP;
};
state: BICState ← NARROW[stateAny];
csOn: BOOL;
ck: Ports.Level ← X;
cid, cs, rs, csOt, selScanPath: CARD ← 0;
-- structure of selScanPath
ReadChipID: NAT = 128;
AccessDP: NAT = 64;
ReadExtCK: NAT = 32;
ReadIntCK: NAT = 16;
WriteExtCK: NAT = 8;
WriteIntCK: NAT = 4;
{OPEN Ports, state, state.ports;
-- Unclocked stuff
[cid, cs, rs] ← ExplodeAddress[deviceIdS];
csOn ← (cid=MyGDW[Name]) AND NOT MyGBS[DBusIn, BIC.DAddress] AND MyGBS[DBusIn, BIC.HybridSel];
csOt ← Decoder[ad: cs, en: csOn, s: 4];
selScanPath ← Decoder[ad: rs, en: csOt=8, s: 8];
-- Clocks: we ignore Clock and ExtCKIn
Not[nEClock, LocCKOut];
Not[nEClock, ExtCKOut];
-- at the Rosemary level, the delay lines are invisible
Copy[ChipCKIn, ChipCKOut];
ck ← GL[ChipCKIn]; 
-- ck is the current clock distributed inside the chip
-- Using BIC.DShiftCK as clock
-- DBus address register
SELECT MyGBS[DBusIn, BIC.DShiftCK] FROM
FALSE => {
SELECT TRUE FROM
MyGBS[DBusIn, BIC.DAddress] => deviceIdM ← ShiftOneLeft[deviceIdS, 8, MyGBS[DBusIn, BIC.DSerialIn]]; -- shift chipID
ENDCASE => NULL;
};
TRUE => deviceIdS ← deviceIdM;
ENDCASE => ERROR;
-- (0) ChipID shift register
SELECT MyGBS[DBusIn, BIC.DShiftCK] FROM
FALSE => {
SELECT TRUE FROM
MyGBS[DBusIn, BIC.DAddress] => chipIdM ← BIC.chipID+version; -- load chipID
selScanPath=ReadChipID => chipIdM ← ShiftOneLeft[chipIdS, 16, MyGBS[DBusIn, BIC.DSerialIn]]; -- shift chipID
ENDCASE => NULL;
};
TRUE => chipIdS ← chipIdM;
ENDCASE => ERROR;
-- (2 and 4) External clock shift register
SELECT MyGBS[DBusIn, BIC.DShiftCK] FROM
FALSE => IF selScanPath=ReadExtCK OR selScanPath=WriteExtCK THEN
extCkM ← ShiftOneLeft[extCkS, 4, MyGBS[DBusIn, BIC.DSerialIn]]; -- shift extCkM
TRUE => extCkS ← extCkM;
ENDCASE => ERROR;
-- (3 and 5) Internal clock shift register
SELECT MyGBS[DBusIn, BIC.DShiftCK] FROM
FALSE => IF selScanPath=ReadIntCK OR selScanPath=WriteIntCK THEN
intCkM ← ShiftOneLeft[intCkS, 4, MyGBS[DBusIn, BIC.DSerialIn]]; -- shift extCkM
TRUE => intCkS ← intCkM;
ENDCASE => ERROR;
-- System clock: Control of slices
IF NOT clockEval AND ck=L THEN { -- clock is low: sample the input in all masters
f4: BOOL;
grantM ← MyGDW[Send]#0; -- logical OR
r1M ← MyGBS[DBusIn, BIC.nDReset];
r2M ← r1S;
er1M ← MyGB[nSStop];
f1M ← MyGBS[DBusIn, BIC.nDFreeze];
f2M ← f1S;
s1M ← NOT(MyGBS[DBusIn, BIC.DShiftCK] AND BitOps.EBFD[selScanPath, 1, 8]); -- AccessDP
s2M ← s1S;
s3M ← s2S;
e1M ← MyGBS[DBusIn, BIC.DExecute];
e2M ← e1S;
-- the order of evaluation is important
f4 ← ~(er1S AND f2S);
resetM ← r2S;
freezeM ← ~(r2S AND f4 AND ~(~s2S AND s3S));
shiftM ← ~(~s2S AND s3S AND ~e2S) ;
normalM ← ~(resetM AND freezeM AND shiftM); -- leave as last expression!
Assert[NOT MoreThanOne[normal, freeze, shift, reset]];
orMaster ← MyGDW[OrInH]#0; -- a logical or4 ;
SELECT TRUE FROM
normal => {
bMaster ← IF grantS THEN MyGDW[BInH] ELSE 0;
rqMaster ← MyGDW[RqIn];
nBMaster ← MyGDW[nBInB];
nRqFMaster ← 3; -- because of unconnected 2V receivers
};
reset => {
bMaster ← 0;
rqMaster ← 0;
nBMaster ← 0FFFFFFFFH;
nRqFMaster ← 3;
};
shift => { -- MyGBS[DBusIn, BIC.DSerialIn] to Normal to Request to DPShiftOut; lsb to msb
-- chain is the chain of flops whose outputs, inverted, will become BOutH; the 2 ghost flops do not come out;
chain: CARD ← 0; -- 26 bits
bMaster ← nBSlave;
rqMaster ← nRqFSlave;
chain ← BitOps.ILID[bSlave, chain, 2, 24, 26];
chain ← BitOps.ICID[rqSlave, chain, 0, 2, 26];
chain ← ShiftOneLeft[chain, 26, NOT MyGBS[DBusIn, BIC.DSerialIn]];
nBMaster ← BitOps.ELFD[chain, 2, 24, 26];
nRqFMaster ← BitOps.ECFD[chain, 0, 2, 26];
};
freeze => NULL; -- all flops keep their value except [orMaster, orSlave]
ENDCASE => NULL;
};
IF NOT clockEval AND ck=H THEN {  -- clock is high: copy masters into slaves
grantS ← grantM;
r1S ← r1M;
r2S ← r2M;
er1S ← er1M;
f1S ← f1M;
f2S ← f2M;
s1S ← s1M;
s2S ← s2M;
s3S ← s3M;
e1S ← e1M;
e2S ← e2M;
normal ← NOT normalM;
freeze ← NOT freezeM;
shift ← NOT shiftM;
reset ← NOT resetM;
bSlave ← bMaster;
rqSlave ← rqMaster;
orSlave ← orMaster;
nBSlave ← nBMaster;
nRqFSlave ← nRqFMaster;
nOrFSlave ← nOrFMaster;
};
-- Always copy slaves to outputs
-- 2V outputs (remember to modify to express the wired or: value=0, drive changes)
IF MyGB[DOEn] THEN Not[DInH, nDOutB] ELSE Set[nDOutB, H];
MyNot[bSlave, nBOutB];
PB[nOrOutB, ~ orSlave];
MyNot[rqSlave, nRqOutB];
-- 5V outputs
Not[nDInB, DOutH];
MyNot[nBSlave, BOutH];
PDW[DCS, csOt MOD 8]; -- low-order three bits
PB[DBusOut, SELECT selScanPath FROM
0 => FALSE,    -- RAB of the value; port is tristate
ReadChipID => BitOps.EBFD[chipIdS, 0, 16], -- ChipID
AccessDP => NOT orSlave,  -- DPShiftOut
ReadExtCK => BitOps.EBFD[extCkS, 0, 4], -- ExtCkDelay
ReadIntCK => BitOps.EBFD[intCkS, 0, 4], -- IntCkDelay
WriteExtCK => BitOps.EBFD[extCkS, 0, 4], -- ExtDelayState
WriteIntCK => BitOps.EBFD[intCkS, 0, 4], -- IntDelayState
ENDCASE => ERROR
];
IF selScanPath=0 THEN PD[DBusOut, none]; -- tristate
OpenCollector[nBOutB];
OpenCollector[nOrOutB];
OpenCollector[nRqOutB];
OpenCollector[nDOutB];
IF debug AND state.version=targetVersion THEN {
TerminalIO.PutF["CK=%g %g ", IO.rope[LtoR[ck]], IO.rope[BtoR[clockEval, "clockEval"]]];
TerminalIO.PutF["mode= %g %g %g %g ", IO.rope[BtoR[normal, "normal"]], IO.rope[BtoR[reset, "reset"]], IO.rope[BtoR[shift, "shift"]], IO.rope[BtoR[freeze, "freeze"]]];
TerminalIO.PutF["\n"];
};
}};
END.