DPLayout.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Don Curry, May 1, 1987 11:47:40 am PDT
DIRECTORY Basics, CD, CDBasics, CDDirectory, CDProperties, CDRects, CDRoutingObjects, CDSimpleRules, CMosB, Core, CoreClasses, CoreCreate, CoreGeometry, CoreOps, CoreProperties, 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, 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 ← CoreOps.GetFullWireName[dp.cell.public, 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]};
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] = {
nodes:  LIST OF CDRoutingObjects.Node;
action: RefTab.EachPairAction = {
node: CDRoutingObjects.Node;
pos: DP.PObjs ← GetPObjs[val, bit];
node ← CDRoutingObjects.CreateNode[pos];
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.