DPLayout.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Don Curry, November 16, 1987 6:10:33 pm PST
DIRECTORY Basics, CD, CDBasics, CDDirectory, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Core, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DP, RefTab, IO, PW, PWCore, Rope, Sisyph, TerminalIO;
DPLayout: CEDAR PROGRAM
IMPORTS Basics, CD, CDBasics, CDDirectory, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, CoreRoute, CoreXform, DP, RefTab, IO, PW, PWCore, Rope, Sisyph, TerminalIO
EXPORTS DP
SHARES CDRects =
BEGIN
Signal:   SIGNAL[msg: DP.ROPE ← NIL] = CODE;
DrawingError: SIGNAL = CODE;
schDeco:  PUBLIC CoreGeometry.Decoration ← Sisyph.mode.decoration;
layDeco:  PUBLIC CoreGeometry.Decoration ← PWCore.extractMode.decoration;
layRules:  ATOM ← $cmosB;
Layout: PWCore.LayoutProc ~ {
data:   CoreClasses.RecordCellType ← NARROW[cellType.data];
spec:   DP.DPSpec ← NARROW[CoreProperties.GetProp[cellType.properties, $DPSpec].value];
schIR:   CD.Rect ← [x1: LAST[INT], x2: FIRST[INT], y1: LAST[INT], y2: FIRST[INT]];
xIntervals: DP.Intervals ← NIL;
yIntervals: DP.Intervals ← NIL;
yIntervalsSB: DP.Intervals ← NIL;
colChans:  NAT ← spec.chans*DP.schChanW;
count:   NAT ← 0;
nofRows:  NAT ← 0;
nofCols:  NAT ← 0;
row:   NAT ← 0;
col:   NAT ← 0;
transistors: INT ← 0;
dp:   DP.DataPath ← NIL;
loc:   CD.Position;
size:   CD.Position;
Build Interval Lists
TerminalIO.PutF["Layout %g\n", IO.rope[CoreOps.GetCellTypeName[cellType]]];
FOR child: NAT IN [0..data.size) DO
count: INT ← CountTransistors[data.instances[child].type];
IF count=0 THEN {TerminalIO.PutF["Warning: Zero transistor celltype: %g\n",
IO.rope[CoreOps.GetCellTypeName[data.instances[child].type]]]};
transistorstransistors + count;
[loc, size] ← LocSize[data.instances[child]];
IF size.x=(spec.dChans*DP.schChanW)
THEN xIntervals ← InsertInterval[[loc.x-colChans, size.x+colChans], xIntervals]
ELSE xIntervals ← InsertInterval[[loc.x,    size.x],    xIntervals];
yIntervals   ← InsertInterval[[loc.y,    size.y],    yIntervals];
ENDLOOP;
TerminalIO.PutF[" %g transistors\n", IO.int[transistors]];
yIntervalsSB ← FindSBIntervals[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 ← yIntervalsSB, 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;
IF dp.spec.xforms = NIL THEN dp.spec.xforms ← LIST[[dp.spec.cols, 0], [dp.spec.n, 1]];
FOR row IN [0..dp.size) DO
sb: BOOL ← yIntervals=NIL OR yIntervalsSB#NIL AND yIntervalsSB.first.loc<yIntervals.first.loc;
dp[row] ← NEW[DP.ColSeqRec[nofCols]];
dp[row].schIR ← dp.schIR;
IF sb
THEN {
dp[row].sb  ← RefTab.Create[];
dp[row].schIR.y1 ← yIntervalsSB.first.loc;
dp[row].schIR.y2 ← yIntervalsSB.first.loc + yIntervalsSB.first.size;
yIntervalsSB  ← yIntervalsSB.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;
col ← col+1 ENDLOOP;
ENDLOOP;
ShowDP[dp];
Make Switchbox Layouts
AddSchematicGeometrySB[dp];
FOR row IN [0..dp.size) DO IF dp[row].sb#NIL THEN DP.BuildSB[dp, row] ENDLOOP;
Make Device Layouts
FOR child: NAT IN [0..data.size) DO
IF CountTransistors[data.instances[child].type]=0 THEN LOOP;
[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];
dp[row][col].devCells ← GetDeviceCellTypes[dp, data.instances[child]];
IF (SchHalfChan[loc.x - dp[row][col].schIR.x1] MOD 2) # 0 THEN Signal[];
dp[row][col].devCOff ← SchHalfChan[loc.x - dp[row][col].schIR.x1]/2;
dp[row].layY.size ← CDBasics.SizeOfRect[PWCore.InterestRect[dp[row][col].devCells[0]]].y
ENDLOOP;
InitRouting[dp];
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]*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
AddSchematicGeometry[dp];
AddGlobalRoutingInformation[dp];
obj ← dp.obj ← AssembleObject[dp];
TerminalIO.PutF["\nLayout %g\n", IO.rope[CoreOps.GetCellTypeName[cellType]]];
TerminalIO.PutF[" %g transistors\n", IO.int[transistors]];
ShowDP[dp];
TerminalIO.PutF["Layout Size (lambda) x: %g y: %g xy: %g\n",
IO.int[CD.InterestSize[obj].x/DP.lambda],
IO.int[CD.InterestSize[obj].y/DP.lambda],
IO.int[(CD.InterestSize[obj].x/DP.lambda)*(CD.InterestSize[obj].y/DP.lambda)] ]};
InitRouting: PROC[dp: DP.DataPath] = {
gnd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Gnd"];
vdd: DP.Wire = CoreOps.FindWire[dp.cell.public, "Vdd"];
FOR row: INT DECREASING IN [0..dp.size) DO
ytop: INT ← dp[row].layY.size;
FOR col: INT DECREASING IN [0..dp[row].size) DO
dp[row][col].wpo ← RefTab.Create[];
IF dp[row].sb#NIL THEN LOOP;
IF dp[row][col].schInst=NIL THEN {
AddPObj[dp[row][col].wpo, gnd, VerPObj[0, ytop, (dp.spec.chans+1)*2-1, DP.pwrW]];
AddPObj[dp[row][col].wpo, vdd, VerPObj[0, ytop, (dp.spec.chans+2)*2-1, DP.pwrW]]};
ENDLOOP ENDLOOP};
BitWidth: PUBLIC PROC[dp: DP.DataPath] RETURNS[bitWidth: INT] =
{RETURN[(dp.spec.chans+ dp.spec.dChans)*DP.layChanW]};
EachWireInst: TYPE = PROC[w: DP.Wire, geo: CoreGeometry.Instance];
EnumInternalSchematicGeometry: PROC[cell: DP.CellType, eachWireInst: EachWireInst] = {
data: CoreClasses.RecordCellType ← NARROW[cell.data];
EnumSchematicGeometry: CoreOps.EachWireProc ~ {
geometry: CoreGeometry.Instances ← CoreGeometry.GetGeometry[schDeco, wire];
IF geometry=NIL THEN RETURN[subWires: TRUE];
FOR geometry ← geometry, geometry.rest WHILE geometry#NIL DO
eachWireInst[wire, geometry.first] ENDLOOP;
RETURN[subWires: TRUE]};
[]𡤌oreOps.VisitWire[data.internal, EnumSchematicGeometry]};
FindSBIntervals: PROC[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) >= DP.schChanW/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;
IF CountTransistors[data.instances[child].type]#0 THEN LOOP;
[pos, size] ← LocSize[data.instances[child]];
CheckAndAdd[pos.y + size.y/2];
ENDLOOP;
EnumInternalSchematicGeometry[cell, eachWireInst]};
AddSchematicGeometrySB: PROC[dp: DP.DataPath] = {
eachWireInst: EachWireInst = {
instIR: CD.Rect ← CDBasics.MapRect[ CD.InterestRect[geo.obj], geo.trans];
lc:   DP.LayoutCoord ← GetLayoutCoord[dp, w, instIR, TRUE];
IF lc.hor OR lc.inBody THEN FOR row: NAT IN [lc.rowBot..lc.rowTop] DO
IF dp[row].sb#NIL THEN DP.AddSBNode[dp, row, w, lc]; ENDLOOP};
EnumInternalSchematicGeometry[dp.cell, eachWireInst]};
AddSchematicGeometry: PROC[dp: DP.DataPath] = {
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].sb#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.chanLt IN [1..dp.spec.chans*2) THEN
AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanLt, lc.yTop, lc.horLayTop]];
IF lc.chanRt IN [1..dp.spec.chans*2) THEN
AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanRt, lc.yTop, lc.horLayTop]];
AddPObj[dp[row][col].wpo, w,
HorPObj[lc.yTop, lc.chanLt, lc.chanRt, 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[lc.chanLt, lc.yBot, lc.horLayBot]];
IF lc.yTop IN (0..dp[row].layY.size) THEN
AddPObj[dp[row][col].wpo, w, ContPObj[lc.chanLt, lc.yTop, lc.horLayTop]];
AddPObj[dp[row][col].wpo, w,
VerPObj[lc.yBot, lc.yTop, lc.chanLt]]};
ENDLOOP;
ENDLOOP;
Add Public Pins
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];
xform:  CoreXform.Xform ← CoreXform.GenXform[dp.spec.xforms];
logical: INT ← bigLC.colLt*dp.spec.n + bit;
loc.y ← SELECT side FROM
bottom => 0,
top  => dp.layIR.y2 - CD.InterestSize[tag].y ENDCASE=>ERROR;
loc.x ← BitWidth[dp] * CoreXform.XformIndex[xform, lr, logical].i
+ DP.leftTail + (bigLC.chanLt-1)*DP.layChanW/2 - DP.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].sb#NIL
THENDP.GetSBY[dp[bigLC.rowBot].sb, kid].loc
ELSE bigLC.yBot;
IF dp[bigLC.rowBot].sb=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;
AddPObj[dp.wpo, kid, [tag, loc]];
AddPin[    kid, [tag, loc]];
ENDLOOP};
ENDLOOP } };
EnumInternalSchematicGeometry[dp.cell, eachWireInst]};
NextLeftIndexes: PROC[dp: DP.DataPath, col, bit: INT]
RETURNS[atEdge: BOOL, collt, bitlt: INT] = {
xform:  CoreXform.Xform ← CoreXform.GenXform[dp.spec.xforms];
addr:  CoreXform.Addr;
logical: INT ← col*dp.spec.cols + bit;
physical: INT ← CoreXform.XformIndex[xform, lr, logical].i;
IF (physical←physical-1)=-1 THEN RETURN[TRUE,0,0];
addr ← CoreXform.XformIndex[xform, rl, physical].a;
RETURN[FALSE, addr.first, addr.rest.first]};
collt, bitlt: NAT;
atEdge: BOOL;
[atEdge, collt, bitlt] ← NextLeftIndexes[dp, col, 1]; -- ???Bit????
IF atEdge THEN Signal[];
GetGlobalNames: PROC[dp: DP.DataPath] RETURNS[globals: LIST OF DP.ROPE] =
{globals ← LIST["Gnd", "Vdd", "Vbb"]};
AddGlobalRoutingInformation: PROC[dp: DP.DataPath] = {
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].sb#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: INT ← dp.spec.chans + (IF dp[row][refCol].schInst=NIL
THEN dp.spec.dChans
ELSE 0);
AddPObj[ dp[row][col].wpo, actualWire,
HorPObj[lss.first.loc+lss.first.size/2, 0, cWidth*2, lss.first.size, CMosB.met2] ];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
AddGlobalSideDecorations[dp];
AddGlobalEndDecorations[dp]};
tagVer: DP.Object ← CDRects.CreateRect[ [x: DP.metW, y: DP.pinSize], CMosB.met];
tagHor: DP.Object ← CDRects.CreateRect[ [x: DP.pinSize, y: DP.met2W], CMosB.met2];
AddGlobalSideDecorations: PROC[dp: DP.DataPath] = {
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].sb#NIL
THEN {
lss: LSRec;
IF NOT RefTab.Fetch[dp[row].sb, actWire].found THEN LOOP;
lss ← [loc: DP.GetSBY[dp[row].sb, actWire].loc - DP.met2W/2, size: DP.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.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.pinSize, y: lss.first.size], CMosB.met2];
loc ← [dp.spec.cols*dp.spec.n*BitWidth[dp]- CD.InterestSize[tag].x, dp[row].layY.loc + lss.first.loc];
AddPObj[dp.wpo, actWire, [tag, loc]];
AddPin[    actWire, [tag, loc]] ENDLOOP;
ENDLOOP;
ENDLOOP};
pwrSep: INT ← 1;
AddGlobalEndDecorations: PROC[dp: DP.DataPath] = {
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.pwrW, y: DP.pinSize], CMosB.met];
FOR row: INT ← 0, row+dp.size-1 WHILE row< dp.size 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: NAT IN [0..dp.spec.n) DO
gndx: INT ← BitWidth[dp]*(col*dp.spec.n+bit)
+ dp.spec.chans*DP.layChanW + DP.leftTail - CD.InterestSize[tag].x/2;
vddx: INT ← gndx + pwrSep*DP.layChanW;
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
ENDLOOP};
This can probably be made to work generally when the top/bot global position is unknown
AddGlobalEndDecorationsOld: PROC[dp: DP.DataPath] = {
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;
FOR row: INT ← 0, row+dp.size-1 WHILE row< dp.size DO
xform:   CoreXform.Xform ← CoreXform.GenXform[dp.spec.xforms];
FOR col: NAT IN [0..dp[row].size) DO
cell: DP.CellType ← dp[row][col].devCells[0];
wire: DP.Wire  ← CoreOps.FindWire[cell.public, globals.first];
act: DP.Wire  ← CoreOps.FindWire[dp[row][col].schInst.actual, globals.first];
FOR bit: NAT IN [0..dp.spec.n) DO
logical:  INT ← col*dp.spec.n + bit;
bitPosition: INT ← BitWidth[dp] * CoreXform.XformIndex[xform, lr, logical].i;
IF row=0 THEN {
lss: LSs ← GetGeometryLocSizes[cell, wire, bottom, CMosB.met];
FOR lss ← lss, lss.rest WHILE lss#NIL DO
tag ← CDRects.CreateRect[ [x: lss.first.size, y: DP.pinSize], CMosB.met];
loc ← [bitPosition + dp[row][col].devCOff*DP.layChanW + lss.first.loc, 0];
AddPObj[dp.wpo, act, [tag, loc]];
AddPin[    act, [tag, loc]] ENDLOOP};
IF row=dp.size-1 THEN {
lss: LSs  ← GetGeometryLocSizes[cell, wire, top, CMosB.met];
FOR lss ← lss, lss.rest WHILE lss#NIL DO
tag ← CDRects.CreateRect[ [x: lss.first.size, y: DP.pinSize], CMosB.met];
loc ← [bitPosition + dp[row][col].devCOff*DP.layChanW + lss.first.loc, 0];
loc.y ← dp[row-1].layY.loc + dp[dp.size-1].layY.size - tag.size.y;
AddPObj[dp.wpo, act, [tag, loc]];
AddPin[    act, [tag, loc]] ENDLOOP};
ENDLOOP;
ENDLOOP };
ENDLOOP;
ENDLOOP};
BitPosX: PUBLIC PROC[dp: DP.DataPath, col, bit: NAT] RETURNS[pos: INT] = {
xform:  CoreXform.Xform ← CoreXform.GenXform[dp.spec.xforms];
logical: INT ← col*dp.spec.n + bit;
RETURN[BitWidth[dp] * CoreXform.XformIndex[xform, lr, logical].i ]};
slop: INTDP.schChanW/4;
GetInBodyIR: PROC[dp: DP.DataPath, schIR: CD.Rect] RETURNS[BOOL] = {
schBodyIR: CD.Rect ← [
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];
RETURN[CDBasics.Intersect[schIR, CDBasics.Extend[schBodyIR, -1]]]};
GetLayoutCoordSides: PROC[dp: DP.DataPath, 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.DataPath, wire: DP.Wire, schIR: CD.Rect, initialLayYSize: BOOL]
RETURNS[lc: DP.LayoutCoord] = {
lc.inBody   ← GetInBodyIR[dp, schIR];
lc.sides   ← GetLayoutCoordSides[dp, schIR];
lc.hor    ← GetLayoutHor[schIR];
FOR row: NAT IN [0..dp.size) DO
FOR col: NAT IN [0..dp[row].size) DO
OPEN CDB: CDBasics;
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].sb#NIL
THEN RETURN[DP.initialYSize/2, DP.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;
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 [dp[row][col].schIR.x1-slop..dp[row][col].schIR.x1+slop) THEN {
lc.colLt ← col;
lc.chanLt ← 0};
IF schIR.x1 IN [dp[row][col].schIR.x1+slop..dp[row][col].schIR.x2-slop) THEN {
lc.colLt ← col;
lc.chanLt ← SchHalfChan[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.chanRt ← SchHalfChan[schIR.x2-dp[row][col].schIR.x1]};
IF schIR.x2 >= dp[row][col].schIR.x2-slop          THEN {
lc.colRt ← col;
lc.chanRt ← SchHalfChan[dp[row][col].schIR.x2-dp[row][col].schIR.x1]};
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.initialYSize ELSE dp[row].layY.size};
ENDLOOP;
ENDLOOP};
TrimLayoutCoord: PROC[dp: DP.DataPath, bigLC: DP.LayoutCoord, row, col: NAT]
RETURNS[lc: DP.LayoutCoord] = {
lc ← bigLC;
IF col  > bigLC.colLt THEN lc.chanLt ← 0;
IF col  < bigLC.colRt THEN lc.chanRt ← (dp.spec.chans+ dp.spec.dChans)*2;
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 };
AddPin: PROC [public: DP.Wire, po: DP.PObj] = {
pin: CoreGeometry.Instance ← [po.object, [po.position]];
CoreGeometry.AddPins[layDeco, public, LIST[pin]]};
IconToLayoutGeoLocSizes: PROC
[sec: DP.Section, actual: DP.Wire, schLoc: INT, side: DP.Side, layer: CD.Layer]
RETURNS[lss: LSs] = {
iconPub:  DP.Wire  ← GetSchematicPublic[sec.schInst, actual, side, schLoc];
bitCellPub: DP.Wire;
bitCell:  DP.CellType ← sec.devCells[0];
name:   DP.ROPE;
IF iconPub=NIL THEN DrawingError[];
name  ← CoreOps.GetShortWireName[iconPub];
IF name=NIL THEN name ← DP.GetCharCode[iconPub];
bitCellPub ← CoreCreate.FindWire[bitCell.public, name];
IF bitCellPub=NIL THEN 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]};
LSs:  TYPE = LIST OF LSRec;
LSRec: TYPE = RECORD[loc, size: INT];
GetGeometryLocSizes: PROC
[cell: DP.CellType, wire: DP.Wire, cSide: DP.Side, lay: CD.Layer ← CD.commentLayer]
RETURNS[lss: LSsNIL] = {
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]};
SchHalfChan: PUBLIC PROC[pos: INT] RETURNS[chan: INT] = {
RETURN[pos/(DP.schChanW/2)]};
ContPObj: PROC[chan, layY: INT, layer: CD.Layer] RETURNS[po: DP.PObj] = {
po.object  ← CDSimpleRules.Contact[layRules, CMosB.met, layer];
po.position.x ← DP.leftTail + (chan-1)*DP.layChanW/2 - DP.cnctSize/2;
po.position.y ← layY - DP.cnctSize/2};
HorPObj: PROC[layY, lChan, rChan, size: INT, layer: CD.Layer]
RETURNS[po: DP.PObj] = {
offSet:  INTDP.leftTail-DP.layChanW/2;
ltEdge: BOOL ← lChan   = 0;
rtEdge: BOOL ← rChan MOD 2 = 0;
x1: INT ← DP.leftTail + (lChan-1) * DP.layChanW/2 - (IF ltEdge THEN offSet ELSE 0);
x2: INT ← DP.leftTail + (rChan-1) * DP.layChanW/2 - (IF rtEdge THEN offSet ELSE 0);
IF x1 >= x2 THEN Signal[];
po.object  ← CDRects.CreateRect[ [x: x2-x1, y: size], layer];
po.position ← [x1, layY - size/2]};
VerPObj: PROC[layYbot, layYtop, chan: INT, size: INT ← DP.metW] RETURNS[po: DP.PObj] = {
IF layYbot >= layYtop THEN Signal[];
po.object  ← CDRects.CreateRect[ [x: size, y: layYtop-layYbot], CMosB.met];
po.position.x ← DP.leftTail + (chan-1)*DP.layChanW/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]};
AssembleObject: PROC[dp: DP.DataPath] 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] = {
loc ← CDBasics.SubPoints[loc, CD.InterestBase[obj]]; -- for sb and mux offsets
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;
xform:  CoreXform.Xform ← CoreXform.GenXform[dp.spec.xforms];
FOR row: NAT IN [0..dp.size) DO
IF dp[row].sb#NIL THEN {
Include[dp[row].obj, [0, dp[row].layY.loc]]; LOOP};
FOR col: NAT IN [0..dp[row].size) DO
routing: DP.Object ← CreateRoutingObject[dp, row, col, 0];
FOR bit: NAT IN [0..dp.spec.n) DO
refPos: CD.Position ← [BitPosX[dp, col, bit] + 0, dp[row].layY.loc];
IF routing#NIL THEN Include[ obj: routing, loc: refPos ];
IF dp[row][col].schInst=NIL THEN LOOP;
IF IsMux[dp[row][col].schInst.type]
THEN {
obj: CD.Object ← PWCore.Layout[dp[row][col].devCells[bit]];
new: CD.Object ← CDDirectory.Expand1[obj].new;
IF new=NIL THEN ERROR;
Include[obj: new, loc: [x: refPos.x, y: refPos.y ]]}
ELSE Include[
obj: PWCore.Layout[dp[row][col].devCells[bit]],
loc: [x: refPos.x+ dp[row][col].devCOff*DP.layChanW, 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.DataPath, row, col, bit: INT, names: BOOLFALSE]
RETURNS[obj: DP.Object] = {
ir: CD.Rect;
max: CD.Position ← [(dp.spec.chans)*DP.layChanW, dp[row].layY.size];
action: RefTab.EachPairAction = {
FOR pos: DP.PObjs ← GetPObjs[val, bit], pos.rest WHILE pos#NIL DO
-- min ← CDBasics.MinPoint[min, pos.first.position];
max ← CDBasics.MaxPoint
[max, CDBasics.AddPoints[pos.first.position, CD.InterestSize[pos.first.object]]];
insts ← CONS[ NEW[CD.InstanceRep ←
[pos.first.object, [pos.first.position]]], insts] ENDLOOP};
insts: CD.InstanceList ← NIL;
IF RefTab.GetSize[dp[row][col].wpo]=0 THEN RETURN[NIL];
[ ] ← RefTab.Pairs[dp[row][col].wpo, action];
ir ← CDBasics.RectAt[[0, 0], max];
obj ← PW.CreateCell[instances: insts, name: NIL, ir: ir]};
CreateRoutingObject: PROC[dp: DP.DataPath, row, col, bit: 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 ← GetPObjs[val, bit];
node ← CDRoutingObjects.CreateNode[pos, LIST [[key: $SignalName, val: name]]];
nodes ← CONS[node, nodes]};
IF RefTab.GetSize[dp[row][col].wpo]=0 THEN RETURN[NIL];
[ ] ← RefTab.Pairs[dp[row][col].wpo, action];
obj ← CDRoutingObjects.CreateRoutingObject[nodes, [0, 0, (dp.spec.chans)*DP.layChanW, dp[row].layY.size]]};
GetPObjs: PROC[value: REF, bit: INT] RETURNS[pos: DP.PObjs] = {
WITH value SELECT FROM
lopobjs: DP.PObjs  => RETURN[lopobjs];
pobjseq: DP.PObjSeq => RETURN[pobjseq[bit]];
ENDCASE     => ERROR};
GetDeviceCellTypes: PROC[dp: DP.DataPath, inst: DP.CellInstance]
RETURNS[cells: DP.CellTypeSeq] = {
IF IsMux[inst.type] THEN RETURN[DP.GetMuxCellTypes[dp, inst]];
cells ← NEW[DP.CellTypeSeqRec[dp.spec.n]];
FOR i: NAT IN [0..cells.size) DO cells[i] ← GetChild[inst.type, i] ENDLOOP};
IsMux: PROC[cell: DP.CellType] RETURNS[isMux: BOOL] = {
rec: CoreClasses.RecordCellType;
name: DP.ROPE ← CoreOps.GetCellTypeName[cell];
IF NOT ISTYPE[cell.data, CoreClasses.RecordCellType] THEN RETURN[FALSE];
IF name.Substr[MAX[0, name.Length-3], 3].Equal["Mux", FALSE] THEN RETURN[TRUE];
rec ← NARROW[cell.data];
RETURN[CoreOps.GetCellTypeName[rec[0].type].Equal["DP.DPMuxSwitch.icon"]]};
GetChild: PROC[cell: DP.CellType, bit: INT ← -1] RETURNS[child: DP.CellType] = {
IF bit<0 THEN RETURN[cell]; -- -1 means no bitwise replication hierarchy
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]]};
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] ] ] ] }};
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};
ShowDP: PUBLIC PROC[dp: DP.DataPath] = {
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.spec.cols) 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].sb # NIL => TerminalIO.PutF[" \tSB\t\t"];
mux     => TerminalIO.PutF[" \tMux\t"];
ENDCASE    => TerminalIO.PutF[" \t\t\t"];
TerminalIO.PutF["%g\n", IO.rope[name]];
ENDLOOP};
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]] };
Decorate: PWCore.DecorateProc ~ { };
Use rectangles on border to apply names and specify sides. (extentions, not overlayed).
[] ← PWCore.RegisterLayoutAtom[$DP, Layout, Decorate];
END.