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; 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: NAT _ LAST[NAT], val: SEQUENCE size: NAT OF Ports.LevelSequence]; Ram2Init: Rosemary.InitProc = { n: NAT _ NARROW[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; }; 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]; }; }; 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: NAT _ LAST[NAT], val: SEQUENCE size: NAT OF Ports.LevelSequence]; Ram2MCInit: Rosemary.InitProc = { n: NAT _ NARROW[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; }; 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"]; }; FifoState: TYPE = REF FifoStateRec; FifoStateRec: TYPE = RECORD [ ck, in, out, load, unLoad, reset, dataAv, full, nearlyFull: NAT _ LAST[NAT], prevCK, loadSt, unloadSt, resetSt: Ports.Level _ X, master: Ports.LevelSequence, valid: BOOL _ FALSE, 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: NAT _ NARROW[CoreProperties.GetCellTypeProp[cellType, $n], REF NAT]^; nbFreeNF: NAT _ NARROW[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=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. ’LogicMemImpl.mesa Copyright c 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 Ram2 -- 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. Single-cycle write Ram2 Fifo 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] ~ { }; [] _ Fifo[3, 4, 2]; Κ %– "cedar" style˜codešœ™Kšœ Οmœ1™K˜—šœžœ(˜šžœžœž˜šœžœ'˜;Kš žœžœžœžœžœ˜=K˜—šœžœ(˜K˜—šœžœ(˜