CoreGlueImpl:
CEDAR
PROGRAM
IMPORTS CardTable, CCDUtils, CD, CDCells, CDRects, CDSimpleRules, CDSymbolicObjects, Convert, CoreBlock, CoreFrame, CoreGlue, CoreLibrary, CoreName, CoreOps, HashTable, IFUCoreData, IO, PW, PWRoute, Rope, Route
EXPORTS CoreGlue =
BEGIN OPEN CCD: CCDUtils;
ROPE: TYPE = Core.ROPE;
GlueClass: TYPE = CoreGlue.GlueClass;
GlueSideType: TYPE = CoreGlue.GlueSideType;
Glue: TYPE = CoreGlue.Glue;
GlueSpec: TYPE = CoreGlue.GlueSpec;
Node: TYPE = CoreGlue.Node;
NodeRec: TYPE = CoreGlue.NodeRec;
CellType: TYPE = Core.CellType;
Frame: TYPE = CoreFrame.Frame;
FrameRec: TYPE = CoreFrame.FrameRec;
FrameSeq: TYPE = CoreFrame.FrameSeq;
Side: TYPE = CoreFrame.Side;
Status: TYPE = CoreGlue.Status;
Ph: TYPE = CoreName.Ph;
NWMML: TYPE = CCD.NWMML;
FCT: PROC[ct: CellType] RETURNS[Frame] = {RETURN[CoreFrame.FCT[ct]]};
StatusRope:
ARRAY Status
OF
ROPE
= ["rejustify", "progress", "delayed", "complete1", "complete2"];
glueCellClass:
PUBLIC Core.CellClass ←
CoreOps.SetClassPrintProc[
NEW[Core.CellClassRec ← [name: "CoreGlue", recast: NIL]],
ClassPrintProc];
ClassPrintProc: CoreOps.PrintClassProc = {
glueData: Glue ← NARROW[data];
IO.PutRope[out, "\nGlue: "];
GlueDescription[glueData, out]};
GlueSideTypeRp:
ARRAY GlueSideType
OF
ROPE = [
cap: CoreName.RopeNm["cap"],
conn: CoreName.RopeNm["conn"],
pwr: CoreName.RopeNm["pwr"],
ext: CoreName.RopeNm["ext"],
chan: CoreName.RopeNm["chan"],
sum: CoreName.RopeNm["sum"],
diff: CoreName.RopeNm["diff"] ];
GlueClassRp:
ARRAY GlueClass
OF
ROPE = [
fill: CoreName.RopeNm["Fill-"],
ext: CoreName.RopeNm["Ext-"],
xlt : CoreName.RopeNm["Xlt-"],
chan: CoreName.RopeNm["Chan-"],
pwr: CoreName.RopeNm["Pwr-"],
sb : CoreName.RopeNm["SBox-"],
bad: CoreName.RopeNm["Bad-"] ];
GlueDescription:
PROC[glue: Glue, out:
IO.
STREAM] = {
out.PutF[" Subclass: %g b:%g l:%g t:%g r:%g ",
IO.rope[ glue.subClass ],
IO.rope[ GlueSideTypeRp[ glue.type[bottom] ] ],
IO.rope[ GlueSideTypeRp[ glue.type[left] ]] ,
IO.rope[ GlueSideTypeRp[ glue.type[top] ] ],
IO.rope[ GlueSideTypeRp[ glue.type[right] ] ] ] };
defaultOptimization: PWRoute.Optimization ← full;
CellProc:
PUBLIC
PROC[
subClass: ROPE ← NIL,
name: ROPE ← NIL,
l,r,b,t: GlueSideType ← cap, -- cap conn ext chan sum diff
bCell,rCell,tCell,lCell: Core.CellType ← NIL,
tDir: PWRoute.HorV ← vertical, -- vertical horizontal
tLayer: ROPE ← NIL, -- metal metal2 poly
bLayer: ROPE ← NIL,
xlate: BOOL ← FALSE,
data:
REF ←
NIL ]
--
metal2 poly metal
RETURNS [cellType: CellType] = {
glue:
REF GlueSpec ←
NEW[GlueSpec ← [
subClass: CoreName.RopeNm[subClass],
tDir: tDir,
type: [b,r,t,l],
cell: [bCell,rCell,tCell,lCell],
data: data,
params:
NEW[PWRoute.RouterParamsRec ← [
opt: defaultOptimization,
trunkLayer: tLayer,
branchLayer: bLayer]]]];
met: ROPE ← CoreName.RopeNm["metal"];
met2: ROPE ← CoreName.RopeNm["metal2"];
tLayer ← CoreName.RopeNm[tLayer];
bLayer ← CoreName.RopeNm[bLayer];
SetGlueClass[glue];
glue.params.trunkLayer ← tLayer ←
SELECT tLayer
FROM
NIL =>
SELECT bLayer
FROM
NIL => IF tDir=horizontal THEN met ELSE met2,
met => met2,
met2 => met,
ENDCASE => ERROR,
ENDCASE => tLayer;
glue.params.branchLayer ← bLayer ←
SELECT bLayer
FROM
NIL =>
SELECT tLayer
FROM
met => met2,
met2 => met,
ENDCASE => ERROR,
ENDCASE => bLayer;
IF xlate THEN IF glue.class#ext THEN Signal[] ELSE glue.class ← xlt;
IF name=NIL OR name.Length[]=0 THEN name ← CoreName.ID[ GlueClassRp[glue.class] ];
cellType ← CoreOps.SetCellTypeName[
NEW [ Core.CellTypeRec ← [
class: glueCellClass,
public: CoreOps.CreateWires[0],
data: glue] ],
name];
CoreFrame.SetFrameExpandProc[hard, cellType, NEW[CoreFrame.ExpandProc ← ExpandHard] ];
CoreFrame.SetFrameExpandProc[soft, cellType, NEW[CoreFrame.ExpandProc ← ExpandSoft] ]};
ExpandSoft: CoreFrame.ExpandProc = {
frameCT.data ← NEW[FrameRec ← [data: frameCT.data, seq: NEW[FrameSeq[0]] ]];
frameCT.class ← CoreFrame.frameCellClass;
CoreFrame.SetFrameExpandProc[soft, frameCT, NIL]};
ExpandHard: CoreFrame.ExpandProc = {
frameCT.data ← NEW[FrameRec ← [data: frameCT.data, seq: NEW[FrameSeq[0]] ]];
frameCT.class ← CoreFrame.frameCellClass;
CoreFrame.SetFrameExpandProc[hard, frameCT, NIL]};
SetGlueClass:
PROC[glue: Glue] = {
OPEN glue;
Type: PROC[side: CoreFrame.Side]
RETURNS[GlueSideType] = {
SELECT type[side]
FROM
pwr => RETURN[conn];
sum, diff => RETURN[chan];
ENDCASE => RETURN[type[side]]};
eqS: BOOL ← (Type[left] = Type[right]) OR (Type[top] = Type[bottom]);
cnt: ARRAY GlueSideType OF INT ← ALL[0];
FOR side: CoreFrame.Side
IN CoreFrame.Side
DO
cnt[type[side]] ← cnt[type[side]] +1;
IF type[side]=ext
AND type[CoreFrame.OppSide[side]]#conn
THEN {class ← bad; Signal[]; RETURN} ENDLOOP;
IF cnt[pwr]>1 THEN {class ← bad; Signal[]; RETURN};
SELECT
(((cnt[conn]+cnt[pwr]) *10 +
cnt[ext]) *10 +
cnt[cap]) *10 +
cnt[chan] + cnt[sum] + cnt[diff] FROM
4000 => {class ← sb};
3100 => {class ← sb};
3010 => {class ← sb};
2200 => {class ← IF eqS THEN bad ELSE sb};
2110 => {class ← IF eqS THEN bad ELSE sb};
2020 => {class ← IF ~eqS THEN sb ELSE chan};
2011 => {class ← IF ~eqS THEN bad ELSE chan};
2002 => {class ← IF ~eqS THEN bad ELSE chan};
1120 => {class ← IF ~eqS THEN bad ELSE ext};
1111 => {class ← chan};
1102 => {class ← IF ~eqS THEN bad ELSE chan};
1021 => {class ← IF eqS THEN bad ELSE chan};
1012 => {class ← IF ~eqS THEN bad ELSE chan};
0040 => {class ← fill};
0022 => {class ← IF ~eqS THEN bad ELSE chan}; -- pass through gap
ENDCASE => {class ← bad};
IF class=chan
THEN
{
IF Type[left]=conn
OR Type[right]=conn
OR
Type[top]=chan OR Type[bottom]=chan THEN tDir←vertical ELSE tDir←horizontal;
IF cnt[chan]+cnt[sum]+cnt[diff]=0
THEN {IF (tDir=vertical) = (type[left] = cap AND type[right] = cap) THEN Signal[]}
ELSE {IF (tDir=vertical) = (Type[left] = chan OR Type[right] = chan) THEN Signal[]}};
IF class=chan AND cnt[pwr]#0 THEN class←pwr;
IF class=bad THEN Signal[]};
CheckExpandedFrame:
PROC[frameCT: CellType] = {
checkProc: CoreFrame.EnumProc = {
frame: Frame ← FCT[fCT];
name: ROPE ← CoreName.CellNm[fCT].n;
IF frame.seq.size#0 THEN RETURN;
IF frame.cell#NIL THEN RETURN;
IF frame.data=NIL THEN {Signal[]; RETURN};
IF NOT ISTYPE [frame.data, Glue] THEN Signal[];
IF frame.size.x<1 OR frame.size.y<1 THEN Signal[]};
[ ] ← CoreFrame.EnumFrame[frameCT, checkProc]};
Instantiate:
PROC[frameCT: CellType]
RETURNS[status: Status] = {
frame: Frame ← FCT[frameCT];
name: ROPE ← CoreName.CellNm[frameCT].n;
IF frame.cell#NIL THEN RETURN[complete2];
IF frame.data#NIL AND frame.seq.size#0 THEN {Signal[]; frame.data ← NIL};
IF frame.seq.size=0
THEN {
IF frame.data = NIL THEN {Signal[]; RETURN[complete2]};
status ← InstantiateGlue[frameCT];
IF status=complete2 THEN ERROR;
RETURN[status]};
status ← complete2;
FOR kid:
INT
IN [0..frame.seq.size)
WHILE status#rejustify
DO
stat: Status ← Instantiate[frame.seq[kid]];
status ← MIN[status, stat];
ENDLOOP;
IF status=complete2
THEN {
log.PutF["\n Completed: %g %g", IO.rope[name], IO.time[]];
[ ] ← CoreFrame.RecastFrameHard[frameCT];
IF CoreFrame.IsFrameCheckPoint[framCT] THEN {
frame: CoreFrame.Frame ← CoreFrame.FCT[frameCT];
CoreFrame.WriteFrameCheckPoint[frameCT];
frame.seq ← NEW[CoreFrame.FrameSeq[0]];
frame.data ← NIL;
CoreFrame.ReadFrameCheckPoint[frameCT, shallow]};
RETURN[progress]} };
InstantiateGlue:
PROC[frameCT: CellType]
RETURNS[status: Status] = {
frame: Frame ← FCT[frameCT];
name: ROPE ← CoreName.CellNm[frameCT].n;
glue: Glue ← NARROW[frame.data];
status ← complete1;
FOR side: Side
IN Side
DO
SELECT glue.type[side]
FROM
chan => {IF glue.cell[side]=NIL THEN Signal[]; LOOP};
sum => LOOP;
diff => LOOP;
cap => LOOP;
ext => {
IF glue.cell[side]#NIL THEN LOOP;
IF glue.cell[CoreFrame.OppSide[side]]#
NIL
THEN {
IF glue.class=xlt THEN LOOP;
glue.cell[side] ←
IF side=left
OR side=right
THEN CoreFrame.RotateCellType
[ glue.cell[CoreFrame.OppSide[side]], CDOrient.mirrorX]
ELSE CoreFrame.RotateCellType
[ glue.cell[CoreFrame.OppSide[side]], CDOrient.mirrorY];
status ← MIN[status, progress]}
ELSE {
log.PutF["\n Glue %g %g side waiting on %g side.",
IO.rope[name],
IO.rope[CoreFrame.SideRope[side]],
IO.rope[CoreFrame.SideRope[CoreFrame.OppSide[side]]]];
status ← MIN[status, delayed]};
LOOP};
conn, pwr => {
neighborCT: CellType;
found: BOOL;
IF glue.cell[side]#NIL THEN LOOP;
[neighborCT, found] ← CoreFrame.Neighbor[frameCT, side];
IF ~found
THEN {status ← MIN[status, delayed]; Signal[]} -- Drop To printout
ELSE {
neighbor: Frame ← FCT[neighborCT];
IF neighbor.cell#
NIL
THEN {
glue.cell[side] ← neighbor.cell;
status ← MIN[status, progress];
LOOP};
IF neighbor.data#
NIL
THEN
WITH neighbor.data
SELECT
FROM
--
ELSE Drop
neighborGlue: Glue => {
IF neighborGlue.type[CoreFrame.OppSide[side]]=ext
AND neighborGlue.cell[side]#
NIL
AND neighborGlue.class#xlt
AND neighborGlue.class#pwr
THEN {
glue.cell[side] ← neighborGlue.cell[side];
status ← MIN[status, progress];
LOOP} };
ELSE Drop To printout
ENDCASE => {Signal[]; LOOP} };
log.PutF["\n Glue %g can not yet%guse %g as %g %g.",
IO.rope[name],
IO.rope[IF found THEN " " ELSE " (never?) "],
IO.rope[IF neighborCT=NIL THEN "???" ELSE CoreName.CellNm[neighborCT].n],
IO.rope[CoreFrame.SideRope[side]],
IO.rope[IF glue.type[side]=conn THEN "conn" ELSE "pwr"]];
status ← MIN[status, delayed]; LOOP};
ENDCASE => ERROR ENDLOOP;
IF status < complete1 THEN RETURN[status];
status ← GlueIt[frameCT]};
GlueIt:
PROC[frameCT: CellType]
RETURNS[status: Status] = {
frame: Frame ← FCT[frameCT];
name: ROPE ← CoreName.CellNm[frameCT].n;
msg: IO.ROPE;
initSize: CD.Position ← [frame.size.x, frame.size.y];
cell: CellType;
glue: Glue ← NARROW[frame.data];
channels: INT ← IF glue.data=NIL THEN 6 ELSE NARROW[glue.data, REF INT]^;
pwrSide: Side;
variable: BOOL ← MAX[frame.size.xfree, frame.size.yfree]#fixed;
variable ← MAX[frame.size.xfree, frame.size.yfree]#fixed;
IF variable AND glue.class IN [fill..xlt] THEN RETURN[complete1];
IF glue.class=chan
AND ((
FCT[frame.father].first=top
OR
FCT[frame.father].first=bottom) = (glue.tDir=vertical))
THEN Signal[];
AdjustLayerAssignments[glue];
SELECT glue.class
FROM
fill => cell ← FCT[CCD.BlankCell[initSize]].cell;
ext, xlt => {
cell ←
SELECT
TRUE
FROM
glue.type[top] = ext => FillerCell [glue, top, initSize.y],
glue.type[bottom] = ext => FillerCell [glue, bottom, initSize.y],
glue.type[left] = ext => FillerCell [glue, left, initSize.x],
glue.type[right] = ext => FillerCell [glue, right, initSize.x],
ENDCASE => ERROR};
chan, pwr, sb => {
ENABLE {
Route.Signal => {log.PutF["\n Route Signal: %g", IO.rope[explanation]]; RESUME};
Route.Error => {log.PutF["\n Route ERROR: %g",
IO.rope[explanation]];
cell ← FCT[CCD.BlankCell[initSize]].cell; CONTINUE}};
pwrCell: CellType ← NIL;
routeType: PWRoute.RouteType ← IF glue.class=sb THEN switchBox ELSE channel;
sizeSpec:
REF
CD.Rect ←
NEW[
CD.Rect ←
[0, 0, CoreFrame.minSize.x, CoreFrame.minSize.y]];
IF glue.class=pwr
THEN {
OPEN glue;
width: INT;
SELECT
TRUE
FROM
type[bottom] = pwr => {pwrSide ← bottom; width ← sizeSpec.y2};
type[top] = pwr => {pwrSide ← top; width ← sizeSpec.y2};
type[left] = pwr => {pwrSide ← left; width ← sizeSpec.x2};
type[right] = pwr => {pwrSide ← right; width ← sizeSpec.x2};
ENDCASE => ERROR;
pwrCell ← MergePwr [glue, pwrSide, width]};
IF
NOT variable
THEN {
sizeSpec.x2 ← initSize.x; sizeSpec.y2 ← initSize.y;
IF pwrCell#
NIL
THEN
IF glue.tDir=horizontal
THEN sizeSpec.y2 ←
MAX[0, sizeSpec.y2 - CCD.CellSize[pwrCell].y]
ELSE sizeSpec.x2 ←
MAX[0, sizeSpec.x2 - CCD.CellSize[pwrCell].x] };
IF glue.class=pwr THEN glue.cell[pwrSide] ← pwrCell;
IF glue.subClass = CoreName.RopeNm["ThreeLevel"]
THEN cell ← ThreeLevel [glue, channels]
ELSE cell ← MakeChannel [glue, name, sizeSpec, routeType];
IF glue.class=pwr
THEN cell ← CoreBlock.AbutCellList[
name: NIL,
first: CoreFrame.SideSides[pwrSide],
cellTypes: LIST[pwrCell, cell] ] };
ENDCASE => Signal[];
frame.cell ← cell;
msg ←
IO.PutFR["\n Routed %g %g Frame: %g",
IO.rope[
IF ~variable
THEN "fixed"
ELSE
IF (glue.class=chan
OR glue.class=pwr)
THEN "firm" ELSE "variable"],
IO.rope[GlueClassRp[glue.class]],
IO.rope[name] ];
log.PutRope[msg]; PW.WriteF[msg]; PW.WriteF["\n"];
frame.size ← CoreFrame.FixedSize[CCD.CellSize[cell]];
IF variable
AND (glue.class=chan
OR glue.class=pwr)
THEN {
IF glue.tDir=vertical
THEN {IF frame.size.y # initSize.y THEN Signal[]; frame.size.xfree ← tame}
ELSE {IF frame.size.x # initSize.x THEN Signal[]; frame.size.yfree ← tame};
RETURN[rejustify]}
ELSE {
IF initSize # [frame.size.x, frame.size.y] THEN Signal[];
RETURN[progress] } };
CellBad:
PROC[obj:
CD.Object]
RETURNS[bad:
BOOL] = {
bad ← obj=NIL OR obj.specificRef=NIL;
IF
NOT bad
THEN
WITH obj.specificRef
SELECT
FROM
cellPtr: CD.CellPtr => bad ← cellPtr.contents=NIL;
list: LIST OF CD.Object => bad ← list=NIL; -- redundant
ENDCASE => bad ← TRUE;
RETURN[bad OR CD.InterestSize[obj].x<1 OR CD.InterestSize[obj].y<1]};
ChanSideCell:
PUBLIC
PROC
[side: Side, list: LIST OF ROPE, layer: CD.Layer] RETURNS[cell: CellType] = {
object: CD.Object;
nwmmls: LIST OF NWMML;
FOR list ← list, list.rest
WHILE list#
NIL
DO
name: ROPE ← Rope.Substr[list.first, 0, Rope.Index[list.first, 0, "/"]];
size:
INT ←
IF list.first.Length[] > name.Length[]
THEN Convert.IntFromRope[Rope.Substr[list.first, Rope.Index[list.first, 0, "/"]+1]]
ELSE 4;
nwmmls ←
CONS[[
name: CoreName.RopeNm[name],
min: CCD.lambda, -- move away from beginning edge
max: size*CCD.lambda],
nwmmls]
ENDLOOP;
object ← SideObject[side, nwmmls, layer];
cell ← CoreLibrary.ObjCell[object, CoreName.ID["ChanSide"]]};
SideObject:
PUBLIC
PROC
[side: Side, list: LIST OF NWMML, layer: CD.Layer, length: INT ← 0] -- max => size
RETURNS[cell: CD.Object] = {
dim: INT ← CD.FetchTechnology[$cmosB].lambda;
pos: CD.Position ← [0, 0];
size: CD.Position ← [0, 0];
cell ← CDCells.CreateEmptyCell[];
FOR list ← list, list.rest
WHILE list#
NIL
DO
pinApl: CD.Instance;
size ←
SELECT side
FROM
top, bottom => [list.first.max, dim]
ENDCASE => [dim, list.first.max];
SELECT side
FROM
top, bottom => pos.x ← MAX[pos.x, list.first.min];
ENDCASE => pos.y ← MAX[pos.y, list.first.min];
[ ] ← PW.IncludeInCell[cell, CDRects.CreateRect[size, layer], pos];
pinApl ← PW.IncludeInCell[cell, CDSymbolicObjects.CreatePin[size], pos];
CDSymbolicObjects.SetName[pinApl, list.first.name];
CDSymbolicObjects.SetLayer[pinApl, layer];
SELECT side
FROM
top, bottom =>
{length ← MAX[length, pos.x ← pos.x+list.first.max]; pos.x←pos.x+dim*4};
ENDCASE =>
{length ← MAX[length, pos.y ← pos.y+list.first.max]; pos.y←pos.y+dim*4};
ENDLOOP;
CDCells.SetInterestRect[cell,
SELECT side
FROM
left => [-dim, 0, +dim, length ],
bottom => [0, -dim, length, +dim ],
right => [0, 0, 2*dim, length ],
top => [0, 0, length, 2*dim ],
ENDCASE => ERROR ];
[ ] ← CDCells.RepositionCell[cell, NIL]};
GlueSideObject:
PUBLIC
PROC[glue: Glue, side: Side]
RETURNS[obj:
CD.Object] = {
cell: CellType ← glue.cell[side];
layer: CD.Layer ← CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]];
length: INT;
list: LIST OF NWMML;
IF cell=NIL THEN RETURN[NIL];
length ←
SELECT side
FROM
top, bottom => CCDUtils.CellSize[cell].x
ENDCASE => CCDUtils.CellSize[cell].y;
list ← CCD.SidePinList[cell, CoreFrame.OppSide[side]];
FOR lst:
LIST
OF
NWMML ← list, lst.rest
WHILE lst#
NIL
DO
lst.first.max ← lst.first.max - lst.first.min; -- max ← size
ENDLOOP;
obj ← SideObject[side, list, layer, length]};
MakeChannel:
PUBLIC
PROC
[glue: Glue, name:
ROPE, sizeSpec:
REF
CD.Rect, routeType: PWRoute.RouteType]
RETURNS [cell: CellType] = {
sumDiffType: BOOL ← FALSE;
sum, diff: LIST OF NWMML;
objs:
ARRAY Side
OF
CD.Object ← [
bottom: GlueSideObject[glue, bottom ],
right: GlueSideObject[glue, right ],
top: GlueSideObject[glue, top ],
left: GlueSideObject[glue, left ] ];
obj: CD.Object;
FOR side: Side
IN Side
WHILE
NOT sumDiffType
DO IF glue.type[side]=sum OR glue.type[side]=diff THEN sumDiffType ← TRUE ENDLOOP;
IF sumDiffType
THEN {
FOR side: Side
IN Side
DO
nwmmls: LIST OF NWMML;
IF glue.type[side]#conn AND glue.type[side]#chan AND glue.type[side]#pwr THEN LOOP;
nwmmls ← CCD.SidePinList[glue.cell[side], CoreFrame.OppSide[side]];
FOR list:
LIST
OF
NWMML ← nwmmls, list.rest
WHILE list#
NIL
DO
list.first.max ← list.first.max - list.first.min; -- max ← size
list.first.min ← 0 ENDLOOP; -- throw away position info for channel sides
FOR list:
LIST
OF
NWMML ← nwmmls, list.rest
WHILE list#
NIL
DO
unique: BOOL;
[sum, unique] ← AddIfUnique[list.first, sum];
IF unique
THEN diff ← CONS[list.first, diff]
ELSE diff ← DelIfPresent[list.first, diff].new;
ENDLOOP;
ENDLOOP;
FOR side: Side
IN Side
DO
layer: CD.Layer ← CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]];
IF glue.type[side]=sum THEN objs[side] ← SideObject[side, sum, layer];
IF glue.type[side]=diff THEN objs[side] ← SideObject[side, diff, layer];
ENDLOOP};
obj ←
IF glue.tDir=horizontal
THEN PWRoute.MakeChannel[objs[bottom], objs[top], objs[left], objs[right],
sizeSpec, glue.params, FALSE, routeType]
ELSE PWRoute.MakeChannel[objs[left], objs[right], objs[bottom], objs[top],
sizeSpec, glue.params, TRUE, routeType];
cell ← CoreLibrary.ObjCell[name: name, obj: obj]};
AddIfUnique:
PROC[item:
NWMML, list:
LIST
OF
NWMML]
RETURNS[new: LIST OF NWMML, done: BOOL] = {
FOR l:
LIST
OF
NWMML ← list, l.rest
WHILE l#
NIL
DO
IF item.name = l.first.name
THEN
{l.first.max ← MAX[l.first.max, item.max]; RETURN[list, FALSE]} ENDLOOP;
RETURN[CONS[item, list], TRUE]};
DelIfPresent:
PROC[item:
NWMML, list:
LIST
OF
NWMML]
RETURNS[new: LIST OF NWMML, done: BOOL] = {
IF list=NIL THEN RETURN[NIL, FALSE];
IF item.name = list.first.name THEN RETURN[list.rest, TRUE];
FOR l:
LIST
OF
NWMML ← list, l.rest
WHILE l.rest#
NIL
DO
IF item.name = list.rest.first.name
THEN
{l.rest ← l.rest.rest; RETURN[list, TRUE]} ENDLOOP;
RETURN[list, FALSE]};
ChanObj: PUBLIC PROC [
layer: CD.Layer,
side: Side,
ref: REF ← NIL,
ph: Ph ← unk,
dim: INT ← 0 ]
RETURNS [cell: CD.Object] ~ {
pos: CD.Position ← [0, 0];
form: REFBit.Format ← REFBit.Desc[ref].bitForm;
list: LIST OF NWMML;
dim ← MAX[dim, 4*CD.FetchTechnology[$cmosB].lambda];
FOR i: CARDINAL DECREASING IN [0..form.size) DO
name: ROPE ← CoreName.BitRopeToSigRope[form[i].name];
nameInv: ROPE ← CoreName.BitRopeToSigRope[form[i].nameInv];
list ← CONS[ NWMML[
name: CoreName.SignalName[FALSE, name, nameInv, ph],
wire: NIL, min: 0, max: dim, layer: layer], list];
ENDLOOP;
cell ← SideObject[side, list, layer]};
FillerCell:
PROC [glue:
Glue, objSide: Side, width:
INT]
RETURNS [cell: CellType] = {
templateCT: CellType ← glue.cell[CoreFrame.OppSide[objSide]];
templateSize: CD.Position ← CCD.CellSize[templateCT];
resultSize: CD.Position;
deslayerRope: IO.ROPE ← GlueSideLayer[glue, objSide];
IF glue.class=xlt
THEN cell ← CoreGlue.XferPins[templateCT, objSide, deslayerRope, width]
ELSE cell ← CoreGlue.XferPins[templateCT, objSide, NIL, width];
resultSize ← CCD.CellSize[cell];
IF (
SELECT objSide
FROM
left, right => resultSize.x#width OR resultSize.y#templateSize.y,
top, bottom => resultSize.y#width OR resultSize.x#templateSize.x,
ENDCASE => ERROR) THEN Signal[] };
MergePwr:
PROC [glue:
Glue, objSide: Side, width:
INT]
RETURNS [cell: CellType] = {
pinSide: Side ← CoreFrame.OppSide[objSide];
pinCell: CellType ← glue.cell[objSide];
vgCell: CellType ← glue.cell[pinSide];
size1: CD.Position ← CCD.CellSize[pinCell];
size2: CD.Position ← CCD.CellSize[vgCell];
size3: CD.Position;
deslayerRope: IO.ROPE ← GlueSideLayer[glue, objSide];
cell ← CoreGlue.MergePwrPins[vgCell, pinCell, pinSide, deslayerRope, width];
size3 ← CCD.CellSize[cell];
IF (
SELECT objSide
FROM
left, right => size3.y#size1.y OR size3.y#size2.y OR size3.x < width,
top, bottom => size3.x#size1.x OR size3.x#size2.x OR size3.y < width,
ENDCASE => ERROR) THEN Signal[] };
AdjustLayerAssignments:
PROC[glue: Glue] = {
reversed: BOOL ← FALSE;
FOR side: Side
IN Side
DO
temp: ROPE;
nwmmls: LIST OF NWMML;
layer: CD.Layer;
IF glue.type[side]#conn THEN LOOP;
nwmmls ← CCD.SidePinList[glue.cell[side], CoreFrame.OppSide[side]];
layer ← CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]];
IF (layer=nwmmls.first.layer)#(glue.class=xlt) THEN LOOP;
IF reversed THEN Signal[];
reversed ← TRUE;
temp ← glue.params.trunkLayer;
glue.params.trunkLayer ← glue.params.branchLayer;
glue.params.branchLayer ← temp;
layer ← CDSimpleRules.GetLayer[$cmosB, GlueSideLayer[glue, side]];
IF layer#nwmmls.first.layer THEN Signal[];
log.PutF["\nAdjusting Glue layers; %g side to be %g ",
IO.rope[CoreFrame.SideRope[side]], IO.rope[GlueSideLayer[glue, side]]];
ENDLOOP};
GlueSideLayer:
PROC[glue: Glue, side: Side]
RETURNS[layer:
ROPE] = {
tLayer:
BOOL ←
SELECT side
FROM
left, right => glue.tDir=horizontal,
top, bottom => glue.tDir=vertical,
ENDCASE => ERROR;
RETURN[IF tLayer THEN glue.params.trunkLayer ELSE glue.params.branchLayer]};
ThreeLevel:
PROC[glue: Glue, channels:
INT]
RETURNS[cell: Core.CellType] = {
cellWidth: INT ← IFUCoreData.CellWidth[channels];
rowWidth: INT ← CCD.CellSize[glue.cell[top]].x;
range: INT ← rowWidth/cellWidth;
left: INT ← CCD.metW/2-CCD.leftTail;
right: INT ← CCD.metW/2-CCD.leftTail+rowWidth;
polyMax: INT ← rowWidth/8;
left, right, channels etc are all needed to position VDD and GND; Change this;
GetNode:
PROC[name:
ROPE]
RETURNS[node: Node] = {
IF IsPwr[name] THEN RETURN[NIL];
IF name=NIL THEN RETURN[NIL];
node ← NARROW[HashTable.Fetch[nodeTable, name].value];
IF node=
NIL
THEN {
node ← NEW[NodeRec ← [name: name, minX: right, maxX: 0, type: CCD.cmosMet2]];
[ ] ← HashTable.Store[nodeTable, name, node] } };
MarkPolys: HashTable.EachPairAction = {
node: Node ← NARROW[value];
node.type ← IF node.maxX-node.minX <= polyMax THEN CCD.cmosPoly ELSE CCD.cmosMet2;
RETURN[FALSE] };
nwmmls: LIST OF NWMML;
nodeTable: HashTable.Table ←
HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope];
nwmmls ← CCD.SidePinList[glue.cell[top], bottom];
FOR nwmmls ← nwmmls, nwmmls.rest
WHILE nwmmls#
NIL
DO
node: Node ← GetNode[nwmmls.first.name];
loc: INT ← nwmmls.first.min+left;
IF node=NIL THEN LOOP;
node.top ← CONS [loc, node.top];
node.minX ← MIN [loc, node.minX];
node.maxX ← MAX [loc, node.maxX] ENDLOOP;
nwmmls ← CCD.SidePinList[glue.cell[bottom], top];
FOR nwmmls ← nwmmls, nwmmls.rest
WHILE nwmmls#
NIL
DO
node: Node ← GetNode[nwmmls.first.name];
loc: INT ← nwmmls.first.min+left;
IF node=NIL THEN LOOP;
node.bot ← CONS [loc, node.bot];
node.minX ← MIN [loc, node.minX];
node.maxX ← MAX [loc, node.maxX] ENDLOOP;
IF glue.cell[left]#
NIL
THEN {
nwmmls ← CCD.SidePinList[glue.cell[left], right];
FOR nwmmls ← nwmmls, nwmmls.rest
WHILE nwmmls#
NIL
DO
node: Node ← GetNode[nwmmls.first.name];
IF node=NIL THEN LOOP;
node.minX ← left ENDLOOP};
IF glue.cell[right]#
NIL
THEN {
nwmmls ← CCD.SidePinList[glue.cell[right], left];
FOR nwmmls ← nwmmls, nwmmls.rest
WHILE nwmmls#
NIL
DO
node: Node ← GetNode[nwmmls.first.name];
IF node=NIL THEN LOOP;
node.maxX ← right ENDLOOP };
[ ] ← HashTable.Pairs[nodeTable, MarkPolys];
cell ← ThreeLevelRoute[nodeTable, range, left, right, cellWidth, channels]};
ThreeLevelRoute:
PUBLIC PROC
[ nodeTable: HashTable.Table, range, left, right, cellWidth, channels:
INT]
RETURNS[cell: CellType] = {
obj: CD.Object;
pitch: CD.Position ← [CCD.metPitch, CCD.met2Pitch/2]; -- y pitch - met2 pol met2 pol . . .
pass: LIST OF Node ← NIL;
conn: LIST OF Node ← NIL;
assigned: LIST OF Node ← NIL;
iSize: CD.Rect ← [left, 0, right, 0];
MarkNodeDependencies[nodeTable];
[pass, conn] ← BuildNodeLists[nodeTable, iSize];
Assign Node Rows
DO
progress: BOOL ← FALSE;
workToDo: BOOL ← FALSE;
FOR nodePtr:
LIST
OF Node ← conn, nodePtr.rest
WHILE nodePtr#
NIL
DO
polyRow: BOOL ← nodePtr.first.type = CCD.cmosPoly;
rockMax: INT ← pitch.y*(IF polyRow THEN -1 ELSE -2);
IF polyRow THEN Signal[];
IF nodePtr.first.row>-1 THEN LOOP;
workToDo ← TRUE;
FOR rocks:
LIST
OF Node ← nodePtr.first.rocks, rocks.rest
WHILE rocks#
NIL
DO
IF rocks.first.row=-1 THEN GOTO unAssignedRocks;
rockMax ← MAX[rockMax, rocks.first.row];
REPEAT unAssignedRocks => LOOP ENDLOOP;
progress ← TRUE;
assigned ← AddUnassignedNodeToAssigned
[polyRow, pitch.y, nodePtr.first, assigned, rockMax];
ENDLOOP;
IF NOT workToDo THEN EXIT;
IF NOT progress THEN Signal[]; -- circular
ENDLOOP;
Determine Y Size
iSize.y2 ← 0;
FOR nodePtr:
LIST
OF Node ← assigned, nodePtr.rest
WHILE nodePtr#
NIL
DO
iSize.y2 ← MAX[iSize.y2, nodePtr.first.row] ENDLOOP;
iSize.y2 ← iSize.y2 + CCD.cnctSize/2 + CCD.topTail;
iSize.y1 ← 0 - CCD.cnctSize/2 - CCD.botTail - CCD.lambda;
obj ← CDCells.CreateEmptyCell[];
Draw Power extension wires
FOR jj:
INT
IN [0..1]
DO
name: ROPE ← CoreName.RopeNm[IF jj=0 THEN "GND" ELSE "VDD"];
FOR ii:
INT
IN [0..range)
DO
xx: INT ← ii*cellWidth + (channels+jj)*pitch.x;
CCD.PutPin[obj,
[CCD.metW, CCD.metW], [xx, iSize.y2-CCD.metW], CCD.cmosMet, name];
CCD.PutPin[obj,
[CCD.metW, CCD.metW], [xx, iSize.y1], CCD.cmosMet, name];
CCD.AddRet[obj,
[CCD.pwrW, iSize.y2-iSize.y1], [xx-(CCD.pwrW-CCD.metW)/2, iSize.y1], CCD.cmosMet];
ENDLOOP ENDLOOP;
Draw Other extension wires
FOR nodePtr:
LIST
OF Node ← pass, nodePtr.rest
WHILE nodePtr#
NIL
DO
-- pass
name: ROPE ← nodePtr.first.name;
vgNode: BOOL ← IsPwr[name];
xx: INT ← nodePtr.first.minX;
xxx: INT ← xx;
wireW: INT ← CCD.metW;
IF vgNode THEN {wireW ← CCD.pwrW; xxx ← xx-(CCD.pwrW-CCD.metW)/2};
IF nodePtr.first.top=
NIL
OR nodePtr.first.bot=
NIL
THEN {
log.PutF["\nSignal %g is not connected anywhere", IO.rope[nodePtr.first.name]];
Signal[]};
CCD.PutPin [obj, [wireW, CCD.metW], [xx, iSize.y2-CCD.metW], CCD.cmosMet, name];
CCD.PutPin [obj, [wireW, CCD.metW], [xx, iSize.y1], CCD.cmosMet, name];
CCD.AddRet [obj, [wireW, iSize.y2-iSize.y1], [xxx, iSize.y1], CCD.cmosMet];
ENDLOOP;
DrawAssigndedNodes[obj, assigned, iSize];
CDCells.SetInterestRect[obj, iSize];
[ ] ← CDCells.RepositionCell[obj, NIL];
cell ← CoreLibrary.ObjCell[obj, CoreName.ID["SB"]];
RETURN[cell]};
Branch: TYPE = REF BranchRec;
BranchRec: TYPE = RECORD[loc: INT, top, bot: Node];
InsertBranch:
PROC [branchTab: CardTable.Ref, s: {top,bot}, loc:
INT, node: Node] ~ {
branch: Branch ← NARROW[CardTable.Fetch[branchTab, loc].val];
IF branch=
NIL
THEN {
branch ← NEW[BranchRec ← [loc: loc]];
[ ] ← CardTable.Store[branchTab, loc, branch]};
SELECT s
FROM
top => {IF branch.top#NIL THEN Signal[]; branch.top ← node};
bot => {IF branch.bot#NIL THEN Signal[]; branch.bot ← node}; ENDCASE};
MarkNodeDependencies:
PROC[nodeTable: HashTable.Table] = {
InsertNodes: HashTable.EachPairAction = {
node: Node ← NARROW[value];
FOR list:
LIST
OF
INT ← node.top, list.rest
WHILE list#
NIL
DO
InsertBranch[branchTab, top, list.first, node] ENDLOOP;
FOR list:
LIST
OF
INT ← node.bot, list.rest
WHILE list#
NIL
DO
InsertBranch[branchTab, bot, list.first, node] ENDLOOP;
RETURN[FALSE] };
MarkNodes: CardTable.EachPairAction = {
branch: Branch ← NARROW[val];
IF branch.top=NIL OR branch.bot=NIL OR branch.top=branch.bot THEN RETURN[FALSE];
FOR list:
LIST
OF Node ← branch.top.rocks, list.rest
WHILE list#
NIL
DO
IF list.first=branch.bot THEN EXIT;
REPEAT FINISHED => branch.top.rocks ← CONS[branch.bot, branch.top.rocks] ENDLOOP;
FOR list:
LIST
OF Node ← branch.bot.clouds, list.rest
WHILE list#
NIL
DO
IF list.first=branch.top THEN EXIT;
REPEAT FINISHED => branch.bot.clouds ← CONS[branch.top, branch.bot.clouds] ENDLOOP;
RETURN[FALSE] };
branchTab: CardTable.Ref ← CardTable.Create[];
[ ] ← HashTable.Pairs[nodeTable, InsertNodes];
[ ] ← CardTable.Pairs[branchTab, MarkNodes]};
BuildNodeLists:
PROC[nodeTable: HashTable.Table, iSize:
CD.Rect]
RETURNS[pass, conn: LIST OF Node] = {
SortNodes: HashTable.EachPairAction = {
node: Node ← NARROW[value];
SELECT
TRUE
FROM
node.maxX = node.minX => pass ← OrderedInsertion[pass, node];
ENDCASE => conn ← OrderedInsertion[conn, node];
RETURN[FALSE] };
[ ] ← HashTable.Pairs[nodeTable, SortNodes]};
OrderedInsertion:
PROC[list:
LIST
OF Node, node: Node]
RETURNS [
LIST
OF Node] = {
test: INT;
IF list = NIL THEN RETURN[CONS[node, list]];
test ← (list.first.maxX-list.first.minX)-(node.maxX-node.minX); -- largest segemet first
IF test = 0 THEN test ← (node.minX)-(list.first.minX); -- smallest position first
IF test < 0
THEN RETURN[CONS[node, list]]
ELSE {list.rest ← OrderedInsertion[list.rest, node]; RETURN[list]}};
AddUnassignedNodeToAssigned:
PROC
[oddRow: BOOL, step: INT, node: Node, orig: LIST OF Node, rockMax: INT]
RETURNS [LIST OF Node] = {
Next:
PROC[row:
INT]
RETURNS[next:
INT] =
{ next ← row + (IF (((row/step+2) MOD 2)=1)=oddRow THEN 2*step ELSE step) };
minOkRow: INT ← Next[rockMax+step];
IF orig=
NIL
OR minOkRow < orig.first.row
THEN {node.row ← minOkRow; RETURN[CONS[node, orig] ]};
IF minOkRow = orig.first.row
AND node.maxX < orig.first.minX
THEN {node.row ← minOkRow; RETURN[CONS[node, orig] ]};
FOR list:
LIST
OF Node ← orig, list.rest
DO
thisRow: INT ← list.first.row;
nextRow:
INT ←
IF list.rest#
NIL
THEN list.rest.first.row
ELSE Next[MAX[thisRow, rockMax+step]];
nextMinX:
INT ←
IF list.rest#
NIL
THEN list.rest.first.minX
ELSE LAST[INT];
minOkRow ← Next[MAX[thisRow-step, rockMax+step]]; -- thisRow or thisRow+step
SELECT
TRUE
FROM
thisRow = nextRow =>
SELECT
TRUE
FROM
minOkRow < thisRow => ERROR;
minOkRow > thisRow => LOOP;
list.first.maxX >= node.minX => LOOP;
node.maxX >= nextMinX => LOOP;
ENDCASE => node.row ← thisRow;
thisRow+step = nextRow =>
SELECT
TRUE
FROM
minOkRow < thisRow => ERROR;
minOkRow = thisRow =>
SELECT
TRUE
FROM
list.first.maxX >= node.minX => LOOP;
ENDCASE => node.row ← thisRow;
minOkRow = nextRow =>
SELECT
TRUE
FROM
node.maxX >= nextMinX => LOOP;
ENDCASE => node.row ← nextRow;
minOkRow > thisRow => LOOP;
ENDCASE => ERROR;
thisRow+2*step = nextRow =>
SELECT
TRUE
FROM
minOkRow < thisRow => ERROR;
minOkRow = thisRow =>
SELECT
TRUE
FROM
list.first.maxX < node.minX => node.row ← thisRow;
node.maxX < nextMinX => node.row ← nextRow;
ENDCASE => LOOP;
minOkRow < nextRow => node.row ← minOkRow; -- between
minOkRow = nextRow =>
SELECT
TRUE
FROM
node.maxX < nextMinX => node.row ← nextRow;
ENDCASE => LOOP;
ENDCASE => LOOP;
ENDCASE => ERROR;
list.rest ← CONS[node, list.rest];
IF oddRow#(((node.row)/step MOD 2)=1) THEN Signal[];
EXIT ENDLOOP;
RETURN[orig]};
IsPwr:
PROC[name:
ROPE]
RETURNS[
BOOL] =
{RETURN[Rope.Find[name,"GND"]#-1 OR Rope.Find[name,"VDD"]#-1]};
DrawAssigndedNodes:
PROC[cell:
CD.Object, assigned:
LIST
OF Node, iSize:
CD.Rect] = {
FOR nodePtr:
LIST
OF Node ← assigned, nodePtr.rest
WHILE nodePtr#
NIL
DO
-- top bot
name: ROPE ← nodePtr.first.name;
yMid: INT ← nodePtr.first.row;
minX: INT ← nodePtr.first.minX;
maxX: INT ← nodePtr.first.maxX;
rowType: CD.Layer ← nodePtr.first.type;
pFrng: INT ← (CCD.pwrW-CCD.metW)/2;
vgNode: BOOL ← IsPwr[name];
rowWW: INT ← IF rowType = CCD.cmosPoly THEN CCD.polW ELSE CCD.met2W;
ctct: CD.Object ← CCD.Contact[rowType];
IF minX=iSize.x1
THEN
CCD.PutPin[cell, [rowWW, rowWW], [minX, yMid-rowWW/2], rowType, name];
IF maxX=iSize.x2
THEN
CCD.PutPin[cell, [rowWW, rowWW], [maxX-rowWW, yMid-rowWW/2], rowType, name];
CCD.AddRet [cell, [maxX-minX, rowWW], [minX, yMid-rowWW/2], rowType];
FOR nodeTop:
LIST
OF
INT ← nodePtr.first.top, nodeTop.rest
WHILE nodeTop#
NIL
DO
xx: INT ← nodeTop.first;
IF vgNode
THEN CCD.AddRet[cell, [CCD.pwrW, iSize.y2-yMid], [xx-pFrng, iSize.y1], CCD.cmosMet]
ELSE CCD.AddRet[cell, [CCD.metW, iSize.y2-yMid], [xx, yMid], CCD.cmosMet];
CCD.PutPin [cell, [CCD.metW, CCD.metW], [xx,iSize.y2-CCD.metW], CCD.cmosMet, name];
[] ← PW.IncludeInCell[cell, ctct, [xx-(CCD.cnctSize-CCD.metW)/2, yMid-CCD.cnctSize/2]];
ENDLOOP;
FOR nodeBot:
LIST
OF
INT ← nodePtr.first.bot, nodeBot.rest
WHILE nodeBot#
NIL
DO
xx: INT ← nodeBot.first;
IF vgNode
THEN CCD.AddRet[cell, [CCD.pwrW, yMid-iSize.y1], [xx-pFrng, iSize.y1], CCD.cmosMet]
ELSE CCD.AddRet[cell, [CCD.metW, yMid-iSize.y1], [xx, iSize.y1], CCD.cmosMet];
CCD.PutPin [cell, [CCD.metW, CCD.metW], [xx, iSize.y1], CCD.cmosMet, name];
[] ← PW.IncludeInCell[cell, ctct, [xx-(CCD.cnctSize-CCD.metW)/2, yMid-CCD.cnctSize/2]];
ENDLOOP;
ENDLOOP};
RouteSoft: PUBLIC CoreGlue.FrameRouter = {RETURN[complete2]};
RouteHard:
PUBLIC CoreGlue.FrameRouter = {
PROC[frameCT: CellType] RETURNS[status: Status]
name: ROPE ← CoreName.CellNm[frameCT].n;
status ← rejustify;
log.PutF["\n\n Building Frame: %g", IO.rope[name]];
CoreFrame.RotateFrame [frameCT];
CoreFrame.TellKidsAboutDad [frameCT];
CheckExpandedFrame [frameCT];
FOR pass:
INT ← 1, pass+1
WHILE status<complete2
DO
log.PutF["\n\n Pass %g %g\n", IO.int[pass], IO.time[]]; log.Flush[];
IF status=rejustify
THEN {
log.PutRope[" Rejustify\n"]; log.Flush[];
CoreFrame.GetSize [frameCT];
CoreFrame.ReSize [frameCT];
CoreFrame.RePos [frameCT, [0,0]];
IF pass<2
THEN {
log.PutRope["\n\n"];
CoreFrame.LogFCT[frameCT, 0, 1, log];
log.Flush[]} };
log.PutRope["\n"];
status ← Instantiate[frameCT];
log.PutF["\n Status: %g", IO.rope[StatusRope[status]]];
SELECT status
FROM
rejustify => {LOOP};
progress => {LOOP};
delayed => {IF NOT CoreFrame.FixOneSize[frameCT] THEN Signal[]};
complete1 => {IF NOT CoreFrame.FixOneSize[frameCT] THEN Signal[]};
complete2 => {EXIT};
ENDCASE => {ERROR};
ENDLOOP;
log.PutRope["\n\n"];
CoreFrame.LogFCT[frameCT, 0, 1, log];
log.Flush[]};
CoreFrame.GetPins[new];
log: IO.STREAM ← CoreFrame.GetLog[];
Signal: SIGNAL = CODE;
END.