DataPathLayout.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Don Curry, November 10, 1987 12:46:04 pm PST
Last Edited by: Gasbarro November 11, 1987 7:48:44 pm PST
DIRECTORY Basics, CD, CDBasics, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Convert, Core, CoreClasses, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DataPath, RefTab, IO, PW, PWCore, Rope, Sisyph, SymTab, TerminalIO;
DataPathLayout: CEDAR PROGRAM
IMPORTS Basics, CD, CDBasics, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Convert, CoreClasses, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DataPath, RefTab, IO, PW, PWCore, Rope, Sisyph, SymTab, TerminalIO
EXPORTS DataPath
SHARES CDRects =
BEGIN OPEN DP: DataPath;
Signals and constants
Signal:   SIGNAL[msg: DP.ROPENIL] = CODE;
DrawingError: SIGNAL = CODE;
schDeco:   PUBLIC CoreGeometry.Decoration ← Sisyph.mode.decoration;
layDeco:   PUBLIC CoreGeometry.Decoration ← PWCore.extractMode.decoration;
layRules:   ATOM ← $cmosB;
dpKeyTab:  SymTab.Ref ← SymTab.Create[];
sectionRtEdge: NATLAST[NAT];
Layout Proc
Layout:   PWCore.LayoutProc ~ {
data:   CoreClasses.RecordCellType ← NARROW[cellType.data];
spec:   DP.DPSpec ← NewCellTypeSpec[cellType];
interleave: BOOL  ← CoreProperties.GetCellTypeProp[cellType, $DataPathInterleave]#NIL;
refPolyBits: REF INT ← NARROW
[CoreProperties.GetCellTypeProp[cellType, $ChanPolyBits]];
schIR:   CD.Rect ← [x1: LAST[INT], x2: FIRST[INT], y1: LAST[INT], y2: FIRST[INT]];
xIntervals: DP.Intervals ← NIL;
yIntervals: DP.Intervals ← NIL;
yIntervalsCh: DP.Intervals ← NIL;
colBuss:  NAT ← spec.buses*spec.schBusW;
count:   NAT ← 0;
nofRows:  NAT ← 0;
nofCols:  NAT ← 0;
row:   NAT ← 0;
col:   NAT ← 0;
dp:   DP.Form ← NIL;
loc:   CD.Position;
size:   CD.Position;
spec.n    ← GetSize[data[0].type];
spec.cols   ← 0;
spec.interleave ← interleave;
spec.chPolyBits ← IF refPolyBits#NIL THEN refPolyBits^ ELSE 0;
Build Interval Lists
TerminalIO.PutF["Layout %g\n", IO.rope[CoreOps.GetCellTypeName[cellType]]];
FOR child: NAT IN [0..data.size) DO
width: INT ← spec.schDWidth+colBuss;
exposedBusses: INT;
[loc, size] ← LocSize[data.instances[child]];
exposedBusses ← (width-size.x+slop)/spec.schBusW; -- icons must be correct width
xIntervals ← InsertInterval[[loc.x-exposedBusses*spec.schBusW, width], xIntervals];
yIntervals ← InsertInterval[[loc.y,         size.y], yIntervals];
ENDLOOP;
yIntervalsCh ← FindChIntervals[spec, cellType, yIntervals];
Examine Interval Lists
FOR list: DP.Intervals ← yIntervals, list.rest WHILE list#NIL DO
nofRows ← nofRows+1;
schIR.y1 ← MIN[schIR.y1, list.first.loc]; schIR.y2 ← MAX[schIR.y2, list.first.loc + list.first.size];
IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[
IO.PutFR["Rows %g and %g Overlap\n", IO.int[nofRows], IO.int[nofRows+1]]] ENDLOOP;
FOR list: DP.Intervals ← yIntervalsCh, list.rest WHILE list#NIL DO
nofRows ← nofRows+1;
schIR.y1 ← MIN[schIR.y1, list.first.loc]; schIR.y2 ← MAX[schIR.y2, list.first.loc + list.first.size];
IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[] ENDLOOP;
FOR list: DP.Intervals ← xIntervals, list.rest WHILE list#NIL DO
nofCols ← nofCols+1;
schIR.x1 ← MIN[schIR.x1, list.first.loc]; schIR.x2 ← MAX[schIR.x2, list.first.loc + list.first.size];
IF list.rest#NIL AND list.first.loc + list.first.size > list.rest.first.loc THEN Signal[] ENDLOOP;
Build dp: DataPath, row - column array
dp  ← NEW[DP.RowSeqRec[nofRows]];
dp.schIR ← schIR;
dp.cell ← cellType;
dp.spec ← spec;
dp.wpo ← RefTab.Create[];
IF dp.spec.cols#0 AND dp.spec.cols#nofCols THEN Signal[];
dp.spec.cols ← nofCols;
FOR row IN [0..dp.size) DO
sb: BOOL ← yIntervals=NIL OR yIntervalsCh#NIL AND yIntervalsCh.first.loc<yIntervals.first.loc;
dp[row] ← NEW[DP.ColSeqRec[nofCols]];
dp[row].schIR ← dp.schIR;
IF sb
THEN {
dp[row].ch  ← RefTab.Create[];
dp[row].schIR.y1 ← yIntervalsCh.first.loc;
dp[row].schIR.y2 ← yIntervalsCh.first.loc + yIntervalsCh.first.size;
yIntervalsCh  ← yIntervalsCh.rest}
ELSE {
dp[row].schIR.y1 ← yIntervals.first.loc;
dp[row].schIR.y2 ← yIntervals.first.loc + yIntervals.first.size;
yIntervals ← yIntervals.rest};
col ← 0;
FOR xlist: DP.Intervals ← xIntervals, xlist.rest WHILE xlist#NIL DO
dp[row][col].schIR.x1 ← xlist.first.loc;
dp[row][col].schIR.x2 ← xlist.first.loc + xlist.first.size;
dp[row][col].schIR.y1 ← dp[row].schIR.y1;
dp[row][col].schIR.y2 ← dp[row].schIR.y2;
IF ~sb THEN dp[row][col].wpo ← RefTab.Create[];
col ← col+1 ENDLOOP;
ENDLOOP;
Find section instances
FOR child: NAT IN [0..data.size) DO
[loc, size] ← LocSize[data.instances[child]];
FOR row DECREASING IN [0..dp.size) DO
IF dp[row].schIR.y1 <= loc.y THEN EXIT REPEAT FINISHED => Signal[] ENDLOOP;
FOR col DECREASING IN [0..dp[row].size) DO
IF dp[row][col].schIR.x1 <= loc.x THEN EXIT REPEAT FINISHED => Signal[] ENDLOOP;
IF dp[row][col].schInst#NIL THEN Signal[];
dp[row][col].schInst  ← data.instances[child];
IF (SchHalfBus[spec, loc.x - dp[row][col].schIR.x1] MOD 2) # 0 THEN Signal[];
dp[row][col].devBOff ← SchHalfBus[spec, loc.x - dp[row][col].schIR.x1]/2;
ENDLOOP;
ShowDP[dp];
Make Device Layouts
FOR row IN [0..dp.size) DO
IF dp[row].ch=NIL THEN FOR col IN [0..dp[row].size) DO
IF dp[row][col].schInst=NIL THEN LOOP;
dp[row][col].devCells ← GetDeviceCellTypes[dp[row][col].schInst];
dp[row].layY.size ← CDBasics.SizeOfRect[PWCore.InterestRect[dp[row][col].devCells[0]]].y
ENDLOOP ENDLOOP;
Make Channel Layouts
AddExplicitRoutingChannel[dp];
AddImplicitRoutingChannel[dp];
FOR row IN [0..dp.size) DO IF dp[row].ch#NIL THEN DP.BuildChan[dp, row] ENDLOOP;
Set Layout IR
FOR row IN [1..dp.size) DO
dp[row].layY.loc ← dp[row-1].layY.loc+dp[row-1].layY.size ENDLOOP;
dp.layIR ← [
x1:  0, x2: BitWidth[dp.spec]*dp.spec.cols*dp.spec.n,
y1: 0, y2: dp[dp.size-1].layY.loc+dp[dp.size-1].layY.size ];
Make Device Wiring Layouts then Complete Layout
AddExplicitRoutingSwitchBox[dp];
AddImplicitRoutingSwitchBox[dp];
AddExplicitDecorations[dp];
AddImplicitDecorations[dp];
obj ← dp.obj ← AssembleObject[dp];
TerminalIO.PutF["\nLayout %g\n", IO.rope[CoreOps.GetCellTypeName[dp.cell]]];
TerminalIO.PutF[" %g transistors\n", IO.int[CountTransistors[dp.cell]]];
ShowDP[dp];
TerminalIO.PutF["Layout Size (CMosB.lambda) x: %g y: %g xy: %g\n",
IO.int[CD.InterestSize[obj].x/CMosB.lambda],
IO.int[CD.InterestSize[obj].y/CMosB.lambda],
IO.int[(CD.InterestSize[obj].x/CMosB.lambda)*(CD.InterestSize[obj].y/CMosB.lambda)] ]};
Interval Utils
FindChIntervals: PROC[spec: DP.DPSpec, cell: DP.CellType, instY: DP.Intervals]
RETURNS[sbIVals: DP.Intervals←NIL] = {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
CheckAndAdd: PROC[loc: INT] = {
last: INT ← schIR.y1+2;
FOR list: DP.Intervals ← instY, list.rest WHILE list#NIL DO
IF loc < list.first.loc
THEN {sbIVals ← InsertInterval[[last, list.first.loc-last], sbIVals]; RETURN};
IF loc < list.first.loc + list.first.size THEN RETURN;
last ← list.first.loc + list.first.size;
REPEAT FINISHED => sbIVals ← InsertInterval[[last, schIR.y2-2-last], sbIVals] ENDLOOP};
eachWireInst: EachWireInst = {
instIR: CD.Rect ← CDBasics.MapRect[CD.InterestRect[geo.obj], geo.trans];
hor:  BOOL  ← (instIR.x2-instIR.x1) >= spec.schBusW/2;
loc:  INT  ← (instIR.y1+instIR.y2)/2;
IF hor THEN CheckAndAdd[loc]};
schIR: CD.Rect ← CD.InterestRect[CoreGeometry.GetObject[schDeco, cell]];
FOR child: NAT IN [0..data.size) DO
pos, size: CD.Position;
[pos, size] ← LocSize[data.instances[child]];
CheckAndAdd[pos.y + size.y/2] ENDLOOP;
EnumInternalSchematicGeometry[cell, eachWireInst]};
InsertInterval: PROC[intvl: DP.Interval, intvls: DP.Intervals] RETURNS[result: DP.Intervals] = {
result ← CONS[intvl, intvls];
FOR intvls ← result, intvls.rest WHILE intvls#NIL DO
TwoIntervals: TYPE = RECORD[i0, i1: DP.Interval];
IF intvls.rest=NIL OR intvls.first.loc < intvls.rest.first.loc THEN RETURN;
IF intvls.first = intvls.rest.first THEN {intvls.rest ← intvls.rest.rest; RETURN};
IF intvls.first.loc = intvls.rest.first.loc THEN IF intvls.first.size < intvls.rest.first.size
THEN RETURN
ELSE [intvls.first, intvls.rest.first] ← TwoIntervals[intvls.rest.first, intvls.first];
[intvls.first, intvls.rest.first] ← TwoIntervals[intvls.rest.first, intvls.first];
ENDLOOP};
Routing Geometry Enumeration
EachWireInst: TYPE = PROC[w: DP.Wire, geo: CoreGeometry.Instance];
GetGlobalNames: PROC[dp: DP.Form] RETURNS[globals: LIST OF DP.ROPE] =
{globals ← LIST["Gnd", "Vdd", "Vbb"]};
EnumInternalSchematicGeometry: PROC[cell: DP.CellType, eachWireInst: EachWireInst] = {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
EnumSchematicGeometry: CoreOps.EachWireProc ~ {
geometry: CoreGeometry.Instances ← CoreGeometry.GetGeometry[schDeco, wire];
IF ~RefTab.Store[visitOnceTab, wire, wire] THEN RETURN[FALSE, FALSE]; -- only once
IF geometry=NIL THEN RETURN[subWires: TRUE];
FOR geometry ← geometry, geometry.rest WHILE geometry#NIL DO
eachWireInst[wire, geometry.first] ENDLOOP;
RETURN[subWires: TRUE]};
visitOnceTab: RefTab.Ref ← RefTab.Create[];
[]𡤌oreOps.VisitWire[data.internal, EnumSchematicGeometry];
RefTab.Erase[visitOnceTab]; visitOnceTab ← NIL};
AddExplicitRoutingChannel:  PROC[dp: DP.Form] = {
eachWireInst: EachWireInst = {
instIR: CD.Rect ← CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans];
lc:   DP.LayoutCoord ← GetLayoutCoord[dp, w, instIR, TRUE];
IF CoreOps.GetShortWireName[w].Equal["CryInTerm"]
THEN TerminalIO.PutRope["Dubug Here\n"];
IF lc.hor OR lc.inBody THEN FOR row: NAT IN [lc.rowBot..lc.rowTop] DO
IF dp[row].ch#NIL THEN DP.AddChanNode[dp, row, w, lc]; ENDLOOP};
EnumInternalSchematicGeometry[dp.cell, eachWireInst]};
AddImplicitRoutingChannel:  PROC[dp: DP.Form] = {
FOR row: INT DECREASING IN [0..dp.size) DO
IF dp[row].ch#NIL THEN DP.AddPowerPassBuses[dp, row] ENDLOOP};
AddExplicitRoutingSwitchBox: PROC[dp: DP.Form] = {
eachWireInst: EachWireInst = {
instIR: CD.Rect ← CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans];
bigLC: DP.LayoutCoord ← GetLayoutCoord[dp, w, instIR, FALSE];
IF geo.obj.class#CDRects.bareRectClass THEN Signal[];
Add Bit routing and contacts
IF bigLC.inBody THEN FOR row: NAT IN [bigLC.rowBot..bigLC.rowTop] DO
IF dp[row].ch#NIL THEN LOOP;
FOR col: NAT IN [bigLC.colLt..bigLC.colRt] DO
lc:   DP.LayoutCoord ← TrimLayoutCoord[dp, bigLC, row, col];
IF lc.hor THEN {
IF lc.busLt IN [1..dp.spec.buses*2) THEN
AddPObj[dp[row][col].wpo, w,
ContPObj[dp.spec, lc.busLt, lc.yTop, lc.horLayTop]];
IF lc.busRt IN [1..dp.spec.buses*2) THEN
AddPObj[dp[row][col].wpo, w,
ContPObj[dp.spec, lc.busRt, lc.yTop, lc.horLayTop]];
AddPObj[dp[row][col].wpo, w,
HorPObj[dp.spec, lc.yTop, lc.busLt, lc.busRt, lc.horSize, lc.horLayTop]]};
IF ~lc.hor THEN {
IF lc.yBot IN (0..dp[row].layY.size) THEN
AddPObj[dp[row][col].wpo, w,
ContPObj[dp.spec, lc.busLt, lc.yBot, lc.horLayBot]];
IF lc.yTop IN (0..dp[row].layY.size) THEN
AddPObj[dp[row][col].wpo, w,
ContPObj[dp.spec, lc.busLt, lc.yTop, lc.horLayTop]];
AddPObj[dp[row][col].wpo, w,
VerPObj[dp.spec, lc.yBot, lc.yTop, lc.busLt, dp.spec.metW]]};
ENDLOOP;
ENDLOOP};
EnumInternalSchematicGeometry[dp.cell, eachWireInst]};
AddImplicitRoutingSwitchBox:  PROC[dp: DP.Form] = {
AddImplicitRoutingSwitchBoxSides[dp];
AddImplicitRoutingSwitchBoxEnds[dp]};-- only needed for missing instances
AddImplicitRoutingSwitchBoxSides:  PROC[dp: DP.Form] = {
FOR globals: LIST OF DP.ROPE ← GetGlobalNames[dp], globals.rest WHILE globals#NIL DO
FOR row: NAT IN [0..dp.size) DO
refCol:  NAT;
actualWire: DP.Wire;
cell:   DP.CellType;
lss:   LSs;
IF dp[row].ch#NIL THEN LOOP;
FOR refCol ← 0, refCol+1 WHILE refCol<dp[row].size DO
IF dp[row][refCol].schInst#NIL THEN EXIT REPEAT FINISHED => ERROR ENDLOOP;
actualWire ← CoreOps.FindWire[dp[row][refCol].schInst.actual, globals.first];
cell ← dp[row][refCol].devCells[0];
lss  ← GetGeometryLocSizes
[cell, CoreOps.FindWire[cell.public, globals.first], right, CMosB.met2];
FOR lss ← lss, lss.rest WHILE lss#NIL DO
FOR col: NAT IN [0..dp[row].size) DO
cWidth: INTIF dp[row][col].schInst=NIL
THEN sectionRtEdge
ELSE dp.spec.buses*2;
AddPObj[ dp[row][col].wpo, actualWire,
HorPObj[dp.spec, lss.first.loc+lss.first.size/2,0,cWidth,lss.first.size,CMosB.met2] ];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP};
AddImplicitRoutingSwitchBoxEnds:  PROC[dp: DP.Form] = {
gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"];
vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"];
IF dp.spec.gndBus<=0 THEN RETURN;
IF dp.spec.vddBus<=0 THEN ERROR;
FOR row: INT DECREASING IN [0..dp.size) DO
ytop: INT ← dp[row].layY.size;
IF dp[row].ch#NIL THEN LOOP;
FOR col: INT DECREASING IN [0..dp[row].size) DO
IF dp[row][col].schInst#NIL THEN LOOP;
AddPObj[dp[row][col].wpo, gnd,
VerPObj[dp.spec, 0, ytop, (dp.spec.gndBus+1)*2-1, dp.spec.pwrW]];
AddPObj[dp[row][col].wpo, vdd,
VerPObj[dp.spec, 0, ytop, (dp.spec.vddBus+1)*2-1, dp.spec.pwrW]];
ENDLOOP ENDLOOP};
AddExplicitDecorations: PROC[dp: DP.Form] = {
tagVer: DP.Object ← CDRects.CreateRect[ [x: dp.spec.metW, y: dp.spec.pinSize], CMosB.met];
tagHor: DP.Object ← CDRects.CreateRect[ [x: dp.spec.pinSize, y: dp.spec.met2W], CMosB.met2];
eachWireInst: EachWireInst = {
instIR: CD.Rect ← CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans];
bigLC: DP.LayoutCoord ← GetLayoutCoord[dp, w, instIR, FALSE];
IF bigLC.sides#CoreGeometry.noSide THEN {
tag: DP.Object ← IF bigLC.hor THEN tagHor ELSE tagVer;
FOR side: DP.Side IN DP.Side DO
loc: CD.Position;
IF NOT bigLC.sides[side] THEN LOOP;
IF side=top OR side=bottom THEN FOR bit: INT IN [0..dp.spec.n) DO
kid:  DP.Wire ← IF w.size=0 THEN w ELSE w[bit];
loc.y ← SELECT side FROM
bottom => 0,
top  => dp.layIR.y2 - CD.InterestSize[tag].y ENDCASE=>ERROR;
loc.x ← BitPosX[dp.spec, bigLC.colLt, bit]
+ dp.spec.leftTail + (bigLC.busLt-1)*dp.spec.layBusW/2 - dp.spec.metW/2;
AddPObj[dp.wpo, kid, [tag, loc]];
AddPin[    kid, [tag, loc]];
ENDLOOP;
IF side=left OR side=right THEN {
range: INTIF w.size=0 THEN 1 ELSE w.size;
FOR bit: INT IN [0..range) DO
kid: DP.Wire ← IF w.size=0 THEN w ELSE w[bit];
layy: INTIF dp[bigLC.rowBot].ch#NIL
THENDP.GetChanY[dp[bigLC.rowBot].ch, kid].loc
ELSE bigLC.yBot;
IF dp[bigLC.rowBot].ch=NIL AND w.size#0 THEN ERROR;
loc.x ← SELECT side FROM
left  => 0,
right  => dp.layIR.x2- CD.InterestSize[tag].x,
ENDCASE =>ERROR;
loc.y ← dp[bigLC.rowBot].layY.loc + layy - bigLC.horSize/2;
IF bigLC.horLayBot#CMosB.met2 THEN ERROR;
AddPObj[dp.wpo, kid, [tag, loc]];
AddPin[    kid, [tag, loc]];
ENDLOOP};
ENDLOOP } };
EnumInternalSchematicGeometry[dp.cell, eachWireInst]};
AddImplicitDecorations:    PROC[dp: DP.Form] = {
AddImplicitSideDecorations[dp];
AddImplicitEndDecorations[dp]};
AddImplicitSideDecorations:   PROC[dp: DP.Form] = {
loc:  CD.Position;
tag:  DP.Object;
FOR row: NAT IN [0..dp.size) DO
FOR globals: LIST OF DP.ROPE ← GetGlobalNames[dp], globals.rest WHILE globals#NIL DO
cell: DP.CellType;
wire: DP.Wire;
actWire: DP.Wire ← CoreOps.FindWire[dp.cell.public, globals.first];
lssLt, lssRt: LSs;
IF dp[row].ch#NIL
THEN {
lss: LSRec;
IF NOT RefTab.Fetch[dp[row].ch, actWire].found THEN LOOP;
lss ← [loc: DP.GetChanY[dp[row].ch, actWire].loc - dp.spec.met2W/2, size: dp.spec.met2W];
lssLt ← CONS[lss, NIL];
lssRt ← CONS[lss, NIL]}
ELSE {
FOR refCol: INT ← 0, refCol+1 WHILE refCol<dp[row].size DO
IF dp[row][refCol].schInst=NIL THEN LOOP;
cell  ← dp[row][refCol].devCells[0];
wire  ← CoreOps.FindWire[cell.public, globals.first];
lssLt  ← GetGeometryLocSizes[cell, wire, left, CMosB.met2];
EXIT REPEAT FINISHED => ERROR ENDLOOP;
FOR refCol: INT ← dp[row].size-1, refCol-1 WHILE refCol>=0 DO
IF dp[row][refCol].schInst=NIL THEN LOOP;
cell ← dp[row][refCol].devCells[0];
wire ← CoreOps.FindWire[cell.public, globals.first];
lssRt ← GetGeometryLocSizes[dp[row][refCol].devCells[0], wire, right, CMosB.met2];
EXIT REPEAT FINISHED => ERROR ENDLOOP};
FOR lss: LSs ← lssLt, lss.rest WHILE lss#NIL DO
tag ← CDRects.CreateRect[ [x: dp.spec.pinSize, y: lss.first.size], CMosB.met2];
loc ← [0, dp[row].layY.loc + lss.first.loc];
AddPObj[dp.wpo,  actWire, [tag, loc]];
AddPin[    actWire, [tag, loc]] ENDLOOP;
FOR lss: LSs ← lssRt, lss.rest WHILE lss#NIL DO
tag ← CDRects.CreateRect[ [x: dp.spec.pinSize, y: lss.first.size], CMosB.met2];
loc ← [dp.spec.cols*dp.spec.n*BitWidth[dp.spec]- CD.InterestSize[tag].x, dp[row].layY.loc + lss.first.loc];
AddPObj[dp.wpo, actWire, [tag, loc]];
AddPin[    actWire, [tag, loc]] ENDLOOP;
ENDLOOP;
ENDLOOP};
AddImplicitEndDecorations:   PROC[dp: DP.Form] = {
gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"];
vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"];
tag: CD.Object ← CDRects.CreateRect[ [x: dp.spec.pwrW, y: dp.spec.pinSize], CMosB.met];
row: INT ← 0;
IF dp.spec.gndBus<=0 THEN RETURN;
IF dp.spec.vddBus<=0 THEN ERROR;
DO
topPos: CD.Position ← [0, dp[row].layY.loc + dp[row].layY.size - CD.InterestSize[tag].y];
botPos: CD.Position ← [0, 0];
FOR col: INT IN [0..dp[row].size) DO
FOR bit: INT IN [0..dp.spec.n) DO
gndx: INT ← BitWidth[dp.spec]*(col*dp.spec.n+bit)
+ dp.spec.gndBus*dp.spec.layBusW + dp.spec.leftTail - CD.InterestSize[tag].x/2;
vddx: INT ← BitWidth[dp.spec]*(col*dp.spec.n+bit)
+ dp.spec.vddBus*dp.spec.layBusW + dp.spec.leftTail - CD.InterestSize[tag].x/2;
IF row+1=dp.size THEN {
topPos.x ← gndx; AddPObj[dp.wpo, gnd, [tag, topPos]]; AddPin[gnd, [tag, topPos]];
topPos.x ← vddx; AddPObj[dp.wpo, vdd, [tag, topPos]]; AddPin[vdd, [tag, topPos]]};
IF row=0 THEN {
botPos.x ← gndx; AddPObj[dp.wpo, gnd, [tag, botPos]]; AddPin[gnd, [tag, botPos]];
botPos.x ← vddx; AddPObj[dp.wpo, vdd, [tag, botPos]]; AddPin[vdd, [tag, botPos]]}
ENDLOOP ENDLOOP;
IF row = dp.size-1 THEN EXIT ELSE row ← dp.size-1 ENDLOOP};
Coordinate Utils
LSs:  TYPE = LIST OF LSRec;
LSRec: TYPE = RECORD[loc, size: INT];
slop:  INT ← CMosB.lambda/2;
BitWidth: PUBLIC PROC[spec: DP.DPSpec] RETURNS[bitWidth: INT] =
{RETURN[spec.layBusW*spec.buses + spec.layDWidth]};
BitPosX: PUBLIC PROC[spec: DP.DPSpec, col, bit: NAT] RETURNS[pos: INT] = {
xform:  CoreXform.Xform ← CoreXform.GenXform[(IF spec.interleave
THENLIST[[spec.cols, 1], [spec.n, 0]]
ELSELIST[[spec.cols, 0], [spec.n, 1]] )];
logical: INT ← col*spec.n + bit;
RETURN[BitWidth[spec] * CoreXform.XformIndex[xform, lr, logical].i ]};
SchBodyIR: PROC[dp: DP.Form] RETURNS[schIR: CD.Rect] = {
schIR ← [
x1:  dp[0][0].schIR.x1,
y1: dp[0][0].schIR.y1,
x2:  dp[dp.size-1][dp[0].size-1].schIR.x2,
y2: dp[dp.size-1][dp[0].size-1].schIR.y2]};
SchRowIR: PROC[dp: DP.Form, row: INT] RETURNS[schIR: CD.Rect] = {
schIR ← [
x1:  dp[row][0].schIR.x1,
y1: dp[row][0].schIR.y1,
x2:  dp[row][dp[0].size-1].schIR.x2,
y2: dp[row][dp[0].size-1].schIR.y2]};
GetLayoutCoordSides: PROC[dp: DP.Form, schIR: CD.Rect]
RETURNS[sides: DP.Sides] = {
externalIR: CD.Rect ← CD.InterestRect[CoreGeometry.GetObject[schDeco, dp.cell]];
sides[left] ← schIR.x1 < externalIR.x1 + slop;
sides[bottom] ← schIR.y1 < externalIR.y1 + slop;
sides[right] ← schIR.x2 > externalIR.x2 - slop;
sides[top]  ← schIR.y2 > externalIR.y2 - slop};
sides[right] ← schIR.x2=externalIR.x2-externalIR.x1;
sides[top]  ← schIR.y2=externalIR.y2-externalIR.y1};
GetLayoutHor: PROC[schIR: CD.Rect] RETURNS[hor: BOOL] = {
comp: Basics.Comparison ← Basics.CompareInt[schIR.x2-schIR.x1, schIR.y2-schIR.y1];
RETURN[SELECT comp FROM
less  => FALSE,
greater => TRUE,
ENDCASE => TRUE]}; -- little wire icon pins
GetLayoutCoord: PROC[dp: DP.Form, wire: DP.Wire, schIR: CD.Rect, initialLayYSize: BOOL]
RETURNS[lc: DP.LayoutCoord] = {
OPEN CDB: CDBasics;
lc.inBody   ← CDB.Intersect[schIR, CDB.Extend[SchBodyIR[dp], -slop-1]];
lc.sides   ← GetLayoutCoordSides[dp, schIR];
lc.hor    ← GetLayoutHor[schIR];
FOR row: NAT IN [0..dp.size) DO
notOutSideRow: BOOL ← CDB.Inside[schIR, CDB.Extend[SchRowIR[dp, row], -slop] ];
IF notOutSideRow AND dp[row].ch#NIL THEN
{lc.rowBot ← lc.rowTop ← row; lc.yBot ← lc.yTop ← dp.spec.initialYSize/2; RETURN[lc]};
FOR col: NAT IN [0..dp[row].size) DO
ENABLE DrawingError => {
TerminalIO.PutF["Drawing Error in row %g col %g\n", IO.int[row], IO.int[col]];
TerminalIO.PutF[" x1: %g y1: %g x2: %g y2: %g \n",
IO.int[schIR.x1], IO.int[schIR.y1], IO.int[schIR.x2], IO.int[schIR.y2]];
REJECT};
GetY: PROC[schy: INT] RETURNS[layy, size: INT, layer: CD.Layer] = {
Ck both layers/sides
layerCMosB.met2;
IF initialLayYSize OR dp[row].ch#NIL
THEN RETURN[dp.spec.initialYSize/2, dp.spec.met2W, CMosB.met2];
FOR sideIndex: INT IN [0..1] DO
side: DP.Side ← IF (sideIndex=0)=firstSideRight THEN right ELSE left;
incr: INT  ← IF side=right THEN -1 ELSE +1;
FOR cc: INT ← col, cc+incr WHILE cc IN [0..dp.spec.cols) DO
IF dp[row][cc].schInst=NIL THEN LOOP;
THROUGH [0..1] DO-- check both pol and met2
lss: LSs ← IconToLayoutGeoLocSizes[dp[row][cc], wire, schy, side, layer];
IF lss#NIL THEN RETURN[lss.first.loc+lss.first.size/2, lss.first.size, layer];
layer ← IF layer=CMosB.pol THEN CMosB.met2 ELSE CMosB.pol;
ENDLOOP ENDLOOP ENDLOOP; ERROR};
firstSideRight: BOOLFALSE;
slopGap: INTIF row>0 THEN dp[row].schIR.y1 - dp[row-1].schIR.y2 + slop ELSE slop;
leftEdge: INTIF col=0 THEN dp[row][col].schIR.x1 ELSE dp[row][col-1].schIR.x2;
SELECT TRUE FROM
CDB.Intersect[schIR, CDB.Extend[dp[row][col].schIR, -1]] => { }; -- doit
lc.inBody               => LOOP;
lc.sides[bottom] AND row = 0        => { }; -- doit
lc.sides[left]  AND col = 0        => { }; -- doit
lc.sides[top]  AND row = dp.size-1      => { }; -- doit
lc.sides[right]  AND col = dp[0].size-1     => { }; -- doit
ENDCASE               => LOOP;
IF lc.hor AND schIR.x1 <= dp[row][col].schIR.x1 OR
lc.hor AND schIR.x2 >= dp[row][col].schIR.x2 THEN firstSideRight ← TRUE;
IF schIR.x1 IN [leftEdge-slop..dp[row][col].schIR.x1+slop) THEN {
lc.colLt ← col;
lc.busLt ← 0};
IF schIR.x1 IN [dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN {
lc.colLt ← col;
lc.busLt ← SchHalfBus[dp.spec, schIR.x1-dp[row][col].schIR.x1]};
IF schIR.x2 IN (dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN {
lc.colRt ← col;
lc.busRt ← SchHalfBus[dp.spec, schIR.x2-dp[row][col].schIR.x1]};
IF schIR.x2 >= dp[row][col].schIR.x2-slop          THEN {
lc.colRt ← col;
lc.busRt ← sectionRtEdge};
IF schIR.y1 IN [dp[row].schIR.y1-slopGap..dp[row].schIR.y1+slop]  THEN {
lc.rowBot ← row;
lc.yBot ← 0};
IF schIR.y1 IN (dp[row].schIR.y1+slop..dp[row].schIR.y2-slop)    THEN {
lc.rowBot ← row;
[lc.yBot, lc.horSize, lc.horLayBot] ← GetY[schIR.y1-dp[row].schIR.y1]};
IF schIR.y2 IN (dp[row].schIR.y1+slop..dp[row].schIR.y2-slop)    THEN {
lc.rowTop ← row;
[lc.yTop, lc.horSize, lc.horLayTop] ← GetY[schIR.y2-dp[row].schIR.y1]};
IF schIR.y2 >= dp[row].schIR.y2-slop           THEN {
lc.rowTop ← row;
lc.yTop ← IF initialLayYSize THEN dp.spec.initialYSize ELSE dp[row].layY.size};
ENDLOOP;
ENDLOOP};
TrimLayoutCoord: PROC[dp: DP.Form, bigLC: DP.LayoutCoord, row, col: NAT]
RETURNS[lc: DP.LayoutCoord] = {
lc ← bigLC;
IF col  > bigLC.colLt THEN lc.busLt ← 0;
IF col  < bigLC.colRt THEN lc.busRt ← sectionRtEdge ;
IF row > bigLC.rowBot THEN lc.yBot ← 0;
IF row < bigLC.rowTop THEN lc.yTop ← dp[row].layY.size;
lc.rowTop ← lc.rowBot ← row;
lc.colLt ← lc.colRt  ← col };
IconToLayoutGeoLocSizes: PROC
[sec: DP.Section, actual: DP.Wire, schLoc: INT, side: DP.Side, layer: CD.Layer]
RETURNS[lss: LSs] = {
VisitBaseSeqCellBinding: PUBLIC PROC [base, seq: DP.Wire] = {
IF seq=iconPub THEN {bitCellPub ← base; RETURN};
FOR i: NAT IN [0 .. base.size) WHILE bitCellPub=NIL DO
VisitBaseSeqCellBinding[base[i], seq[i]] ENDLOOP};
iconPub:  DP.Wire  ← GetSchematicPublic[sec.schInst, actual, side, schLoc];
bitCellPub: DP.Wire;
bitCell:  DP.CellType ← sec.devCells[0];
IF iconPub=NIL  THEN Signal[];
VisitBaseSeqCellBinding[bitCell.public, sec.schInst.type.public];
IF bitCellPub=NILTHEN Signal[];
RETURN [GetGeometryLocSizes[bitCell, bitCellPub, side, layer]]};
GetSchematicPublic: PROC
[cellInst: DP.CellInstance, actual: DP.Wire, cSide: DP.Side, schY: INT]
RETURNS[schPub: DP.Wire ← NIL] = {
eachPair: CoreOps.EachWirePairProc ~ {
lss: LSs;
IF (actual # actualWire) THEN RETURN;
lss ← GetGeometryLocSizes[cellInst.type, publicWire, cSide];
FOR lss ← lss, lss.rest WHILE lss#NIL DO
IF schY-lss.first.loc IN [0..lss.first.size] THEN EXIT;
REPEAT FINISHED=>RETURN[subWires: FALSE]; ENDLOOP;
schPub ← publicWire; RETURN[quit: TRUE]};
[]𡤌oreOps.VisitBinding[cellInst.actual, cellInst.type.public, eachPair]};
GetGeometryLocSizes: PROC
[cell: DP.CellType, wire: DP.Wire, cSide: DP.Side, lay: CD.Layer ← CD.commentLayer]
RETURNS[lss: LSs ← NIL] = {
eachPin: CoreGeometry.EachPinProc = {
IF (layer # lay) OR (side # cSide) THEN RETURN;
lss ← CONS[LSRec[min, max-min], lss]};
decoration: CoreGeometry.Decoration ← IF lay=CD.commentLayer THEN schDeco ELSE layDeco;
IF wire=NIL THEN RETURN[NIL];
[]𡤌oreGeometry.EnumerateSides[decoration, cell, wire, eachPin]};
LocSize: PROC[inst: DP.CellInstance] RETURNS[loc, size: CD.Position] = {
obj: CD.Object       ← CoreGeometry.GetObject[schDeco, inst.type];
trans: CoreGeometry.Transformation ← CoreGeometry.GetTrans[schDeco, inst];
size ← CD.InterestSize[obj];
loc ← CDBasics.BaseOfRect[CDBasics.MapRect[CD.InterestRect[obj], trans]];
IF trans.orient # original THEN {
Signal[IO.PutFR["Schematic object (%g) has been rotated or flipped\n", IO.rope[CoreOps.GetCellTypeName[inst.type] ] ] ] }};
SchHalfBus: PUBLIC PROC[spec: DP.DPSpec, pos: INT] RETURNS[bus: INT] = {
RETURN[pos/(spec.schBusW/2)]};
Positioned Object Utils
AddPin: PROC [public: DP.Wire, po: DP.PObj] = {
pin: CoreGeometry.Instance ← [po.object, [po.position]];
CoreGeometry.AddPins[layDeco, public, LIST[pin]]};
ContPObj: PROC[spec: DP.DPSpec, bus, layY: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = {
po.object  ← CDSimpleRules.Contact[layRules, CMosB.met, layer];
po.position.x ← spec.leftTail + (bus-1)*spec.layBusW/2 - CD.InterestSize[po.object].x/2;
po.position.y ← layY - CD.InterestSize[po.object].x/2};
HorPObj: PROC[spec: DP.DPSpec, layY, lBus, rBus, size: INT, layer: CD.Layer]
RETURNS[po: DP.PObj] = {
fullW:  INT ← BitWidth[spec];
ltEdge:  BOOL ← lBus = 0;
rtEdge:  BOOL ← rBus = sectionRtEdge;
x1: INT ← IF ltEdge THEN 0  ELSE spec.leftTail + (lBus-1)*(spec.layBusW/2);
x2: INT ← IF rtEdge THEN fullW ELSE spec.leftTail + (rBus-1)*(spec.layBusW/2);
IF ~rtEdge AND (rBus MOD 2)=0 THEN Signal[];
IF x1 >= x2 THEN Signal[];
po.object  ← CDRects.CreateRect[ [x: x2-x1, y: size], layer];
po.position ← [x1, layY - size/2]};
VerPObj: PROC[spec: DP.DPSpec, layYbot, layYtop, bus: INT, size: INT]
RETURNS[po: DP.PObj] = {
IF layYbot >= layYtop THEN Signal[];
po.object  ← CDRects.CreateRect[ [x: size, y: layYtop-layYbot], CMosB.met];
po.position.x ← spec.leftTail + (bus-1)*spec.layBusW/2 - size/2;
po.position.y ← layYbot};
AddPObj: PROC[wpo: RefTab.Ref, wire: DP.Wire, po: DP.PObj] = {
pos: DP.PObjs ← NARROW[RefTab.Fetch[wpo, wire].val];
pos ← CONS[po, pos];
[] ← RefTab.Store[wpo, wire, pos]};
Assembly
AssembleObject: PROC[dp: DP.Form] RETURNS[cell: DP.Object] = {
IncludePins: RefTab.EachPairAction = {
pos: DP.PObjs ← NARROW[val];
name: DP.ROPE ← CoreRoute.LabelInternal[data.internal, NARROW[key]];
FOR pos ← pos, pos.rest WHILE pos#NIL DO
Include[pos.first.object, pos.first.position];
CDProperties.PutProp[insts.first, $SignalName, name] ENDLOOP};
Include: PROC[obj: CD.Object, loc: CD.Position] = {
IF obj=NIL THEN RETURN;
loc ← CDBasics.SubPoints[loc, CD.InterestBase[obj]];
insts ← CONS[ NEW[CD.InstanceRep ← [obj, [loc]]], insts]};
data: CoreClasses.RecordCellType ← NARROW[dp.cell.data];
name: DP.ROPE ← CoreOps.GetCellTypeName[dp.cell];
insts:  CD.InstanceList ← NIL;
FOR row: NAT IN [0..dp.size) DO
IF dp[row].ch#NIL THEN {
Include[dp[row].obj, [0, dp[row].layY.loc]]; LOOP};
FOR col: NAT IN [0..dp[row].size) DO
routing: CD.Object ← CreateRoutingObject[dp, row, col];
FOR bit: INT IN [0..dp.spec.n) DO
refPos: CD.Position ← [BitPosX[dp.spec, col, bit] + 0, dp[row].layY.loc];
IF routing#NIL THEN Include[obj: routing, loc: refPos];
IF dp[row][col].devCells#NIL THEN Include[
obj: PWCore.Layout[dp[row][col].devCells[bit]],
loc: [x: refPos.x+ dp[row][col].devBOff*dp.spec.layBusW, y: refPos.y]];
ENDLOOP;
ENDLOOP;
ENDLOOP;
[ ] ← RefTab.Pairs[dp.wpo, IncludePins];
cell ← PW.CreateCell[instances: insts, name: name.Cat[".mask"], ir: dp.layIR]};
CreateRoutingObject: PROC[dp: DP.Form, row, col: INT] RETURNS[obj: DP.Object] = {
data:  CoreClasses.RecordCellType ← NARROW[dp.cell.data];
nodes:  LIST OF CDRoutingObjects.Node;
action: RefTab.EachPairAction = {
name: IO.ROPE ← CoreRoute.LabelInternal[data.internal, NARROW[key]];
node: CDRoutingObjects.Node;
pos: DP.PObjs ← NARROW[val];
FOR ps: DP.PObjs ← pos, ps.rest WHILE ps#NIL DO ir ← CDBasics.Surround[ ir,
CDBasics.MoveRect[CD.InterestRect[ps.first.object], ps.first.position]] ENDLOOP;
node ← CDRoutingObjects.CreateNode[pos, LIST [[key: $SignalName, val: name]]];
nodes ← CONS[node, nodes]};
ir: CD.Rect ← [x1: 0, y1: 0, x2: 1, y2: 1]; -- need to begin at 0,0 for easy positioning of object
IF RefTab.GetSize[dp[row][col].wpo]=0 THEN RETURN[NIL];
[ ] ← RefTab.Pairs[dp[row][col].wpo, action];
obj ← CDRoutingObjects.CreateRoutingObject[nodes, ir]};
obj ← CDRoutingObjects.CreateRoutingObject
[nodes, [0, 0, (dp.spec.buses)*dp.spec.layBusW, dp[row].layY.size]]};
GetDeviceCellTypes: PROC[inst: DP.CellInstance]
RETURNS[cells: DP.CellTypeSeq] = {
cells ← NEW[DP.CellTypeSeqRec[GetSize[inst.type]]];
FOR i: NAT IN [0..cells.size) DO cells[i] ← GetChild[inst.type, i] ENDLOOP};
GetChild: PROC[cell: DP.CellType, bit: INT] RETURNS[child: DP.CellType] = {
WITH cell.data SELECT FROM
seq: CoreClasses.SequenceCellType => RETURN[seq.base];
rec: CoreClasses.RecordCellType => RETURN[rec[bit].type];
ENDCASE         => RETURN[GetChild[ CoreOps.Recast[cell], bit]]};
GetSize: PROC[cell: DP.CellType] RETURNS[size: INT] = {
WITH cell.data SELECT FROM
seq: CoreClasses.SequenceCellType => RETURN[seq.count];
rec: CoreClasses.RecordCellType => RETURN[rec.size];
ENDCASE         => RETURN[GetSize[ CoreOps.Recast[cell]]]};
Show DataPath
ShowDP: PUBLIC PROC[dp: DP.Form] = {
TerminalIO.PutF["Data Path Rows: %g\n", IO.rope[CoreOps.GetCellTypeName[dp.cell]]];
FOR row: NAT DECREASING IN [0..dp.size) DO
mux: BOOLFALSE;
name: DP.ROPENIL;
TerminalIO.PutF["%3g x1:%5g x2:%5g y1:%5g y2:%5g",
IO.int[row],
IO.int[dp[row].schIR.x1],
IO.int[dp[row].schIR.x2],
IO.int[dp[row].schIR.y1],
IO.int[dp[row].schIR.y2] ];
FOR col: INT IN [0..dp[row].size) DO
IF dp[row][col].schInst=NIL THEN LOOP;
mux ← IsMux[dp[row][col].schInst.type];
name ← CoreOps.GetCellTypeName[dp[row][col].schInst.type];
EXIT ENDLOOP;
SELECT TRUE FROM
dp[row].ch # NIL => TerminalIO.PutF[" \tChan\t\t"];
mux     => TerminalIO.PutF[" \tMux\t"];
ENDCASE    => TerminalIO.PutF[" \t\t\t"];
TerminalIO.PutF["%g\n", IO.rope[name]];
ENDLOOP};
IsMux: PROC[cell: DP.CellType] RETURNS[isMux: BOOL] =
{RETURN[PWCore.GetLayoutAtom[GetChild[cell, 0]]=$DataPathMux]};
CountTransistors: PUBLIC PROC[cell: DP.CellType] RETURNS[count: INT ← 0] = {
IF cell=NIL THEN RETURN[0];
SELECT cell.class FROM
CoreClasses.transistorCellClass => RETURN[1];
CoreClasses.sequenceCellClass  => {
data: CoreClasses.SequenceCellType ← NARROW[cell.data];
count ← data.count*CountTransistors[data.base]};
CoreClasses.recordCellClass  => {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
FOR child: NAT IN [0..data.size) DO
count ← count + CountTransistors[ data.instances[child].type ] ENDLOOP };
ENDCASE       => count ← CountTransistors[CoreOps.Recast[cell]] };
DataPath Spec Registration
RegisterDataPathSpec: PUBLIC PROC[key: IO.ROPE, spec: DP.DPSpec] =
{[] ← SymTab.Store[dpKeyTab, key, spec]};
NewCellTypeSpec: PUBLIC PROC[cellType: DP.CellType] RETURNS[spec: DP.DPSpec] = {
key: IO.ROPENARROW[CoreProperties.GetCellTypeProp[cellType, $DataPathKey]];
spec ← NEW[DP.DPSpecRec ← FetchDataPathSpecRec[key]]};
FetchDataPathSpecRec: PROC[key: IO.ROPE] RETURNS[spec: DP.DPSpecRec] = {
family: IO.ROPE  ← key.Substr[0, key.Index[0,"-"]];
busRp: IO.ROPE  ← key.Substr[key.Index[0,"-"]+1];
buses:  INT   ← Convert.IntFromRope[busRp];
sp:   DP.DPSpec ← NARROW[SymTab.Fetch[dpKeyTab, family].val];
spec      ← sp^;
spec.buses    ← buses;
IF spec.gndBus#-1 THEN spec.gndBus ← spec.gndBus+buses;
IF spec.vddBus#-1 THEN spec.vddBus ← spec.vddBus+buses};
Initialization
InitDataPathDP8: PROC =
{RegisterDataPathSpec["DP", NEW[DP.DPSpecRec ← [ ]]]};
InitDataPathDP8[];
[] ← PWCore.RegisterLayoutAtom[$DataPath, Layout];
END.