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]]]};
transistors ← transistors + 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: INT ← IF 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:
INT ←
IF dp[bigLC.rowBot].sb#
NIL
THEN DP.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: INT ← DP.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
layer ← CMosB.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: BOOL ← FALSE;
slopGap: INT ← IF 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: 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]};
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: INT ← DP.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: BOOL ← FALSE]
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: BOOL ← FALSE;
name: DP.ROPE ← NIL;
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.