LogicMemImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier February 21, 1987 4:36:28 pm PST
Last Edited by: Gasbarro December 17, 1986 10:54:15 am PST
Barth, October 10, 1986 5:33:58 pm PDT
DIRECTORY BitOps, CoreClasses, CoreCreate, CoreFlat, CoreProperties, Logic, LogicUtils, Ports, Rosemary;
LogicMemImpl: CEDAR PROGRAM
IMPORTS BitOps, CoreClasses, CoreCreate, CoreFlat, CoreProperties, Logic, LogicUtils, Ports, Rosemary
EXPORTS Logic
= BEGIN OPEN Logic, CoreCreate;
Ram2
Ram2Name: ROPE = Rosemary.Register[roseClassName: "Ram2", init: Ram2Init, evalSimple: Ram2Simple];
Ram2: PUBLIC PROC [b, n: NAT] RETURNS [ct: CellType] = {
a: NAT ← BitOps.NBits[n]; -- number of address bits
IF b=0 OR n=0 THEN LogicUtils.Error["Please provide parameters for ram2"];
ct ← CoreClasses.CreateUnspecified[name: Ram2Name,
public: Wires["Vdd", "Gnd", Seq["Input", b], Seq["Output", b], Seq["RAdr", a], Seq["WAdr", a], "enW"]];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: Ram2Name];
CoreProperties.PutCellTypeProp[ct, $n, NEW[NAT ← n]];
[] ← CoreFlat.CellTypeCutLabels[ct, logicCutSet];
Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "enW"];
Ports.InitPorts[ct, ls, none, "Input", "RAdr", "WAdr"];
Ports.InitPorts[ct, ls, drive, "Output"];
};
Ram2State: TYPE = REF Ram2StateRec;
Ram2StateRec: TYPE = RECORD [
input, output, rAdr, wAdr, enW: NATLAST[NAT],
val: SEQUENCE size: NAT OF Ports.LevelSequence];
Ram2Init: Rosemary.InitProc = {
n: NATNARROW[CoreProperties.GetCellTypeProp[cellType, $n], REF NAT]^;
b: NAT;
state: Ram2State ← NEW[Ram2StateRec[n]];
[state.input, state.output, state.rAdr, state.wAdr, state.enW] ← Ports.PortIndexes[cellType.public, "Input", "Output", "RAdr", "WAdr", "enW"];
b ← p[state.input].ls.size;
FOR i: NAT IN [0..n) DO
state.val[i] ← NEW[Ports.LevelSequenceRec[b]];
Ports.SetLS[state.val[i], X];
ENDLOOP;
stateAny ← state;
};
-- The write happens before the read, so that if the read and write addresses are equal, the value gets transfered from the Input to the Output port.
Ram2Simple: Rosemary.EvalProc = {
state: Ram2State ← NARROW[stateAny];
n: NAT ← state.size;
SELECT TRUE FROM
p[state.enW].l#L AND LogicUtils.HasX[p[state.wAdr].ls] => {
FOR i: NAT IN [0..n) DO Ports.SetLS[state.val[i], X] ENDLOOP;
};
p[state.enW].l=X AND ~LogicUtils.HasX[p[state.wAdr].ls] => {
writeAdr: CARDINAL ← Ports.LSToC[p[state.wAdr].ls];
IF writeAdr IN [0..n) THEN Ports.SetLS[state.val[writeAdr], X]
};
p[state.enW].l=H AND ~LogicUtils.HasX[p[state.wAdr].ls] => {
writeAdr: CARDINAL ← Ports.LSToC[p[state.wAdr].ls];
IF writeAdr IN [0..n) THEN
Ports.CopyLS[from: p[state.input].ls, to: state.val[writeAdr]];
};
ENDCASE => NULL;
IF LogicUtils.HasX[p[state.rAdr].ls] THEN Ports.SetLS[p[state.output].ls, X]
ELSE {
readAdr: CARDINAL ← Ports.LSToC[p[state.rAdr].ls];
IF readAdr NOT IN [0..n) THEN Ports.SetLS[p[state.output].ls, X];
Ports.CopyLS[from: state.val[readAdr], to: p[state.output].ls];
};
};
Single-cycle write Ram2
Ram2MCName: ROPE = Rosemary.Register[roseClassName: "Ram2MC", init: Ram2MCInit, evalSimple: Ram2MCSimple];
Ram2MC: PUBLIC PROC [b, n: NAT] RETURNS [ct: CellType] = {
a: NAT ← BitOps.NBits[n]; -- number of address bits
IF b=0 OR n=0 THEN LogicUtils.Error["Please provide parameters for ram2MC"];
ct ← CoreClasses.CreateUnspecified[name: Ram2MCName,
public: Wires["Vdd", "Gnd", Seq["Input", b], Seq["Output", b], Seq["RAdr", a], Seq["WAdr", a], "enW", "CK"]];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: Ram2MCName];
CoreProperties.PutCellTypeProp[ct, $n, NEW[NAT ← n]];
[] ← CoreFlat.CellTypeCutLabels[ct, logicCutSet];
Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "enW", "CK"];
Ports.InitPorts[ct, ls, none, "Input", "RAdr", "WAdr"];
Ports.InitPorts[ct, ls, drive, "Output"];
};
Ram2MCState: TYPE = REF Ram2MCStateRec;
Ram2MCStateRec: TYPE = RECORD [
input, output, rAdr, wAdr, enW, ck: NATLAST[NAT],
val: SEQUENCE size: NAT OF Ports.LevelSequence];
Ram2MCInit: Rosemary.InitProc = {
n: NATNARROW[CoreProperties.GetCellTypeProp[cellType, $n], REF NAT]^;
b: NAT;
state: Ram2MCState ← NEW[Ram2MCStateRec[n]];
[state.input, state.output, state.rAdr, state.wAdr, state.enW, state.ck] ← Ports.PortIndexes[cellType.public, "Input", "Output", "RAdr", "WAdr", "enW", "CK"];
b ← p[state.input].ls.size;
FOR i: NAT IN [0..n) DO
state.val[i] ← NEW[Ports.LevelSequenceRec[b]];
Ports.SetLS[state.val[i], X];
ENDLOOP;
stateAny ← state;
};
Ram2MCSimple: Rosemary.EvalProc = {
state: Ram2MCState ← NARROW[stateAny];
n: NAT ← state.size;
IF LogicUtils.HasX[p[state.rAdr].ls] THEN Ports.SetLS[p[state.output].ls, X]
ELSE {
readAdr: CARDINAL ← Ports.LSToC[p[state.rAdr].ls];
IF readAdr NOT IN [0..n) THEN Ports.SetLS[p[state.output].ls, X];
Ports.CopyLS[from: state.val[readAdr], to: p[state.output].ls];
};
IF p[state.ck].l=H THEN RETURN; -- no write when clock is high
SELECT TRUE FROM
p[state.enW].l#L AND LogicUtils.HasX[p[state.wAdr].ls] => {
FOR i: NAT IN [0..n) DO Ports.SetLS[state.val[i], X] ENDLOOP;
};
p[state.enW].l=X AND ~LogicUtils.HasX[p[state.wAdr].ls] => {
writeAdr: CARDINAL ← Ports.LSToC[p[state.wAdr].ls];
IF writeAdr IN [0..n) THEN Ports.SetLS[state.val[writeAdr], X]
};
p[state.enW].l=H AND ~LogicUtils.HasX[p[state.wAdr].ls] => {
writeAdr: CARDINAL ← Ports.LSToC[p[state.wAdr].ls];
IF writeAdr IN [0..n) THEN
Ports.CopyLS[from: p[state.input].ls, to: state.val[writeAdr]];
};
ENDCASE => NULL;
};
Fifo
FifoName: ROPE = Rosemary.Register[roseClassName: "Fifo", init: FifoInit, evalSimple: FifoSimple];
Fifo: PUBLIC PROC [b, n, nbFreeNF: NAT] RETURNS [ct: CellType] = {
ct ← CoreClasses.CreateUnspecified[name: FifoName,
public: Wires["Vdd", "Gnd", "CK", Seq["Input", b], Seq["Output", b], "Load", "UnLoad", "Reset", "DataAv", "Full", "NF"]];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: FifoName];
CoreProperties.PutCellTypeProp[ct, $n, NEW[NAT ← n]];
CoreProperties.PutCellTypeProp[ct, $nbFreeNF, NEW[NAT ← nbFreeNF]];
[] ← CoreFlat.CellTypeCutLabels[ct, macroCutSet];
Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "CK", "Load", "UnLoad", "Reset"];
Ports.InitPorts[ct, l, drive, "DataAv", "Full", "NF"];
Ports.InitPorts[ct, ls, none, "Input"];
Ports.InitPorts[ct, ls, drive, "Output"];
};
fifoDesignName: ROPE = "Fifo";
fifoDesign: CD.Design ← NIL;
fifoCx: Sisyph.Context ← NIL;
FifoArray: PROC [b, n: NAT] RETURNS [ct: CellType] ~ {
cell, row: CellType;
IF fifoDesign=NIL THEN fifoDesign ← PW.OpenDesign[fifoDesignName];
IF fifoCx=NIL THEN fifoCx ← Sisyph.Create[fifoDesign];
cell ← Sisyph.ES["fifoCell.sch", fifoCx];
PWCore.SetGet[cell, fifoDesign];
row ← SequenceCell[baseCell: cell, count: b, sequencePorts: Wires["bw", "br"]];
PWCore.SetLayout[row, $ReverseArrayX];
ct ← SequenceCell[baseCell: row, count: n, sequencePorts: Wires["read", "write", "nWrite"]];
PWCore.SetLayout[ct, $ReverseArrayY];
};
FifoWriteShReg: PROC [n: NAT] RETURNS [ct: CellType] ~ {
};
FifoReadShReg: PROC [n: NAT] RETURNS [ct: CellType] ~ {
};
FifoState: TYPE = REF FifoStateRec;
FifoStateRec: TYPE = RECORD [
ck, in, out, load, unLoad, reset, dataAv, full, nearlyFull: NATLAST[NAT],
prevCK, loadSt, unloadSt, resetSt: Ports.Level ← X,
master: Ports.LevelSequence,
valid: BOOLFALSE,
nbWords: INT ← 0,
nbFreeNF: NAT ← 0,
tail: NAT ← 0, -- "tail" points to the first word used (unless empty)
head: NAT ← 0, -- "head" points to the first free word
val: SEQUENCE size: NAT OF Ports.LevelSequence];
FifoInit: Rosemary.InitProc = {
n: NATNARROW[CoreProperties.GetCellTypeProp[cellType, $n], REF NAT]^;
nbFreeNF: NATNARROW[CoreProperties.GetCellTypeProp[cellType, $nbFreeNF], REF NAT]^;
b: NAT;
state: FifoState ← NEW[FifoStateRec[n]];
[state.ck, state.in, state.out, state.load, state.unLoad, state.reset, state.dataAv, state.full, state.nearlyFull] ← Ports.PortIndexes[cellType.public, "CK", "Input", "Output", "Load", "UnLoad", "Reset", "DataAv", "Full", "NF"];
b ← p[state.in].ls.size;
state.nbFreeNF ← nbFreeNF;
state.prevCK ← X;
FOR i: NAT IN [0..n) DO
state.val[i] ← NEW[Ports.LevelSequenceRec[b]];
Ports.SetLS[state.val[i], X];
ENDLOOP;
state.master ← NEW[Ports.LevelSequenceRec[b]];
Ports.SetLS[state.master, X];
stateAny ← state;
};
FifoSimple: Rosemary.EvalProc = {
state: FifoState ← NARROW[stateAny];
{OPEN state;
n: NAT ← size;
SELECT TRUE FROM
p[ck].l=L => {
loadSt ← p[load].l;
unloadSt ← p[unLoad].l;
resetSt ← p[reset].l;
Ports.CopyLS[from: p[state.in].ls, to: state.master]
};
prevCK=L AND p[ck].l=H => SELECT TRUE FROM
resetSt=H => {
valid ← TRUE;
nbWords ← 0;
tail ← head ← 0;
};
resetSt=X OR unloadSt=X OR loadSt=X => valid ← FALSE;
ENDCASE => IF valid THEN {
IF loadSt=H THEN {
nbWords ← nbWords+1;
Ports.CopyLS[from: state.master, to: val[head]];
head ← (head+1) MOD n;
};
IF unloadSt=H THEN {
nbWords ← nbWords-1;
tail ← (tail+1) MOD n;
};
};
ENDCASE;
IF valid THEN {
Ports.CopyLS[from: val[tail], to: p[out].ls];
p[dataAv].l ← IF nbWords>0 THEN H ELSE L;
p[nearlyFull].l ← IF n-nbWords<nbFreeNF THEN H ELSE L;
p[full].l ← IF nbWords>=n THEN H ELSE L;
}
ELSE {
Ports.SetLS[p[out].ls, X];
p[dataAv].l ← p[nearlyFull].l ← p[full].l ← X;
};
prevCK ← p[ck].l;
IF nbWords>n THEN Rosemary.Stop["Fifo overflow"];
IF nbWords<0 THEN Rosemary.Stop["Fifo underflow"];
}};
END.
[] ← Fifo[3, 4, 2];