LogicSimpleImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier October 28, 1987 12:03:45 pm PST
Last Edited by: McCreight July 13, 1987 2:54:16 pm PDT
Jean-Marc Frailong November 13, 1987 6:53:34 pm PST
Bertrand Serlet March 30, 1987 10:36:12 pm PST
Christian LeCocq October 17, 1986 6:05:34 pm PDT
Barth, October 10, 1986 5:38:40 pm PDT
Alfred Permuy September 11, 1986 10:19:56 pm PDT
Pradeep Sindhu September 11, 1986 11:38:39 pm PDT
This package contains all basic cells present in the library (nand2, flip-flop, ...) and very simple macros: n-inputs and gates, buffer of arbitrary size, ...
DIRECTORY CoreClasses, CoreCreate, CoreOps, CoreProperties, IO, Logic, LogicUtils, Ports, Real, Rosemary, Sinix;
LogicSimpleImpl: CEDAR PROGRAM
IMPORTS CoreClasses, CoreCreate, CoreOps, CoreProperties, IO, LogicUtils, Ports, Real, Rosemary, Sinix
EXPORTS Logic
= BEGIN OPEN LogicUtils, CoreCreate;
Common types of publics
-- All these types and procedures are common to a lot of the cells in this implementation
IXRef: TYPE = REF IXRec;
IXRec: TYPE = RECORD [in, out: NATLAST[NAT]];
IXInit: Rosemary.InitProc = {
state: IXRef ← IF oldStateAny=NIL THEN NEW[IXRec] ELSE NARROW[oldStateAny];
[state.in, state.out] ← Ports.PortIndexes[cellType.public, "I", "X"];
stateAny ← state;
};
Inverters and receivers
Inverters
-- The vanilla inverter (optionally with double power output) with explicit layout
InvRoseClass: ROPE = RoseClass["Inv", IXInit, InvSimple];
Inv: PUBLIC PROC [buffered: BOOLFALSE] RETURNS [ct: CellType] = {
name: ROPE = IF buffered THEN "InvB" ELSE "Inv";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC[IF buffered THEN "invBuffer" ELSE "inv"];
CacheStore[name, ct];
};
InvSimple: Rosemary.EvalProc = {
state: IXRef ← NARROW[stateAny];
p[state.out].l ← SELECT p[state.in].l FROM L => H, H => L, ENDCASE => X;
};
Raw inverting buffer
-- A sequence of double-power inverters. A buffer of drive d is equivalent to d inverters connected in parallel. This is old stuff that should now be obsolete and be replaced by the inverting driver
Buffer: PUBLIC PROC[d: NAT] RETURNS [ct: CellType] = {
fullName: ROPE = IO.PutFR["Buffer d=%g", IO.int[d]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
IF d=0 THEN Error["Please specify size of buffer"];
ct ← SequenceCell[name: "Buffer", baseCell: Inv[TRUE], count: MAX[(d+1)/2, 1]];
SimulateGate[ct, InvRoseClass];
Ports.InitPorts[ct, l, none, "I"]; Ports.InitPorts[ct, l, drive, "X"];
CacheStore[fullName, ct];
};
Clock buffer: forces the buffers to be distributed among the rows
CKBuffer: PUBLIC PROC[d, numRows: NAT] RETURNS [ct: CellType] = {
fullName: ROPE = IO.PutFR["CKBuffer d=%g numRows=%g ", IO.int[d], IO.int[numRows]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
IF d=0 THEN Error["Please specify sizes for clock buffer"];
IF numRows=0 THEN Error["Please specify number of rows for clock buffer"];
ct ← DistributedSequence[MAX[(d+1)/2, 1], numRows];
SimulateGate[ct, InvRoseClass]; -- a simple non-inverting gate
Ports.InitPorts[ct, l, none, "I"]; Ports.InitPorts[ct, l, drive, "X"];
CacheStore[fullName, ct];
};
-- Distributes the n instances evenly among the rows
DistributedSequence: PROC [n, numRows: NAT] RETURNS [ct: CellType] ~ {
data: CoreClasses.RecordCellType;
delta: NAT = MAX[numRows/n, 1]; -- if n>numRows then 1 else big steps
ct ← SequenceCell[name: "CKBuffer", baseCell: Inv[TRUE], count: n];
ct ← CoreOps.Recast[ct];
IF ct.class#CoreClasses.recordCellClass THEN ERROR;
data ← NARROW[ct.data];
FOR i: NAT IN [0..data.size) DO
row: NAT ← ((i*delta) MOD numRows)+1; -- always in [1..numRows]
CoreProperties.PutCellInstanceProp[data.instances[i], $Row, NEW[INT ← row]];
ENDLOOP;
};
2 Volt receiver
-- A Rec2V is a 2-volt receiver with adjustable threshold for DynaBus interface.
Rec2VRoseClass: ROPE = RoseClass["Rec2V", Rec2VInit, Rec2VSimple];
Rec2V: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "Rec2V";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["rec2V"];
SimulateGate[ct, Rec2VRoseClass];
Ports.InitPorts[ct, l, none, "I", "Vth"]; Ports.InitPorts[ct, l, drive, "X"];
CacheStore[name, ct];
};
RecRef: TYPE = REF RecRec;
RecRec: TYPE = RECORD [in, out, v: NATLAST[NAT]];
Rec2VInit: Rosemary.InitProc = {
state: RecRef ← IF oldStateAny=NIL THEN NEW[RecRec] ELSE NARROW[oldStateAny];
[state.in, state.out, state.v] ← Ports.PortIndexes[cellType.public, "I", "X", "Vth"];
stateAny ← state};
Rec2VSimple: Rosemary.EvalProc = {
state: RecRef ← NARROW[stateAny];
p[state.out].l ← SELECT p[state.v].l FROM
H => Ports.NotL[p[state.in].l],
L => L,
ENDCASE => X;
p[state.in].d ← driveWeak; -- weak pullup is part of the input structure
p[state.in].l ← H;
};
TTL receiver
-- An inverter with a low input threshold.
RecTTLRoseClass: ROPE = RoseClass["RecTTL", IXInit, InvSimple];
RecTTL: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "RecTTL";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["recTTL"];
SimulateGate[ct, RecTTLRoseClass];
Ports.InitPorts[ct, l, none, "I"]; Ports.InitPorts[ct, l, drive, "X"];
CacheStore[name, ct];
};
Drivers
All drivers are able to drive d inverter inputs reasonably fast without exceeding 2 loads on their inputs.
The current structure of drivers is a compromise. Strict correction would require the following implementation using constant amplification ratios to load d inverters on output:
- direct driver, using 2 stages of buffers
ideal: stage1: d**0.333333, stage2: d**0.666666
current: stage1: stage2**0.5, stage2: d/4 (rounded up)
- inverting driver, using 3 stages:
ideal: stage1: d**0.25, stage2: d**0.5, stage3: d**0.75
current: stage1: 1, stage2: stage3**0.5, stage3: d/4 (rounded up)
Although those approximations are not ideal, they do save some space. A little further analysis is in order.
Non-inverting driver
DriverRoseClass: ROPE = RoseClass["Driver", IXInit, DriverSimple];
Driver: PUBLIC PROC [d: NAT] RETURNS [ct: CellType] ~ {
fullName: ROPE = IO.PutFR["Driver d=%g", IO.int[d]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
SELECT d FROM
<=0 => Error["Please specify strength of driver"];
<=4 => ct ← SCBlock[Extract["driver4.sch"]];
<=8 => ct ← SCBlock[Extract["driver8.sch"]];
ENDCASE => { -- use constant amplification in 2 stages, correct up to 64
n2: NAT = (d+3)/4; -- second stage: 1 inverter may drive 4, round up
n1: NAT = Real.Round[Real.SqRt[n2]]; -- first stage, sqrt of second stage
ct ← Extract["driver.sch", LIST[["n1", n1], ["n2", n2]]];
};
SimulateMacro[ct, DriverRoseClass];
Ports.InitPorts[ct, l, none, "I"]; Ports.InitPorts[ct, l, drive, "X"];
CacheStore[fullName, ct];
};
DriverSimple: Rosemary.EvalProc = {
state: IXRef ← NARROW[stateAny];
p[state.out].l ← p[state.in].l;
};
Inverting driver
InvDriver: PUBLIC PROC [d: NAT] RETURNS [ct: CellType] ~ {
fullName: ROPE = IO.PutFR["InvDriver d=%g", IO.int[d]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
SELECT d FROM
<=0 => Error["Please specify strength of inverting driver"];
<=4 => ct ← SCBlock[Extract["invDriver4.sch"]];
<=8 => ct ← SCBlock[Extract["invDriver8.sch"]];
ENDCASE => ct ← Extract["invDriver.sch", LIST[["drv", d]]]; -- use direct driver
SimulateMacro[ct, InvRoseClass];
Ports.InitPorts[ct, l, none, "I"]; Ports.InitPorts[ct, l, drive, "X"];
CacheStore[fullName, ct];
};
Symmetrical driver
SymDriverRoseClass: ROPE = RoseClass["SymDriver", SymDriverInit, SymDriverSimple];
SymDriver: PUBLIC PROC [d: NAT] RETURNS [ct: CellType] ~ {
fullName: ROPE = IO.PutFR["SymDriver d=%g", IO.int[d]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
SELECT d FROM
<=0 => Error["Please specify strength of symmetrical driver"];
<=3 => ct ← SCBlock[Extract["symDriver3.sch"]];
<=6 => ct ← SCBlock[Extract["symDriver6.sch"]];
ENDCASE => { -- use constant amplification in 3 stages, correct up to 64
n2: NAT = (d+3)/4; -- last inverting stage: 1 inverter may drive 4, round up
d1: NAT = d+n2; -- logic drive of initial non-inverting driver
ct ← Extract["symDriver.sch", LIST[["n2", n2], ["d1", d1]]];
};
SimulateMacro[ct, SymDriverRoseClass];
Ports.InitPorts[ct, l, none, "I"]; Ports.InitPorts[ct, l, drive, "X", "nX"];
CacheStore[fullName, ct];
};
SymDriverRef: TYPE = REF SymDriverRec;
SymDriverRec: TYPE = RECORD [in, out, nout: NATLAST[NAT]];
SymDriverInit: Rosemary.InitProc = {
state: SymDriverRef ← IF oldStateAny=NIL THEN NEW[SymDriverRec] ELSE NARROW[oldStateAny];
[state.in, state.out, state.nout] ← Ports.PortIndexes[cellType.public, "I", "X", "nX"];
stateAny ← state;
};
SymDriverSimple: Rosemary.EvalProc = {
state: SymDriverRef ← NARROW[stateAny];
p[state.out].l ← p[state.in].l;
p[state.nout].l ← SELECT p[state.in].l FROM L => H, H => L, ENDCASE => X;
};
Tristate Driver
TstDriverRoseClass: ROPE = RoseClass["TstDriver", TstInit, TstDriverSimple];
TstDriver: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "TstDriver";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["tstDriver"];
SimulateGate[ct, TstDriverRoseClass];
Ports.InitPorts[ct, l, none, "I", "EN", "NEN", "X"];
CacheStore[name, ct];
};
TristateI: PUBLIC PROC RETURNS [ct: CellType] ~ {
fullName: ROPE = "TristateI";
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
ct ← SCBlock[Extract["3BufferI.icon"]];
CacheStore[fullName, ct];
};
TristateNI: PUBLIC PROC RETURNS [ct: CellType] ~ {
fullName: ROPE = "TristateNI";
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
ct ← SCBlock[Extract["3BufferNI.icon"]];
CacheStore[fullName, ct];
};
TstRef: TYPE = REF TstRec;
TstRec: TYPE = RECORD [in, out, en, nEn: NATLAST[NAT]];
TstInit: Rosemary.InitProc = {
state: TstRef ← IF oldStateAny=NIL THEN NEW[TstRec] ELSE NARROW[oldStateAny];
[state.in, state.out, state.en, state.nEn] ← Ports.PortIndexes[cellType.public, "I", "X", "EN", "NEN"];
stateAny ← state;
};
TstDriverSimple: Rosemary.EvalProc = {  -- by Pradeep
state: TstRef ← NARROW[stateAny];
SELECT TRUE FROM
p[state.en].l#L AND p[state.in].l#L => { -- N-Section of TstDriver
p[state.out].d ← drive;
p[state.out].l ← IF p[state.en].l=H AND p[state.in].l=H THEN L ELSE X;
};
p[state.nEn].l#H AND p[state.in].l#H => { -- P-Section of TstDriver
p[state.out].d ← drive;
p[state.out].l ← IF p[state.nEn].l=L AND p[state.in].l=L THEN H ELSE X;
};
ENDCASE => p[state.out].d ← none;
};
And, Nand, Or, Nor
Common part
B4: TYPE = {and, nand, or, nor};
nameInLib: ARRAY B4 OF ROPE = [and: "and", nand: "nand", or: "or", nor: "nor"];
nameOfCT: ARRAY B4 OF ROPE = [and: "And", nand: "Nand", or: "Or", nor: "Nor"];
rootCT: ARRAY B4 OF B4 = [and: nor, nand: nand, or: nand, nor: nor];
leafCT: ARRAY B4 OF B4 = [and: nand, nand: and, or: nor, nor: or];
B4Small: PROC [b4: B4, n: NAT] RETURNS [ct: CellType] ~ {
Compute the celltype for those that have explicit layout
fullName: ROPE = IO.PutFR["%g n=%g", IO.rope[nameOfCT[b4]], IO.int[n]];
sc: CellType;
pas: LIST OF PA;
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
sc ← MakeSC[IO.PutFR["%g%g", IO.rope[nameInLib[b4]], IO.int[n]]];
pas ← LIST[["I-A", "I[0]"], ["I-B", "I[1]"]];
IF n>2 THEN pas ← CONS[["I-C", "I[2]"], pas];
IF n>3 THEN pas ← CONS[["I-D", "I[3]"], pas];
ct ← Cell[name: IO.PutFR["%g%g", IO.rope[nameOfCT[b4]], IO.int[n]],
public: Wires["Vdd", "Gnd", Seq["I", n], "X"],
instances: LIST[InstanceList[sc, pas]]];
CacheStore[fullName, ct];
};
B4Large: PROC [b4: B4, n: NAT] RETURNS [ct: CellType] ~ {
Compute all 4 generic functions
-- and -> nor2(nand)
-- nand -> nand2(and)
-- or -> nand2(nor)
-- nor -> nor2(or)
fullName: ROPE;
input: Wire;
n1: NAT = n/2;
SELECT n FROM
0 => Error[IO.PutFR["Please specify the number of inputs of the `%g' gate", IO.rope[nameInLib[b4]]]];
1 => RETURN [Extract[IF b4=and OR b4=or THEN "wrappedInvPair.sch" ELSE "wrappedInv.sch"]];
<=4 => RETURN [B4Small[b4, n]];
ENDCASE => NULL; -- general case, see below
fullName ← IO.PutFR["%g n=%g", IO.rope[nameOfCT[b4]], IO.int[n]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
Here comes the general case
input ← Seq["I", n];
ct ← Cell[name: IO.PutFR["%g%g", IO.rope[nameOfCT[b4]], IO.int[n]],
instances: LIST[
Instance[B4Small[rootCT[b4], 2], ["I", Wires["One", "Two"]]],
Instance[B4Large[leafCT[b4], n1], ["X", "One"], ["I", Range[input, 0, n1]]],
Instance[B4Large[leafCT[b4], n-n1], ["X", "Two"], ["I", Range[input, n1, n-n1]]]
],
public: Wires["Vdd", "Gnd", input, "X"],
onlyInternal: Wires["One", "Two"]];
CacheStore[fullName, ct];
};
Interface calls
And: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = {ct ← B4Large[and, n]};
Nand: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = {ct ← B4Large[nand, n]};
Or: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = {ct ← B4Large[or, n]};
Nor: PUBLIC PROC[n: NAT] RETURNS [ct: CellType] = {ct ← B4Large[nor, n]};
Complex gates
Xor2
Xor2: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "Xor2";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["xor2"];
CacheStore[name, ct];
};
Xnor2
Xnor2: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "Xnor2";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["xnor2"];
CacheStore[name, ct];
};
A22o2i and O22a2i
A22o2i: PUBLIC PROC[] RETURNS [ct: CellType] = {
name: ROPE = "A22o2i";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["a22o2i"];
CacheStore[name, ct];
};
O22a2i: PUBLIC PROC[] RETURNS [ct: CellType] = {
name: ROPE = "O22a2i";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["o22a2i"];
CacheStore[name, ct];
};
A21o2i and O21a2i
A21o2i: PUBLIC PROC[] RETURNS [ct: CellType] = {
name: ROPE = "A21o2i";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["a21o2i"];
CacheStore[name, ct];
};
O21a2i: PUBLIC PROC[] RETURNS [ct: CellType] = {
name: ROPE = "O21a2i";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["o21a2i"];
CacheStore[name, ct];
};
Flip-Flops & other storage elements
Edge-Triggered Flip-Flop (one input, one clock, complementary outputs)
FlipFlopRoseClass: ROPE = RoseClass["FlipFlop", FFInit, FFSimple, TRUE];
FlipFlop: PUBLIC PROC [metaStableResistant: BOOLFALSE] RETURNS [ct: CellType] = {
name: ROPE = IF metaStableResistant THEN "FlipFlopMR" ELSE "FlipFlop";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← IF metaStableResistant THEN SCBlock[Extract["ffMR.sch"]] ELSE MakeSC["ff"];
SimulateGate[ct, FlipFlopRoseClass];
Ports.InitPorts[ct, l, none, "D", "CK"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"];
CacheStore[name, ct];
};
FFRef: TYPE = REF FFRec;
FFRec: TYPE = RECORD [
ffD, ffQ, ffNQ, ffClock: NATLAST[NAT],
master, slave: Ports.Level];
FFInit: Rosemary.InitProc = {
state: FFRef ← IF oldStateAny=NIL THEN NEW[FFRec] ELSE NARROW[oldStateAny];
state.master ← state.slave ← X;
[state.ffD, state.ffQ, state.ffNQ, state.ffClock] ← Ports.PortIndexes[cellType.public, "D", "Q", "NQ", "CK"];
p[state.ffQ].l ← p[state.ffNQ].l ← X;
stateAny ← state;
};
FFSimple: Rosemary.EvalProc = {
-- of course state.master is the inverse of the physical master level in the current CMosB implementation, but nobody has access to the real value, so let's keep things simple...
state: FFRef ← NARROW[stateAny];
IF ~clockEval THEN SELECT p[state.ffClock].l FROM
L => state.master ← p[state.ffD].l; -- load master bit
H => state.slave ← state.master; -- load slave bit
ENDCASE => state.slave ← state.master ← X; -- random clock
p[state.ffQ].l ← state.slave; p[state.ffNQ].l ← Ports.NotL[state.slave];
};
Edge-Triggered Flip-Flop (with data enable)
FlipFlopEnableRoseClass: ROPE = RoseClass["FlipFlopEnable", FFenInit, FFenSimple, TRUE];
FlipFlopEnable: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "FlipFlopEnable";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["ffEn"];
SimulateGate[ct, FlipFlopEnableRoseClass];
Ports.InitPorts[ct, l, none, "D", "CK", "en", "nEn"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"];
CacheStore[name, ct];
};
FFenRef: TYPE = REF FFenRec;
FFenRec: TYPE = RECORD [
ffD, ffQ, ffNQ, ffClock, ffen, ffnEn: NATLAST[NAT],
master, slave: Ports.Level];
FFenInit: Rosemary.InitProc = {
state: FFenRef ← IF oldStateAny=NIL THEN NEW[FFenRec] ELSE NARROW[oldStateAny];
state.master ← state.slave ← X;
[state.ffD, state.ffQ, state.ffNQ, state.ffClock, state.ffen, state.ffnEn, ] ← Ports.PortIndexes[cellType.public, "D", "Q", "NQ", "CK", "en", "nEn"];
p[state.ffQ].l ← p[state.ffNQ].l ← X;
stateAny ← state;
};
FFenSimple: Rosemary.EvalProc = {
-- of course state.master is the inverse of the physical master level in the current CMosB implementation, but nobody has access to the real value, so let's keep things simple...
state: FFenRef ← NARROW[stateAny];
IF ~clockEval THEN SELECT p[state.ffClock].l FROM
L => state.master ← Ports.OrL[ -- load master bit
Ports.AndL[p[state.ffD].l, p[state.ffen].l],
Ports.AndL[state.slave, p[state.ffnEn].l]
];
H => state.slave ← state.master; -- load slave bit
ENDCASE => state.slave ← state.master ← X; -- random clock
p[state.ffQ].l ← state.slave; p[state.ffNQ].l ← Ports.NotL[state.slave];
};
Edge-Triggered Flip-Flop (with asynchronous reset)
FlipFlopAsyncResetRoseClass: ROPE = RoseClass["FlipFlopAsyncReset", FFARInit, FFARSimple, TRUE];
FlipFlopAsyncReset: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "FlipFlopAsyncReset";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← SCBlock[Extract["ffAR.sch"]];
SimulateGate[ct, FlipFlopAsyncResetRoseClass];
Ports.InitPorts[ct, l, none, "D", "CK", "r"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"];
CacheStore[name, ct];
};
FFARRef: TYPE = REF FFARRec;
FFARRec: TYPE = RECORD [
ffD, ffQ, ffNQ, ffClock, ffR: NATLAST[NAT],
master, slave: Ports.Level];
FFARInit: Rosemary.InitProc = {
state: FFARRef ← IF oldStateAny=NIL THEN NEW[FFARRec] ELSE NARROW[oldStateAny];
state.master ← state.slave ← X;
[state.ffD, state.ffQ, state.ffNQ, state.ffClock, state.ffR] ← Ports.PortIndexes[cellType.public, "D", "Q", "NQ", "CK", "r"];
p[state.ffQ].l ← p[state.ffNQ].l ← X;
stateAny ← state;
};
FFARSimple: Rosemary.EvalProc = {
state: FFARRef ← NARROW[stateAny];
SELECT p[state.ffR].l FROM
L => IF ~clockEval THEN SELECT p[state.ffClock].l FROM -- normal mode of operation
L => state.master ← p[state.ffD].l; -- load master bit
H => state.slave ← state.master; -- load slave bit
ENDCASE => state.slave ← state.master ← X; -- random clock
H => state.slave ← state.master ← L; -- asynchronous reset
ENDCASE => state.slave ← state.master ← X; -- mushy reset
p[state.ffQ].l ← state.slave; p[state.ffNQ].l ← Ports.NotL[state.slave];
};
RS Flip-Flop (not a SC)
RSRoseClass: ROPE = RoseClass["RSFlipFlop", RSInit, RSSimple];
RS: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "RSFlipFlop";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← CoreClasses.CreateUnspecified[name: name,
public: Wires["Vdd", "Gnd", "R", "S", "Q", "nQ"]];
SimulateGate[ct, RSRoseClass];
Ports.InitPorts[ct, l, none, "R", "S"]; Ports.InitPorts[ct, l, drive, "Q", "NQ"];
CacheStore[name, ct];
};
RSRef: TYPE = REF RSRec;
RSRec: TYPE = RECORD [
r, s, q, nq: NATLAST[NAT],
bit: Ports.Level]; -- a copy of Q
RSInit: Rosemary.InitProc = {
state: RSRef ← IF oldStateAny=NIL THEN NEW[RSRec] ELSE NARROW[oldStateAny];
state.bit ← X;
[state.r, state.s, state.q, state.nq] ← Ports.PortIndexes[cellType.public, "R", "S", "Q", "nQ"];
p[state.q].l ← p[state.nq].l ← X;
stateAny ← state;
};
RSSimple: Rosemary.EvalProc = {
state: RSRef ← NARROW[stateAny];
SELECT TRUE FROM
p[state.r].l=H => {
state.bit ← p[state.q].l ← L;
p[state.nq].l ← Ports.NotL[p[state.s].l];
};
p[state.r].l=L AND p[state.s].l=H => {
state.bit ← p[state.q].l ← H;
p[state.nq].l ← L;
};
p[state.r].l=L AND p[state.s].l=L => {
p[state.q].l ← state.bit;
p[state.nq].l ← Ports.NotL[state.bit];
};
ENDCASE => state.bit ← p[state.q].l ← p[state.nq].l ← X;
};
Storage (not a SC)
StorageRoseClass: ROPE = RoseClass["Storage", StorageInit, StorageSimple];
Storage: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "Storage";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← CoreClasses.CreateUnspecified[name: name,
public: Wires["Vdd", "Gnd", "bit", "nbit"]];
SimulateGate[ct, StorageRoseClass];
Ports.InitPorts[ct, l, none, "bit", "nbit"];
[] ← Rosemary.SetWire[wire: FindWire[ct.public, "bit"], memory: TRUE];
[] ← Rosemary.SetWire[wire: FindWire[ct.public, "nbit"], memory: TRUE];
CacheStore[name, ct];
};
StorageRef: TYPE = REF StorageRec;
StorageRec: TYPE = RECORD [bit, nBit: NATLAST[NAT]];
StorageInit: Rosemary.InitProc = {
state: StorageRef ← IF oldStateAny=NIL THEN NEW[StorageRec] ELSE NARROW[oldStateAny];
[state.bit, state.nBit] ← Ports.PortIndexes[cellType.public, "bit", "nbit"];
p[state.bit].l ← X;
p[state.bit].d ← driveWeak;
p[state.nBit].l ← X;
p[state.nBit].d ← driveWeak;
stateAny ← state;
};
StorageSimple: Rosemary.EvalProc = {NULL}; -- cf. Pradeep
Latch (1 input)
DLatchRoseClass: ROPE = RoseClass["DLatch", DLInit, DLSimple];
DLatch: PUBLIC PROC RETURNS [ct: CellType] = {
name: ROPE = "DLatch";
ct ← CacheFetch[name];
IF ct#NIL THEN RETURN[ct];
ct ← MakeSC["dLatch"];
SimulateGate[ct, DLatchRoseClass];
Ports.InitPorts[ct, l, none, "D", "S"]; Ports.InitPorts[ct, l, drive, "Q"];
CacheStore[name, ct];
};
DLRef: TYPE = REF DLRec;
DLRec: TYPE = RECORD [
dlD, dlQ, dlS: NATLAST[NAT],
mem: Ports.Level];
DLInit: Rosemary.InitProc = {
state: DLRef ← IF oldStateAny=NIL THEN NEW[DLRec] ELSE NARROW[oldStateAny];
state.mem ← X;
[state.dlD, state.dlQ, state.dlS] ← Ports.PortIndexes[cellType.public, "D", "Q", "S"];
p[state.dlQ].l ← X;
stateAny ← state;
};
DLSimple: Rosemary.EvalProc = {
state: DLRef ← NARROW[stateAny];
IF p[state.dlS].l=H THEN state.mem ← p[state.dlD].l ELSE IF p[state.dlS].l=X THEN
IF p[state.dlD].l#state.mem THEN state.mem ← X;
p[state.dlQ].l ← state.mem;
};
Pull-ups and pull-down
Real pull up/down, normal size and weak
Tr2: PUBLIC PROC [type: ATOM] RETURNS [ct: CellType] = {
fullName: ROPE = IO.PutFR["Tr2 type=$%g", IO.atom[type]];
name: ROPE;
dr: Ports.Drive ← drive;
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
SELECT type FROM
$pd => name ← "pd";
$pdw => {name ← "pdw"; dr ← driveWeak};
$pu => name ← "pu";
$puw => {name ← "puw"; dr ← driveWeak};
ENDCASE => ERROR;
ct ← MakeSC[name]; -- no eval proc for this guy
IF type = $pdw OR type = $puw THEN CoreProperties.PutCellTypeProp[ct, $MintDiscardMe, $TRUE];
Ports.InitPorts[ct, l, none, "I"]; Ports.InitPorts[ct, l, dr, "X"];
CacheStore[fullName, ct];
};
-- Extracts the transistor normally, but makes it invisible to Mint
MintHackExtractProc: Sinix.ExtractProc ~ {
[result, props] ← Sinix.Extract[obj, mode, NIL, userData];
props ← CoreProperties.PutProp[props, $MintDiscardMe, $TRUE];
};
Logical pull-up, no layout
PullUpRoseClass: ROPE = RoseClass["PullUp", PUInit, PUSimple];
PullUp: PUBLIC PROC [n: NAT] RETURNS [ct: CellType] = {
fullName: ROPE = IO.PutFR["PullUp n=%g", IO.int[n]];
ct ← CacheFetch[fullName];
IF ct#NIL THEN RETURN[ct];
ct ← CoreClasses.CreateUnspecified[name: "PullUp", public: Wires[IF n=0 THEN "out" ELSE Seq["out", n]]];
SimulateGate[ct, PullUpRoseClass];
Ports.InitPorts[ct, IF n=0 THEN l ELSE ls, driveWeak, "out"];
CacheStore[fullName, ct];
};
PUInit: Rosemary.InitProc = {
state: IXRef ← IF oldStateAny=NIL THEN NEW[IXRec] ELSE NARROW[oldStateAny];
state.out ← Ports.PortIndex[cellType.public, "out"];
IF p[state.out].levelType=l THEN p[state.out].l ← H ELSE Ports.SetLS[p[state.out].ls, H];
stateAny ← state;
};
PUSimple: Rosemary.EvalProc = {
state: IXRef ← NARROW[stateAny];
IF p[state.out].levelType=l THEN p[state.out].l ← H ELSE Ports.SetLS[p[state.out].ls, H];
};
Sinix.RegisterExtractProc[$MintHackExtractProc, MintHackExtractProc];
END.