LogicMemImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Louis Monier April 28, 1988 5:02:09 pm PDT
Last Edited by: Gasbarro December 17, 1986 10:54:15 am PST
Jean-Marc Frailong September 13, 1987 9:53:09 pm PDT
Bertrand Serlet April 8, 1987 11:20:05 pm PDT
Barth, October 10, 1986 5:33:58 pm PDT
DIRECTORY BitOps, CD, CoreCreate, CoreFlat, CoreProperties, Logic, LogicUtils, Ports, PW, PWCore, Rosemary, Sisyph, TilingClass;
LogicMemImpl: CEDAR PROGRAM
IMPORTS BitOps, CoreCreate, CoreFlat, CoreProperties, Logic, LogicUtils, Ports, PW, PWCore, Rosemary, Sisyph, TilingClass
EXPORTS Logic
= BEGIN OPEN Logic, CoreCreate;
Ram2
ramDesignName: ROPE = "LogicRam2";
ramShortDesignName: ROPE = "LogicRam2Short";
ramDesign, ramShortDesign: CD.Design;
ramCx, ramShortCx: Sisyph.Context ← NIL;
Extract: PUBLIC PROC [schName: ROPE, cx: Sisyph.Context, parms: LIST OF LogicUtils.Value ← NIL] RETURNS [ct: CellType] ~ {
Extracts from the Logic library with the given (INT) parameters.
tmpCx: Sisyph.Context;
IF cx=NIL THEN ERROR;
tmpCx ← IF parms=NIL THEN cx ELSE Sisyph.Copy[cx];
WHILE parms#NIL DO
Sisyph.Store[tmpCx, parms.first.name, NEW[INT ← parms.first.val]];
parms ← parms.rest;
ENDLOOP;
ct ← Sisyph.ES[schName, tmpCx];
};
TakeCareOfContext: PROC [short: BOOL] RETURNS [Sisyph.Context] ~ {
IF short THEN{
IF ramShortDesign=NIL THEN ramShortDesign ← PW.OpenDesign[ramShortDesignName];
ramShortCx ← Sisyph.Create[ramShortDesign];
RETURN[ramShortCx];
}
ELSE {
IF ramDesign=NIL THEN ramDesign ← PW.OpenDesign[ramDesignName];
ramCx ← Sisyph.Create[ramDesign];
RETURN[ramCx];
};
};
Ram2Name: ROPE = Rosemary.Register[roseClassName: "Ram2", init: Ram2Init, evalSimple: Ram2Simple];
Ram2: PUBLIC PROC [b, n: NAT, sameSide, short: BOOLFALSE] RETURNS [ct: CellType] = {
a: NAT = BitOps.NBits[n]; -- number of address bits
schName: ROPE = IF sameSide THEN "SameSideRam.sch" ELSE "BothSidesRam.sch";
context: Sisyph.Context = TakeCareOfContext[short];
IF b=0 OR n=0 THEN LogicUtils.Error["Please provide parameters for ram2"];
IF BitOps.ODD[n] THEN n←n+1; -- number of words must be even
IF short AND BitOps.ODD[b] THEN LogicUtils.Error["b must be even for short ram"];
ct ← Extract[schName, context, LIST[["b", b], ["n", n]]];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: Ram2Name];
CoreProperties.PutCellTypeProp[ct, $n, NEW[NAT ← n]];
[] ← CoreFlat.CellTypeCutLabels[ct, logicCutSet, "Memory"];
Ports.InitPorts[ct, l, none, "Vdd", "Gnd", "enW"];
Ports.InitPorts[ct, ls, none, "Input", "RAdr", "WAdr"];
Ports.InitPorts[ct, ls, drive, "Output"];
};
Decoder: PROC [n: NAT, adrOnTop: BOOL, cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
dec0: CellType ← Sisyph.ES["dec0.sch", cx];
dec1: CellType ← PWCore.RotateCellType[dec0, $FlipX];
decf0: CellType ← PWCore.RotateCellType[dec0, $FlipY];
decf1: CellType ← PWCore.RotateCellType[dec0, $Rot180];
adrAmpli: CellType ← Sisyph.ES["adrAmpli.sch", cx];
adrInv: CellType ← Sisyph.ES["adrInv.sch", cx];
botCt: CellType ← IF adrOnTop THEN PWCore.RotateCellType[adrInv, $FlipY] ELSE adrAmpli;
topCt: CellType ← IF adrOnTop THEN PWCore.RotateCellType[adrAmpli, $FlipY] ELSE adrInv;
a: NAT ← BitOps.NBits[n]; -- number of address bits
norOut: Wire ← Seq["norOut", n];
adr: Wire ← Seq["adr", a];
tileArray: TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[n+2]];
-- from the bottom up: botCt, rows 0, ... n-1, topCt
FOR row: NAT IN [0..n+2) DO-- create the rows
tileArray[row] ← NEW[TilingClass.TileRowRec[a]];
ENDLOOP;
FOR i: NAT IN [0..a) DO-- column 0 is on the left
tileArray[0][i] ← NEW[TilingClass.TileRec ← [
type: botCt,
renaming: IF adrOnTop THEN LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["ad", adr[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO
tileArray[row+1][i] ← NEW[TilingClass.TileRec ← [
type: SELECT TRUE FROM
BitOps.EVEN[row] AND BitOps.EBFW[row, 15-i] => dec0,
BitOps.EVEN[row] AND ~BitOps.EBFW[row, 15-i] => dec1,
BitOps.ODD[row] AND BitOps.EBFW[row, 15-i] => decf0,
BitOps.ODD[row] AND ~BitOps.EBFW[row, 15-i] => decf1,
ENDCASE => ERROR,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", norOut[row]]]]];
ENDLOOP;
tileArray[n+1][i] ← NEW[TilingClass.TileRec ← [
type: topCt,
renaming: IF adrOnTop THEN LIST[ ["ad", adr[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
ct ← TilingClass.CreateTiling[
name: "Decoder",
public: Wires[adr, norOut, "Vdd", "Gnd"],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY
];
};
DecoderShort: PROC [n: NAT, adrOnTop: BOOL, cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
dec0: CellType ← Sisyph.ES["dec0.sch", cx];
dec1: CellType ← PWCore.RotateCellType[dec0, $FlipX];
decf0: CellType ← PWCore.RotateCellType[dec0, $FlipY];
decf1: CellType ← PWCore.RotateCellType[dec0, $Rot180];
adrAmpli: CellType ← Sisyph.ES["adrAmpli.sch", cx];
adrInv: CellType ← Sisyph.ES["adrInv.sch", cx];
botCt: CellType ← IF adrOnTop THEN PWCore.RotateCellType[adrInv, $FlipY] ELSE adrAmpli;
topCt: CellType ← IF adrOnTop THEN PWCore.RotateCellType[adrAmpli, $FlipY] ELSE adrInv;
a: NAT ← BitOps.NBits[n]; -- number of address bits
norOut: Wire ← Seq["norOut", n];
adr: Wire ← Seq["adr", a];
tileArray: TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[n+2]];
-- from the bottom up: botCt, rows 0, ... n-1, topCt
FOR row: NAT IN [0..n+2) DO-- create the rows
tileArray[row] ← NEW[TilingClass.TileRowRec[a]];
ENDLOOP;
FOR i: NAT IN [0..a) DO-- column 0 is on the left
tileArray[0][i] ← NEW[TilingClass.TileRec ← [
type: botCt,
renaming: IF adrOnTop THEN LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["ad", adr[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO
tileArray[row+1][i] ← NEW[TilingClass.TileRec ← [
type: SELECT TRUE FROM
BitOps.EVEN[row] AND BitOps.EBFW[row, 15-i] => dec0,
BitOps.EVEN[row] AND ~BitOps.EBFW[row, 15-i] => dec1,
BitOps.ODD[row] AND BitOps.EBFW[row, 15-i] => decf0,
BitOps.ODD[row] AND ~BitOps.EBFW[row, 15-i] => decf1,
ENDCASE => ERROR,
renaming: LIST[ ["Gnd", "Gnd"], ["norOut", norOut[row]]]]];
ENDLOOP;
tileArray[n+1][i] ← NEW[TilingClass.TileRec ← [
type: topCt,
renaming: IF adrOnTop THEN LIST[ ["ad", adr[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
ct ← TilingClass.CreateTiling[
name: "Decoder",
public: Wires[adr, norOut, "Vdd", "Gnd"],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY
];
};
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 Ports.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 ~Ports.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 ~Ports.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 Ports.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];
};
};
END.
-- Layout of the original ram
-- Array of size n+2 by b+2: read on bottom, write on top, writeWL driver on the left, and readWL driver on the right
Array: PROC [b, n: NAT, sameSide: BOOL, cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
wFiller: CellType ← Sisyph.ES["wFiller.sch", cx];
writeWLDr: CellType ← Sisyph.ES["writeWLDr.sch", cx];
flipWriteWLDr: CellType ← PWCore.RotateCellType[writeWLDr, $FlipY];
topCells: CellType ← Extract[IF sameSide THEN "readWriteTops.sch" ELSE "writeTops.sch", cx, LIST[["b", b]]];
ramCells: CellType ← Extract["ram2Cells.sch", cx, LIST[["b", b]]];
flipYRamCells: CellType ← PWCore.RotateCellType[ramCells, $FlipY];
bottomCells: CellType ← Extract[IF sameSide THEN "readWriteBottoms.sch" ELSE "readBottoms.sch", cx, LIST[["b", b]]];
rFiller: CellType ← Sisyph.ES["rFiller.sch", cx];
readWLDr: CellType ← Sisyph.ES["readWLDr.sch", cx];
flipReadWLDr: CellType ← PWCore.RotateCellType[readWLDr, $FlipY];
in: Wire ← Seq["Input", b];
out: Wire ← Seq["Output", b];
rNorOut: Wire ← Seq["rNorOut", n];
wNorOut: Wire ← Seq["wNorOut", n];
tileArray: TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[n+2]];
from the bottom up: read, rows 0, ... n-1, write
FOR row: NAT IN [0..n+2) DO-- create the rows
tileArray[row] ← NEW[TilingClass.TileRowRec[3]];
ENDLOOP;
-- left row
tileArray[0][0] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[wFiller, $FlipY],
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the write word-line drivers
tileArray[row+1][0] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN writeWLDr ELSE flipWriteWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", wNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][0] ← NEW[TilingClass.TileRec ← [
type: wFiller,
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
-- main array
tileArray[0][1] ← NEW[TilingClass.TileRec ← [
type: bottomCells,
renaming: IF ~sameSide THEN LIST[ ["Output", out], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in], ["Output", out], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO
tileArray[row+1][1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN ramCells ELSE flipYRamCells,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
tileArray[n+1][1] ← NEW[TilingClass.TileRec ← [
type: topCells,
renaming: IF sameSide THEN LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
-- right row
tileArray[0][2] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[rFiller, $FlipY],
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the read word-line drivers
tileArray[row+1][2] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN readWLDr ELSE flipReadWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", rNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][2] ← NEW[TilingClass.TileRec ← [
type: rFiller,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ct ← TilingClass.CreateTiling[
name: "RamArray",
public: Wires["Vdd", "Gnd", in, out, rNorOut, wNorOut, "enW"],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY
];
};
RamAssembly: PROC [b, n: NAT, sameSide: BOOL] RETURNS [ct: CellType] ~ {
a: NAT ← BitOps.NBits[n]; -- number of address bits
array, writeDecoder, readDecoder: CellType;
wNorOut, rNorOut, wAdr, rAdr: Wire;
IF ramDesign=NIL THEN ramDesign ← PW.OpenDesign["LogicRam2"];
ramCx ← Sisyph.Create[ramDesign];
array ← Array[b, n, sameSide, ramCx];
writeDecoder ← Decoder[n: n, adrOnTop: ~sameSide, cx: ramCx];
readDecoder ← Decoder[n: n, adrOnTop: FALSE, cx: ramCx];
wNorOut ← Seq["wNorOut", n];
rNorOut ← Seq["rNorOut", n];
wAdr ← Seq["WAdr", a];
rAdr ← Seq["RAdr", a];
ct ← Cell[
public: Wires["Vdd", "Gnd", Seq["Input", b], Seq["Output", b], rAdr, wAdr, "enW"],
onlyInternal: Wires[wNorOut, rNorOut],
instances: LIST[
Instance[writeDecoder, ["adr", wAdr], ["norOut", wNorOut]],
Instance[array, ["Input", "Input"], ["Output", "Output"], ["wNorOut", wNorOut], ["rNorOut", rNorOut]],
Instance[readDecoder, ["adr", rAdr], ["norOut", rNorOut]]
]
];
PWCore.SetAbutX[ct];
};
-- Layout of the short ram
ArrayShort: PROC [b, n: NAT, sameSide: BOOL, cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
wFiller: CellType ← Sisyph.ES["wFiller.sch", cx];
writeWLDr: CellType ← Sisyph.ES["writeWLDr.sch", cx];
flipWriteWLDr: CellType ← PWCore.RotateCellType[writeWLDr, $FlipY];
topCell: CellType ← Sisyph.ES[IF sameSide THEN "readWriteTop.sch" ELSE "writeTop.sch", cx];
flipXTopCell: CellType ← PWCore.RotateCellType[topCell, $FlipX];
ramCell: CellType ← Sisyph.ES["ram2Cell.sch", cx];
flipYRamCell: CellType ← PWCore.RotateCellType[ramCell, $FlipY];
flipXRamCell: CellType ← PWCore.RotateCellType[ramCell, $FlipX];
flipXYRamCell: CellType ← PWCore.RotateCellType[ramCell, $Rot180];
bottomCell: CellType ← Sisyph.ES[IF sameSide THEN "readWriteBottom.sch" ELSE "readBottom.sch", cx];
flipXBottomCell: CellType ← PWCore.RotateCellType[bottomCell, $FlipX];
rFiller: CellType ← Sisyph.ES["rFiller.sch", cx];
readWLDr: CellType ← Sisyph.ES["readWLDr.sch", cx];
flipReadWLDr: CellType ← PWCore.RotateCellType[readWLDr, $FlipY];
in: Wire ← Seq["Input", b];
out: Wire ← Seq["Output", b];
rNorOut: Wire ← Seq["rNorOut", n];
wNorOut: Wire ← Seq["wNorOut", n];
tileArray: TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[n+2]];
from the bottom up: read, rows 0, ... n-1, write
FOR row: NAT IN [0..n+2) DO-- create the rows
tileArray[row] ← NEW[TilingClass.TileRowRec[b+2]];
ENDLOOP;
-- left row
tileArray[0][0] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[wFiller, $FlipY],
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the write word-line drivers
tileArray[row+1][0] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN writeWLDr ELSE flipWriteWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", wNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][0] ← NEW[TilingClass.TileRec ← [
type: wFiller,
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
-- main array
FOR i: NAT IN [0..b) DO-- column 0 is on the left
tileArray[0][i+1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[i] THEN bottomCell ELSE flipXBottomCell,
renaming: IF ~sameSide THEN LIST[ ["Output", out[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in[i]], ["Output", out[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO
tileArray[row+1][i+1] ← NEW[TilingClass.TileRec ← [
type: SELECT TRUE FROM
BitOps.EVEN[row] AND BitOps.EVEN[i] => ramCell,
BitOps.ODD[row] AND BitOps.EVEN[i] => flipYRamCell,
BitOps.EVEN[row] AND BitOps.ODD[i] => flipXRamCell,
BitOps.ODD[row] AND BitOps.ODD[i] => flipXYRamCell,
ENDCASE => ERROR,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
tileArray[n+1][i+1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[i] THEN topCell ELSE flipXTopCell,
renaming: IF sameSide THEN LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
-- right row
tileArray[0][b+1] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[rFiller, $FlipY],
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the read word-line drivers
tileArray[row+1][b+1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN readWLDr ELSE flipReadWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", rNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][b+1] ← NEW[TilingClass.TileRec ← [
type: rFiller,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ct ← TilingClass.CreateTiling[
name: "RamArray",
public: Wires["Vdd", "Gnd", in, out, rNorOut, wNorOut, "enW"],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY
];
};
RamAssemblyShort: PROC [b, n: NAT, sameSide: BOOL] RETURNS [ct: CellType] ~ {
a: NAT ← BitOps.NBits[n]; -- number of address bits
array, writeDecoder, readDecoder: CellType;
wNorOut, rNorOut, wAdr, rAdr: Wire;
IF ramShortDesign=NIL THEN ramShortDesign ← PW.OpenDesign["LogicRam2Short"];
ramShortCx ← Sisyph.Create[ramShortDesign];
array ← ArrayShort[b, n, sameSide, ramShortCx];
writeDecoder ← DecoderShort[n: n, adrOnTop: ~sameSide, cx: ramShortCx];
readDecoder ← DecoderShort[n: n, adrOnTop: FALSE, cx: ramShortCx];
wNorOut ← Seq["wNorOut", n];
rNorOut ← Seq["rNorOut", n];
wAdr ← Seq["WAdr", a];
rAdr ← Seq["RAdr", a];
ct ← Cell[
public: Wires["Vdd", "Gnd", Seq["Input", b], Seq["Output", b], rAdr, wAdr, "enW"],
onlyInternal: Wires[wNorOut, rNorOut],
instances: LIST[
Instance[writeDecoder, ["adr", wAdr], ["norOut", wNorOut]],
Instance[array, ["Input", "Input"], ["Output", "Output"], ["wNorOut", wNorOut], ["rNorOut", rNorOut]],
Instance[readDecoder, ["adr", rAdr], ["norOut", rNorOut]]
]
];
PWCore.SetAbutX[ct];
};
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"];
}};
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 Ports.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 Ports.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 ~Ports.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 ~Ports.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;
};
Array: PROC [b, n: NAT, sameSide: BOOL, cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
wFiller: CellType ← Sisyph.ES["wFiller.sch", cx];
writeWLDr: CellType ← Sisyph.ES["writeWLDr.sch", cx];
flipWriteWLDr: CellType ← PWCore.RotateCellType[writeWLDr, $FlipY];
topCell: CellType ← Sisyph.ES[IF sameSide THEN "readWriteTop.sch" ELSE "writeTop.sch", cx];
ramCell: CellType ← Sisyph.ES["ram2Cell.sch", cx];
flipYRamCell: CellType ← PWCore.RotateCellType[ramCell, $FlipY];
bottomCell: CellType ← Sisyph.ES[IF sameSide THEN "readWriteBottom.sch" ELSE "readBottom.sch", cx];
rFiller: CellType ← Sisyph.ES["rFiller.sch", cx];
readWLDr: CellType ← Sisyph.ES["readWLDr.sch", cx];
flipReadWLDr: CellType ← PWCore.RotateCellType[readWLDr, $FlipY];
in: Wire ← Seq["Input", b];
out: Wire ← Seq["Output", b];
rNorOut: Wire ← Seq["rNorOut", n];
wNorOut: Wire ← Seq["wNorOut", n];
tileArray: TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[n+2]];
from the bottom up: read, rows 0, ... n-1, write
FOR row: NAT IN [0..n+2) DO-- create the rows
tileArray[row] ← NEW[TilingClass.TileRowRec[b+2]];
ENDLOOP;
-- left row
tileArray[0][0] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[wFiller, $FlipY],
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the write word-line drivers
tileArray[row+1][0] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN writeWLDr ELSE flipWriteWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", wNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][0] ← NEW[TilingClass.TileRec ← [
type: wFiller,
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
-- main array
FOR i: NAT IN [0..b) DO-- column 0 is on the left
tileArray[0][i+1] ← NEW[TilingClass.TileRec ← [
type: bottomCell,
renaming: IF ~sameSide THEN LIST[ ["Output", out[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in[i]], ["Output", out[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO
tileArray[row+1][i+1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN ramCell ELSE flipYRamCell,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
tileArray[n+1][i+1] ← NEW[TilingClass.TileRec ← [
type: topCell,
renaming: IF sameSide THEN LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
-- right row
tileArray[0][b+1] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[rFiller, $FlipY],
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the read word-line drivers
tileArray[row+1][b+1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN readWLDr ELSE flipReadWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", rNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][b+1] ← NEW[TilingClass.TileRec ← [
type: rFiller,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ct ← TilingClass.CreateTiling[
name: "RamArray",
public: Wires["Vdd", "Gnd", in, out, rNorOut, wNorOut, "enW"],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY
];
};
Ram2
Extract: PUBLIC PROC [schName: ROPE, cx: Sisyph.Context, parms: LIST OF LogicUtils.Value ← NIL] RETURNS [ct: CellType] ~ {
Extracts from the Logic library with the given (INT) parameters.
tmpCx: Sisyph.Context;
IF cx=NIL THEN ERROR;
tmpCx ← IF parms=NIL THEN cx ELSE Sisyph.Copy[cx];
WHILE parms#NIL DO
Sisyph.Store[tmpCx, parms.first.name, NEW[INT ← parms.first.val]];
parms ← parms.rest;
ENDLOOP;
ct ← Sisyph.ES[schName, tmpCx];
};
Ram2Name: ROPE = Rosemary.Register[roseClassName: "Ram2", init: Ram2Init, evalSimple: Ram2Simple];
Ram2: PUBLIC PROC [b, n: NAT, sameSide, short: BOOLFALSE] 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"];
IF BitOps.ODD[n] THEN n←n+1; -- number of words must be even
IF short AND BitOps.ODD[b] THEN LogicUtils.Error["b must be even for short ram"];
ct ← (IF short THEN RamAssemblyShort ELSE RamAssembly)[b, n, sameSide];
[] ← Rosemary.BindCellType[cellType: ct, roseClassName: Ram2Name];
CoreProperties.PutCellTypeProp[ct, $n, NEW[NAT ← n]];
[] ← CoreFlat.CellTypeCutLabels[ct, logicCutSet, "Memory"];
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 Ports.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 ~Ports.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 ~Ports.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 Ports.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];
};
};
-- Layout of the original ram
ramDesign, ramShortDesign: CD.Design;
ramCx: Sisyph.Context ← NIL;
ramShortCx: Sisyph.Context ← NIL;
-- Array of size n+2 by b+2: read on bottom, write on top, writeWL driver on the left, and readWL driver on the right
Array: PROC [b, n: NAT, sameSide: BOOL, cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
wFiller: CellType ← Sisyph.ES["wFiller.sch", cx];
writeWLDr: CellType ← Sisyph.ES["writeWLDr.sch", cx];
flipWriteWLDr: CellType ← PWCore.RotateCellType[writeWLDr, $FlipY];
topCells: CellType ← Extract[IF sameSide THEN "readWriteTops.sch" ELSE "writeTops.sch", cx, LIST[["b", b]]];
ramCells: CellType ← Extract["ram2Cells.sch", cx, LIST[["b", b]]];
flipYRamCells: CellType ← PWCore.RotateCellType[ramCells, $FlipY];
bottomCells: CellType ← Extract[IF sameSide THEN "readWriteBottoms.sch" ELSE "readBottoms.sch", cx, LIST[["b", b]]];
rFiller: CellType ← Sisyph.ES["rFiller.sch", cx];
readWLDr: CellType ← Sisyph.ES["readWLDr.sch", cx];
flipReadWLDr: CellType ← PWCore.RotateCellType[readWLDr, $FlipY];
in: Wire ← Seq["Input", b];
out: Wire ← Seq["Output", b];
rNorOut: Wire ← Seq["rNorOut", n];
wNorOut: Wire ← Seq["wNorOut", n];
tileArray: TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[n+2]];
from the bottom up: read, rows 0, ... n-1, write
FOR row: NAT IN [0..n+2) DO-- create the rows
tileArray[row] ← NEW[TilingClass.TileRowRec[3]];
ENDLOOP;
-- left row
tileArray[0][0] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[wFiller, $FlipY],
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the write word-line drivers
tileArray[row+1][0] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN writeWLDr ELSE flipWriteWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", wNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][0] ← NEW[TilingClass.TileRec ← [
type: wFiller,
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
-- main array
tileArray[0][1] ← NEW[TilingClass.TileRec ← [
type: bottomCells,
renaming: IF ~sameSide THEN LIST[ ["Output", out], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in], ["Output", out], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO
tileArray[row+1][1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN ramCells ELSE flipYRamCells,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
tileArray[n+1][1] ← NEW[TilingClass.TileRec ← [
type: topCells,
renaming: IF sameSide THEN LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
-- right row
tileArray[0][2] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[rFiller, $FlipY],
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the read word-line drivers
tileArray[row+1][2] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN readWLDr ELSE flipReadWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", rNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][2] ← NEW[TilingClass.TileRec ← [
type: rFiller,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ct ← TilingClass.CreateTiling[
name: "RamArray",
public: Wires["Vdd", "Gnd", in, out, rNorOut, wNorOut, "enW"],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY
];
};
Decoder: PROC [n: NAT, adrOnTop: BOOL, cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
dec0: CellType ← Sisyph.ES["dec0.sch", cx];
dec1: CellType ← PWCore.RotateCellType[dec0, $FlipX];
decf0: CellType ← PWCore.RotateCellType[dec0, $FlipY];
decf1: CellType ← PWCore.RotateCellType[dec0, $Rot180];
adrAmpli: CellType ← Sisyph.ES["adrAmpli.sch", cx];
adrInv: CellType ← Sisyph.ES["adrInv.sch", cx];
botCt: CellType ← IF adrOnTop THEN PWCore.RotateCellType[adrInv, $FlipY] ELSE adrAmpli;
topCt: CellType ← IF adrOnTop THEN PWCore.RotateCellType[adrAmpli, $FlipY] ELSE adrInv;
a: NAT ← BitOps.NBits[n]; -- number of address bits
norOut: Wire ← Seq["norOut", n];
adr: Wire ← Seq["adr", a];
tileArray: TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[n+2]];
-- from the bottom up: botCt, rows 0, ... n-1, topCt
FOR row: NAT IN [0..n+2) DO-- create the rows
tileArray[row] ← NEW[TilingClass.TileRowRec[a]];
ENDLOOP;
FOR i: NAT IN [0..a) DO-- column 0 is on the left
tileArray[0][i] ← NEW[TilingClass.TileRec ← [
type: botCt,
renaming: IF adrOnTop THEN LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["ad", adr[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO
tileArray[row+1][i] ← NEW[TilingClass.TileRec ← [
type: SELECT TRUE FROM
BitOps.EVEN[row] AND BitOps.EBFW[row, 15-i] => dec0,
BitOps.EVEN[row] AND ~BitOps.EBFW[row, 15-i] => dec1,
BitOps.ODD[row] AND BitOps.EBFW[row, 15-i] => decf0,
BitOps.ODD[row] AND ~BitOps.EBFW[row, 15-i] => decf1,
ENDCASE => ERROR,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", norOut[row]]]]];
ENDLOOP;
tileArray[n+1][i] ← NEW[TilingClass.TileRec ← [
type: topCt,
renaming: IF adrOnTop THEN LIST[ ["ad", adr[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
ct ← TilingClass.CreateTiling[
name: "Decoder",
public: Wires[adr, norOut, "Vdd", "Gnd"],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY
];
};
RamAssembly: PROC [b, n: NAT, sameSide: BOOL] RETURNS [ct: CellType] ~ {
a: NAT ← BitOps.NBits[n]; -- number of address bits
array, writeDecoder, readDecoder: CellType;
wNorOut, rNorOut, wAdr, rAdr: Wire;
IF ramDesign=NIL THEN ramDesign ← PW.OpenDesign["LogicRam2"];
ramCx ← Sisyph.Create[ramDesign];
array ← Extract[IF sameSide THEN "ArraySameSide.sch" ELSE "ArrayThrough.sch",
ramCx, LIST[["b", b], ["n", n]]];
writeDecoder ← Decoder[n: n, adrOnTop: ~sameSide, cx: ramCx];
readDecoder ← Decoder[n: n, adrOnTop: FALSE, cx: ramCx];
wNorOut ← Seq["wNorOut", n];
rNorOut ← Seq["rNorOut", n];
wAdr ← Seq["WAdr", a];
rAdr ← Seq["RAdr", a];
ct ← Cell[
public: Wires["Vdd", "Gnd", Seq["Input", b], Seq["Output", b], rAdr, wAdr, "enW"],
onlyInternal: Wires[wNorOut, rNorOut],
instances: LIST[
Instance[writeDecoder, ["adr", wAdr], ["norOut", wNorOut]],
Instance[array, ["Input", "Input"], ["Output", "Output"], ["wNorOut", wNorOut], ["rNorOut", rNorOut]],
Instance[readDecoder, ["adr", rAdr], ["norOut", rNorOut]]
]
];
PWCore.SetAbutX[ct];
};
-- Layout of the short ram
ArrayShort: PROC [b, n: NAT, sameSide: BOOL, cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
wFiller: CellType ← Sisyph.ES["wFiller.sch", cx];
writeWLDr: CellType ← Sisyph.ES["writeWLDr.sch", cx];
flipWriteWLDr: CellType ← PWCore.RotateCellType[writeWLDr, $FlipY];
topCell: CellType ← Sisyph.ES[IF sameSide THEN "readWriteTop.sch" ELSE "writeTop.sch", cx];
flipXTopCell: CellType ← PWCore.RotateCellType[topCell, $FlipX];
ramCell: CellType ← Sisyph.ES["ram2Cell.sch", cx];
flipYRamCell: CellType ← PWCore.RotateCellType[ramCell, $FlipY];
flipXRamCell: CellType ← PWCore.RotateCellType[ramCell, $FlipX];
flipXYRamCell: CellType ← PWCore.RotateCellType[ramCell, $Rot180];
bottomCell: CellType ← Sisyph.ES[IF sameSide THEN "readWriteBottom.sch" ELSE "readBottom.sch", cx];
flipXBottomCell: CellType ← PWCore.RotateCellType[bottomCell, $FlipX];
rFiller: CellType ← Sisyph.ES["rFiller.sch", cx];
readWLDr: CellType ← Sisyph.ES["readWLDr.sch", cx];
flipReadWLDr: CellType ← PWCore.RotateCellType[readWLDr, $FlipY];
in: Wire ← Seq["Input", b];
out: Wire ← Seq["Output", b];
rNorOut: Wire ← Seq["rNorOut", n];
wNorOut: Wire ← Seq["wNorOut", n];
tileArray: TilingClass.TileArray ← NEW[TilingClass.TileArrayRec[n+2]];
from the bottom up: read, rows 0, ... n-1, write
FOR row: NAT IN [0..n+2) DO-- create the rows
tileArray[row] ← NEW[TilingClass.TileRowRec[b+2]];
ENDLOOP;
-- left row
tileArray[0][0] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[wFiller, $FlipY],
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the write word-line drivers
tileArray[row+1][0] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN writeWLDr ELSE flipWriteWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", wNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][0] ← NEW[TilingClass.TileRec ← [
type: wFiller,
renaming: LIST[ ["enW", "enW"], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
-- main array
FOR i: NAT IN [0..b) DO-- column 0 is on the left
tileArray[0][i+1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[i] THEN bottomCell ELSE flipXBottomCell,
renaming: IF ~sameSide THEN LIST[ ["Output", out[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in[i]], ["Output", out[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO
tileArray[row+1][i+1] ← NEW[TilingClass.TileRec ← [
type: SELECT TRUE FROM
BitOps.EVEN[row] AND BitOps.EVEN[i] => ramCell,
BitOps.ODD[row] AND BitOps.EVEN[i] => flipYRamCell,
BitOps.EVEN[row] AND BitOps.ODD[i] => flipXRamCell,
BitOps.ODD[row] AND BitOps.ODD[i] => flipXYRamCell,
ENDCASE => ERROR,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
tileArray[n+1][i+1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[i] THEN topCell ELSE flipXTopCell,
renaming: IF sameSide THEN LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]
ELSE LIST[ ["Input", in[i]], ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ENDLOOP;
-- right row
tileArray[0][b+1] ← NEW[TilingClass.TileRec ← [
type: PWCore.RotateCellType[rFiller, $FlipY],
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
FOR row: NAT IN [0..n) DO-- the read word-line drivers
tileArray[row+1][b+1] ← NEW[TilingClass.TileRec ← [
type: IF BitOps.EVEN[row] THEN readWLDr ELSE flipReadWLDr,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"], ["norOut", rNorOut[row]]]]];
ENDLOOP;
tileArray[n+1][b+1] ← NEW[TilingClass.TileRec ← [
type: rFiller,
renaming: LIST[ ["Gnd", "Gnd"], ["Vdd", "Vdd"] ]]];
ct ← TilingClass.CreateTiling[
name: "RamArray",
public: Wires["Vdd", "Gnd", in, out, rNorOut, wNorOut, "enW"],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY
];
};
RamAssemblyShort: PROC [b, n: NAT, sameSide: BOOL] RETURNS [ct: CellType] ~ {
a: NAT ← BitOps.NBits[n]; -- number of address bits
array, writeDecoder, readDecoder: CellType;
wNorOut, rNorOut, wAdr, rAdr: Wire;
IF ramShortDesign=NIL THEN ramShortDesign ← PW.OpenDesign["LogicRam2Short"];
ramShortCx ← Sisyph.Create[ramShortDesign];
array ← ArrayShort[b, n, sameSide, ramShortCx];
writeDecoder ← Decoder[n: n, adrOnTop: ~sameSide, cx: ramShortCx];
readDecoder ← Decoder[n: n, adrOnTop: FALSE, cx: ramShortCx];
wNorOut ← Seq["wNorOut", n];
rNorOut ← Seq["rNorOut", n];
wAdr ← Seq["WAdr", a];
rAdr ← Seq["RAdr", a];
ct ← Cell[
public: Wires["Vdd", "Gnd", Seq["Input", b], Seq["Output", b], rAdr, wAdr, "enW"],
onlyInternal: Wires[wNorOut, rNorOut],
instances: LIST[
Instance[writeDecoder, ["adr", wAdr], ["norOut", wNorOut]],
Instance[array, ["Input", "Input"], ["Output", "Output"], ["wNorOut", wNorOut], ["rNorOut", rNorOut]],
Instance[readDecoder, ["adr", rAdr], ["norOut", rNorOut]]
]
];
PWCore.SetAbutX[ct];
};