SmallCacheUtilsImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Written by: Pradeep Sindhu, October 2, 1986 10:52:55 pm PDT
Pradeep Sindhu, April 28, 1988 12:37:55 pm PDT
Cesar Douady January 12, 1988 8:18:59 pm PST
DIRECTORY
CD, CDIO, CDViewer, CommandTool, Convert, Core, CoreCreate, CoreGeometry, CoreOps, GList, IO, PWCore, Rope, RopeList, SCParms, Sinix, Sisyph, SmallCacheUtils, TerminalIO, TilingClass;
SmallCacheUtilsImpl: CEDAR PROGRAM
IMPORTS CDViewer, CommandTool, CDIO, Convert, CoreCreate, CoreGeometry, CoreOps, GList, IO, PWCore, Rope, RopeList, SCParms, Sinix, Sisyph, TerminalIO, TilingClass
EXPORTS SmallCacheUtils
~ BEGIN OPEN SmallCacheUtils;
workingDirectory: PUBLIC ROPE ← CommandTool.CurrentWorkingDirectory[];
layoutDesign: CD.Design ← NIL;
Exported Procs
Log2: PUBLIC PROC [n: INT] RETURNS [log: INT ← 0] ~ {
WHILE n > 1 DO n ← n/2; log ← log+1 ENDLOOP
};
ComRecord: PUBLIC PROC [pattern: ROPE, cx: Sisyph.Context, ctName: ROPE] RETURNS [ct: CellType] ~ {
n: Names ← NIL;
FOR i: INT DECREASING IN [0..Rope.Length[pattern]) DO
SELECT Rope.Fetch[pattern, i] FROM
'0 => n ← CONS["ComCell0.icon", n];
'1 => n ← CONS["ComCell1.icon", n];
'X => n ← CONS["ComCellX.icon", n];
'N => n ← CONS["ComCellN.icon", n];
'E => n ← CONS["ComCellE.icon", n];
ENDCASE => ERROR;
ENDLOOP;
ct ← RecordX[n, cx, Rope.Cat[ctName, pattern]];
};
This procedure constructs a tiling row from a list of object names. It is assumed that the publics of each of the objects are the same.
RecordX: PUBLIC PROC [obNames: Names, cx: Sisyph.Context, ctName: ROPE] RETURNS [ct: CellType] ~ {
count: NAT ← RopeList.Length[obNames];
Index: TYPE = {ComCell0, ComCell1, ComCellX, ComCellN, ComCellE};
baseCTs: CellTypes ← NIL;
public: Wire; -- public of cellType to be returned
tileRow: TilingClass.TileRow ← NEW [TilingClass.TileRowRec[count]];
tileArray: TilingClass.TileArray ← NEW [TilingClass.TileArrayRec[1]];
publicElements, arrayedWires, leftSideOnlyWires, rightSideOnlyWires, globalWires: Wires ← NIL;
EachWire: CoreOps.EachWireProc = {
sides: CoreGeometry.Sides = WireSide[wire, baseCTs.first];
vertical: BOOL = sides[top] OR sides[bottom];
IF vertical AND (sides[right] OR sides[left]) THEN WireSideProblem[wire, "touches adjacent sides", baseCTs.first];
IF vertical
THEN {
newPublic: Wire ← CoreOps.CreateWires[count, CoreOps.GetShortWireName[wire]];
arrayedWires ← CONS[wire, arrayedWires];
FOR i: INT IN [0..count) DO
newPublic[i] ← CoreOps.SetShortWireName[CoreOps.CopyWire[wire], NIL];
ENDLOOP;
publicElements ← CONS[newPublic, publicElements];
}
ELSE {
IF sides=CoreGeometry.noSide
THEN {
IF IsGlobal[wire, cx] THEN {
globalWires ← CONS [wire, globalWires];
publicElements ← CONS [wire, publicElements]
}
}
ELSE {
IF sides[left] THEN leftSideOnlyWires ← CONS[wire, leftSideOnlyWires];
IF sides[right] THEN rightSideOnlyWires ← CONS[wire, rightSideOnlyWires];
publicElements ← CONS [wire, publicElements]
}
}
};
Make the baseCellTypes
FOR l: Names ← obNames, l.rest WHILE l#NIL DO
baseCTs ← CONS[Sisyph.ExtractSchematicByName[l.first, cx], baseCTs];
ENDLOOP;
baseCTs ← NARROW[GList.Reverse[baseCTs]];
Compute the public of the cellType to be returned
[] ← CoreOps.VisitWireSeq[baseCTs.first.public, EachWire];
public ← CoreOps.CreateWire[publicElements];
Fill in the cellTypes
FOR i: INT IN [0..count) DO
tileRow[i] ← NEW [TilingClass.TileRec ← [type: baseCTs.first]];
baseCTs ← baseCTs.rest;
ENDLOOP;
Define the renaming for wires that touch the left side
FOR wl: Wires ← leftSideOnlyWires, wl.rest WHILE wl#NIL DO
wireName: ROPE ← CoreOps.GetShortWireName[wl.first];
tileRow[0].renaming ← CONS[[wireName, wireName], tileRow[0].renaming];
ENDLOOP;
Define the renaming for wires that touch the right side
FOR wl: Wires ← rightSideOnlyWires, wl.rest WHILE wl#NIL DO
wireName: ROPE ← CoreOps.GetShortWireName[wl.first];
tileRow[count-1].renaming ← CONS[[wireName, wireName], tileRow[count-1].renaming];
ENDLOOP;
Define the renaming for global wires
FOR wl: Wires ← globalWires, wl.rest WHILE wl#NIL DO
wireName: ROPE ← CoreOps.GetShortWireName[wl.first];
FOR i: NAT IN [0..count) DO
tileRow[i].renaming ← CONS[[wireName, wireName], tileRow[i].renaming];
ENDLOOP;
ENDLOOP;
Define the renaming for arrayed wires
FOR wl: Wires ← arrayedWires, wl.rest WHILE wl#NIL DO
wireName: ROPE ← CoreOps.GetShortWireName[wl.first];
FOR i: NAT IN [0..count) DO
tileRow[i].renaming ← CONS[[wireName, Rope.Cat[wireName, "[", Convert.RopeFromInt[i], "]"]], tileRow[i].renaming];
ENDLOOP;
ENDLOOP;
tileArray[0] ← tileRow;
Copying the public is necessary to avoid sharing of wires between cellTypes
ct ← TilingClass.CreateTiling[CoreOps.CopyWire[public], tileArray, TilingClass.SchematicsNeighborX, TilingClass.SchematicsNeighborY, Rope.Cat[ctName, ".RecordX"]];
};
RamInterfaceRout: PUBLIC PROC [cx: Sisyph.Context] RETURNS [ct: CellType] ~ {
Flip: TYPE ~ {normal, flipped};
BaseCells: TYPE ~ REF BaseCellsRep;
BaseCellsRep: TYPE ~ RECORD [v: SEQUENCE size: NAT OF ARRAY Flip OF RECORD [ct: CellType, w: Wire]];
index, selIndex, spareIndex: INT;
baseB: BaseCells ← NEW [BaseCellsRep[SCParms.numBytesPerWord]];
baseW: BaseCells ← NEW [BaseCellsRep[SCParms.numWordsPerLine]];
spacerB, spacerW: CellType;
spare: Wire ← CoreCreate.Seq[size: SCParms.numBitsPerCycle, name: "Spare"];
byteSel: Wire ← CoreCreate.Seq[size: SCParms.numBytesPerWord, name: "ByteSel"];
bS: Wire ← CoreCreate.Seq[size: SCParms.numBitsPerLine, name: "BS"];
wordSel: Wire ← CoreCreate.Seq[size: SCParms.numWordsPerLine, name: "WdSel"];
wS: Wire ← CoreCreate.Seq[size: SCParms.numBitsPerLine, name: "WS"];
f0: Wire ← CoreCreate.Seq[size: SCParms.numBitsPerLine, name: "F0"]; -- feedthrough
f1: Wire ← CoreCreate.Seq[size: SCParms.numBitsPerLine, name: "F1"]; -- feedthrough
count: INT ~ SCParms.numBitsPerLine+SCParms.numBitsPerCycle; -- Including the spare lines
tileRowB: TilingClass.TileRow ← NEW [TilingClass.TileRowRec[count]];
tileRowW: TilingClass.TileRow ← NEW [TilingClass.TileRowRec[count]];
tileArray: TilingClass.TileArray ← NEW [TilingClass.TileArrayRec[2]];
Make the baseCellTypes
FOR i: NAT IN [0..SCParms.numBytesPerWord) DO
name: ROPE = IO.PutFR["RamInterfaceBitRout2%g.sch", IO.int[i]];
bSName: ROPE = IO.PutFR["ByteSel[%g]", IO.int[i]];
baseB[i][normal].ct ← Sisyph.ExtractSchematicByName[name, Sisyph.Copy[cx]];
baseB[i][flipped].ct ← PWCore.RotateCellType[baseB[i][normal].ct, $FlipX];
FOR m: Flip IN Flip DO
baseB[i][m].w ← CoreOps.FindWire[baseB[i][m].ct.public, bSName];
ENDLOOP;
ENDLOOP;
FOR word: NAT IN [0..SCParms.numWordsPerLine) DO
name: ROPE = IO.PutFR["RamInterfaceBitRout1%g.sch", IO.int[word]];
wSName: ROPE = IO.PutFR["WdSel[%g]", IO.int[word]];
baseW[word][normal].ct ← Sisyph.ExtractSchematicByName[name, Sisyph.Copy[cx]];
baseW[word][flipped].ct ← PWCore.RotateCellType[baseW[word][normal].ct, $FlipX];
FOR m: Flip IN Flip DO
baseW[word][m].w ← CoreOps.FindWire[baseW[word][m].ct.public, wSName];
ENDLOOP;
ENDLOOP;
spacerB ← Sisyph.ExtractSchematicByName["RamInterfaceSpacerRout2.sch", cx];
spacerW ← Sisyph.ExtractSchematicByName["RamInterfaceSpacerRout1.sch", cx];
Compute the public of the cellType to be returned
Fill in the cellTypes
index ← 0; -- index in the tilling class
selIndex ← 0; -- index in the BS wire
spareIndex ← 0; -- index in the Spare wire
FOR i: INT IN [0..SCParms.numBytesPerWord) DO
FOR j: INT IN [0..SCParms.numBitsPerByte) DO
word: INT ← 0;
FOR k: INT IN [0..SCParms.numWordsPerCycle) DO
FOR l: INT IN [0..SCParms.numCyclesPerLine/2) DO
FOR m: Flip IN Flip DO
bS[selIndex] ← byteSel[i];
wS[selIndex] ← wordSel[word];
tileRowB[index] ← NEW [TilingClass.TileRec ← [
type: baseB[i][m].ct,
renaming: LIST[
[public: "ByteSel", actual: byteSel],
[public: "F0", actual: f0[selIndex]],
[public: "F1", actual: f1[selIndex]],
[public: "WS", actual: wS[selIndex]],
[public: baseB[i][m].w, actual: bS[selIndex]]
]]];
tileRowW[index] ← NEW [TilingClass.TileRec ← [
type: baseW[word][m].ct,
renaming: LIST[
[public: "WdSel", actual: wordSel],
[public: "F0", actual: f0[selIndex]],
[public: "F1", actual: f1[selIndex]],
[public: baseW[word][m].w, actual: wS[selIndex]]
]]];
selIndex ← selIndex+1;
index ← index+1;
word ← word+1;
ENDLOOP;
ENDLOOP;
tileRowB[index] ← NEW [TilingClass.TileRec ← [
type: spacerB,
renaming: LIST[
[public: "ByteSel", actual: byteSel],
[public: "Spare", actual: spare[spareIndex]]
]]];
tileRowW[index] ← NEW [TilingClass.TileRec ← [
type: spacerW,
renaming: LIST[
[public: "WdSel", actual: wordSel],
[public: "Spare", actual: spare[spareIndex]]
]]];
spareIndex ← spareIndex +1;
index ← index+1;
ENDLOOP;
IF word # SCParms.numWordsPerLine THEN ERROR;
ENDLOOP;
ENDLOOP;
IF index # count THEN ERROR;
IF selIndex # SCParms.numBitsPerLine THEN ERROR;
IF spareIndex # SCParms.numBitsPerCycle THEN ERROR;
tileArray[1] ← tileRowW;
tileArray[0] ← tileRowB;
Copying the public is necessary to avoid sharing of wires between cellTypes
ct ← TilingClass.CreateTiling[
public: CoreCreate.Wires[spare, byteSel, bS, wordSel, wS, f0, f1],
tileArray: tileArray,
neighborX: TilingClass.LayoutNeighborX,
neighborY: TilingClass.LayoutNeighborY,
name: "RamInterfaceRout"];
};
Interleave: PUBLIC PROC [b: NAT] RETURNS [public: Core.Wires] = {
wire: Wire ← CoreCreate.Seq["Wire", b];
interleavedWire: Wire ← CoreCreate.Seq["InterleavedWire", b];
IF b MOD 2 = 1 THEN ERROR;
IF b=0 THEN ERROR;
FOR i: NAT IN [0..b/2) DO
interleavedWire[2*i] ← wire[i];
interleavedWire[2*i+1] ← wire[b/2+i];
ENDLOOP;
public ← LIST [wire, interleavedWire];
};
Interleave2: PUBLIC PROC [b: NAT] RETURNS [public: Core.Wires] = {
wire0: Wire ← CoreCreate.Seq["Wire0", b/2];
wire1: Wire ← CoreCreate.Seq["Wire1", b/2];
interleavedWire: Wire ← CoreCreate.Seq["InterleavedWire", b];
IF b MOD 2 = 1 THEN ERROR;
IF b=0 THEN ERROR;
FOR i: NAT IN [0..b/2) DO
interleavedWire[2*i] ← wire0[i];
interleavedWire[2*i+1] ← wire1[i];
ENDLOOP;
public ← LIST [wire0, wire1, interleavedWire];
};
FuseGroups: PUBLIC PROC [numGroups, groupSize: NAT] RETURNS [public: Core.Wires] = {
wire: Wire ← CoreCreate.Seq["Wire", numGroups*groupSize];
fusedWire: Wire ← CoreCreate.Seq["FusedWire", numGroups];
IF numGroups <= 0 OR groupSize <= 0 THEN ERROR;
FOR i: NAT IN [0..numGroups*groupSize) DO
wire[i] ← fusedWire[i/groupSize];
ENDLOOP;
public ← LIST [wire, fusedWire];
};
Flatten: PUBLIC PROC [numGroups, groupSize: NAT] RETURNS [public: Core.Wires] = {
flatWire, wire: Wire;
IF numGroups <= 0 OR groupSize <= 0 THEN ERROR;
flatWire ← CoreCreate.Seq["FlatWire", numGroups*groupSize];
wire ← CoreCreate.Seq["Wire", numGroups, CoreCreate.Seq[size: groupSize]];
FOR i: NAT IN [0..numGroups) DO
FOR j: NAT IN [0..groupSize) DO
flatWire[i*groupSize+j] ← wire[i][j];
ENDLOOP;
ENDLOOP;
public ← LIST [wire, flatWire];
};
HexToBin: PUBLIC PROC [h: ROPE] RETURNS [b: ROPENIL] = {
FOR i: INT IN [0..Rope.Length[h]) DO
SELECT Rope.Fetch[h, i] FROM
'0  => b ← Rope.Cat[b, "0000"];
'1  => b ← Rope.Cat[b, "0001"];
'2  => b ← Rope.Cat[b, "0010"];
'3  => b ← Rope.Cat[b, "0011"];
'4  => b ← Rope.Cat[b, "0100"];
'5  => b ← Rope.Cat[b, "0101"];
'6  => b ← Rope.Cat[b, "0110"];
'7  => b ← Rope.Cat[b, "0111"];
'8  => b ← Rope.Cat[b, "1000"];
'9  => b ← Rope.Cat[b, "1001"];
'a, 'A => b ← Rope.Cat[b, "1010"];
'b, 'B => b ← Rope.Cat[b, "1011"];
'c, 'C => b ← Rope.Cat[b, "1100"];
'd, 'D => b ← Rope.Cat[b, "1101"];
'e, 'E => b ← Rope.Cat[b, "1110"];
'f, 'F => b ← Rope.Cat[b, "1111"];
'x, 'X => b ← Rope.Cat[b, "xxxx"];
ENDCASE => ERROR;
ENDLOOP;
};
BinToHex: PUBLIC PROC [b: ROPE] RETURNS [h: ROPENIL] = {
IF Rope.Length[b] MOD 4 # 0 THEN ERROR;
FOR i: INT IN [0..Rope.Length[b]/4) DO
digit: ROPE ← Rope.Substr[b, 0, 4];
b ← Rope.Substr[b, 4];
SELECT TRUE FROM
Rope.Equal[digit, "0000", FALSE]  => h ← Rope.Cat[h, "0"];
Rope.Equal[digit, "0001", FALSE]  => h ← Rope.Cat[h, "1"];
Rope.Equal[digit, "0010", FALSE]  => h ← Rope.Cat[h, "2"];
Rope.Equal[digit, "0011", FALSE]  => h ← Rope.Cat[h, "3"];
Rope.Equal[digit, "0100", FALSE]  => h ← Rope.Cat[h, "4"];
Rope.Equal[digit, "0101", FALSE]  => h ← Rope.Cat[h, "5"];
Rope.Equal[digit, "0110", FALSE]  => h ← Rope.Cat[h, "6"];
Rope.Equal[digit, "0111", FALSE]  => h ← Rope.Cat[h, "7"];
Rope.Equal[digit, "1000", FALSE]  => h ← Rope.Cat[h, "8"];
Rope.Equal[digit, "1001", FALSE]  => h ← Rope.Cat[h, "9"];
Rope.Equal[digit, "1010", FALSE]  => h ← Rope.Cat[h, "a"];
Rope.Equal[digit, "1011", FALSE]  => h ← Rope.Cat[h, "b"];
Rope.Equal[digit, "1100", FALSE]  => h ← Rope.Cat[h, "c"];
Rope.Equal[digit, "1101", FALSE]  => h ← Rope.Cat[h, "d"];
Rope.Equal[digit, "1110", FALSE]  => h ← Rope.Cat[h, "e"];
Rope.Equal[digit, "1111", FALSE]  => h ← Rope.Cat[h, "f"];
Rope.Equal[digit, "xxxx", FALSE]  => h ← Rope.Cat[h, "x"];
ENDCASE => ERROR;
ENDLOOP;
};
BlockToInterleavedBlock: PUBLIC PROC [b: ROPE] RETURNS [ib: ROPENIL] = {
b ← HexToBin[b];
IF Rope.Length[b]#SCParms.numBitsPerLine THEN ERROR;
FOR i: NAT IN [0..SCParms.numBitsPerWord) DO
FOR c: NAT IN [0..SCParms.numCyclesPerLine) DO
FOR w: NAT IN [0..SCParms.numWordsPerCycle) DO
ib ← Rope.Cat[ib, Rope.FromChar[Rope.Fetch[b, w*SCParms.numBitsPerWord+c*SCParms.numBitsPerCycle+i]]]
ENDLOOP;
ENDLOOP;
ENDLOOP;
ib ← BinToHex[ib];
};
InterleavedBlockToBlock: PUBLIC PROC [ib: ROPE] RETURNS [b: ROPENIL] = {
ib ← HexToBin[ib];
IF Rope.Length[ib]#SCParms.numBitsPerLine THEN ERROR;
FOR c: NAT IN [0..SCParms.numCyclesPerLine) DO
FOR w: NAT IN [0..SCParms.numWordsPerCycle) DO
FOR i: NAT IN [0..SCParms.numBitsPerWord) DO
b ← Rope.Cat[b, Rope.FromChar[Rope.Fetch[ib, i*SCParms.numWordsPerLine+SCParms.numWordsPerCycle*c+w]]]
ENDLOOP;
ENDLOOP;
ENDLOOP;
b ← BinToHex[b];
};
GetDesign: PUBLIC PROC [name: ROPE] RETURNS [design: CD.Design] = {
design ← CDViewer.FindDesign[name];
IF design=NIL THEN design ← CDIO.ReadDesign[name, NIL, workingDirectory];
};
LayoutDesign: PUBLIC PROC [] RETURNS [design: CD.Design] = {
name: ROPE ← "SmallCacheArrayLayout"; -- must declare it as a rope!
IF layoutDesign=NIL THEN layoutDesign ← GetDesign[name];
design ← layoutDesign;
};
Internal Utilities
IsGlobal: PROC [w: Wire, cx: Sisyph.Context] RETURNS [BOOLFALSE] = {
name: ROPE ← CoreOps.GetShortWireName[w];
FOR lr: LIST OF ROPE ← Sisyph.GetGlobalNames[cx], lr.rest WHILE lr#NIL DO
IF Rope.Equal[name, lr.first] THEN RETURN [TRUE]
ENDLOOP;
};
WireSide: PROC [wire: Wire, baseCT: CellType] RETURNS [sides: CoreGeometry.Sides ← CoreGeometry.noSide] ~ {
Finds the sides on which wire touches baseCT (of which it is a public). CoreGeometry.noSide will be returned if the wire has no pins. This should be in CoreGeometry.
EachPin: CoreGeometry.EachPinProc = {
sides[side] ← TRUE;
};
[] ← CoreGeometry.EnumerateSides[Sisyph.mode.decoration, baseCT, wire, EachPin];
};
WireSideProblem: PROC [wire: Wire, msg: ROPE, baseCT: CellType] ~ {
TerminalIO.PutF["\n*** Wire %g %g in cell %g\n",
IO.rope[CoreOps.GetFullWireName[baseCT.public, wire]],
IO.rope[msg],
IO.rope[CoreOps.GetCellTypeName[baseCT]]];
SIGNAL Sinix.CallerBug[];
};
CatIndex: PROC[name: ROPE, index: INT] RETURNS [ROPE] ~ {
RETURN [Rope.Cat[name, "[", Convert.RopeFromInt[index], "]"]]
};
END.