<> <> <> <> <> <> <> <<>> 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; <> 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] ~ { <> 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: BOOL _ FALSE] 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: 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; }; <<-- 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>> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <<>> <> <> <> <> <> <<>> <<-- left row>> <> <> <> <> <> <> <> <> <> <> <> <<>> <<-- main array>> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <<-- right row>> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <<];>> <<};>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<]>> <<];>> <> <<};>> <<-- Layout of the short ram>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <<>> <> <> <> <> <> <<>> <<-- left row>> <> <> <> <> <> <> <> <> <> <> <> <<>> <<-- main array>> <> <> <> <> <> <> <> <> < ramCell,>> < flipYRamCell,>> < flipXRamCell,>> < flipXYRamCell,>> < ERROR,>> <> <> <> <> <> <> <> <<>> <<-- right row>> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <> <<];>> <<};>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<]>> <<];>> <> <<};>> <> <> <> <> <> <<[] _ Rosemary.BindCellType[cellType: ct, roseClassName: FifoName];>> <> <> <<[] _ CoreFlat.CellTypeCutLabels[ct, macroCutSet];>> <> <> <> <> <<};>> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <<};>> <> <<};>> <<>> <> <> <> <> <> <> <> <> <> <> <> <<>> <> <> <> <> <> <<[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"];>> <> <> <> <> <> <> <> <> <> <> <<};>> <<>> <> <> <<{OPEN state;>> <> <