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.