CoreRouteMosaic.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Created by Don Curry February 23, 1988 2:20:43 pm PST
Don Curry August 25, 1988 7:19:32 pm PDT
DIRECTORY
Basics, CD, CDBasics, CDCells, CDSimpleRules, CedarProcess, CMosB, Core, CoreClasses, CoreGeometry, CoreOps, CoreProperties, CoreRoute, DABasics, IntHashTable, IO, PWCore, RefTab, Rope, Route, Sisyph, SymTab, TerminalIO;
CoreRouteMosaic: CEDAR PROGRAM
IMPORTS Basics, CD, CDBasics, CDCells, CDSimpleRules, CedarProcess, CMosB, CoreGeometry, CoreOps, CoreProperties, CoreRoute, DABasics, IntHashTable, IO, PWCore, RefTab, Rope, Route, Sisyph, SymTab, TerminalIO
= BEGIN
Types and constants
MosaicForm:   TYPE = REF MosaicFormRec;
MosaicFormRec:  TYPE = RECORD[
data:   CoreClasses.RecordCellType,
cellType:  CellType,
horizLayer: CD.Layer,
vertLayer: CD.Layer,
ignoreNWell: REF,
seq:   SEQUENCE size: NAT OF MosaicRow];
MosaicRow:   TYPE = REF MosaicRowRec;
MosaicRowRec:  TYPE = RECORD[SEQUENCE size: NAT OF MosaicCell];
MosaicCell:   TYPE = RECORD[schPos, layPos: CD.Position, ctInst: INT, sBox: CD.Object];
PPDist:    TYPE = RECORD[schP1, schP2, layDist: INT];
LocSchLay:   TYPE = RECORD[sch, lay: INT];
RowCol:    TYPE = RECORD[row, col: INT];
WirePin:    TYPE = CoreRoute.WirePin;
WirePins:    TYPE = CoreRoute.WirePins;
WirePinAry:   TYPE = ARRAY Side OF WirePins;
Side:     TYPE = CoreGeometry.Side;
CellType:    TYPE = Core.CellType;
Wire:     TYPE = Core.Wire;
Wires:     TYPE = Core.Wires;
NetInfo:    TYPE = REF NetInfoRec;
NetInfoRec:   TYPE = RECORD [
trunkSize: INT    ← 0,
pins:   LIST OF PinInfo ← NIL];
PinInfo:    TYPE = RECORD [
side:   Side,
min:   CD.Number ← 0,
max:   CD.Number ← 0,
layer:   CD.Layer];
technologyKey:  ATOM ← $cmosB;
wireWidthProp:  ATOM ← $w;
mosaicLayoutProp: ATOM ← $Mosaic;
mosaicFormProp:  ATOM ← $MosaicForm;
lambda:    INT ← CDSimpleRules.GetTechnology[technologyKey].lambda;
Signal:    SIGNAL[msg: IO.ROPE] = CODE;
Mosaic Attribute, Layout and Decorate Procs
MosaicAttributes:  PWCore.AttributesProc = {
frm: MosaicForm ← CreateMosaicForm[cellType];
ShowMosaicForm[frm];
CheckInterfaces[frm];
BuildSBoxs[frm]};
MosaicLayout:   PWCore.LayoutProc  = {
frm: MosaicForm ← NARROW[CoreProperties.GetCellTypeProp[cellType, mosaicFormProp]];
iList: CD.InstanceList;
ctInsts: CoreClasses.CellInstances;
maxLay: CD.Position ← frm[frm.size-1][frm[0].size-1].layPos;
FOR row: INT DECREASING IN [0..frm.size-1) DO
FOR col: INT DECREASING IN [0..frm[row].size-1) DO
IF OriginRowColOf[frm, row, col] # [row, col] THEN LOOP;
IF IsSBox[frm, row, col]
THEN {
inst: CD.Instance ← NewInstance[frm[row][col].sBox, frm[row][col].layPos];
iList ← CONS[inst, iList]}
ELSE {
ctInst: CoreClasses.CellInstance ← frm.data[frm[row][col].ctInst];
inst: CD.Instance ← NewInstance[PWCore.Layout[ctInst.type], frm[row][col].layPos];
ctInsts ← CONS[ctInst, ctInsts];
iList ← CONS[inst, iList]} ENDLOOP ENDLOOP;
FOR i: NAT IN [0..frm.data.size) DO frm.data[i] ← ctInsts.first; ctInsts ← ctInsts.rest ENDLOOP;
obj ← CDCells.CreateCell[il: iList, ir: [0, 0, maxLay.x, maxLay.y]];
CDCells.ToSequenceMode[obj]};
NewInstance: PROC[obj: CD.Object, irLoc: CD.Position]
RETURNS[inst: CD.Instance] = {
CD.Instance given where you want the corner of the interest rect.
base: CD.Position ← CDBasics.BaseOfRect[CD.InterestRect[obj]];
pos: CD.Position ← CDBasics.SubPoints[irLoc, base];
inst     ← NEW[CD.InstanceRep ← [obj, [pos]] ]};
MosaicDecorate:   PWCore.DecorateProc = {
WireToLabels: PROC [wire: Wire] RETURNS [labels: LIST OF Route.Label ← NIL] =
{RETURN[LIST[CoreRoute.LabelInternal[form.data.internal, wire]]]};
form: MosaicForm ← NARROW[CoreProperties.GetCellTypeProp[cellType, mosaicFormProp]];
CoreRoute.DecorateRoutedArea[
cellType:   cellType,
obj:    obj,
wireToLabels: WireToLabels];
form.cellType ← NIL;
form.data  ← NIL;
CoreProperties.PutCellTypeProp[cellType, mosaicFormProp, NIL]};
Primary Procs
CreateMosaicForm: PROC[cellType: CellType] RETURNS[frm: MosaicForm] = {
RoundedIR: PROC[index: INT] RETURNS[ir: CD.Rect] = {
ir  ← CoreRoute.SchMappedIR[data[index]];
ir.x1 ← (ir.x1/lambda)*lambda;  ir.x2 ← (ir.x2/lambda)*lambda;
ir.y1 ← (ir.y1/lambda)*lambda; ir.y2 ← (ir.y2/lambda)*lambda};
data:  CoreClasses.RecordCellType ← NARROW [cellType.data];
xs:   LIST OF PPDist;
ys:  LIST OF PPDist;
locsX:  LIST OF LocSchLay;
locsY:  LIST OF LocSchLay;
FOR i: NAT IN [0..data.size) DO
ir:   CD.Rect  ← RoundedIR[i];
laySize: CD.Position;
laySize ← CD.InterestSize[PWCore.Layout[data[i].type]];
xs ← CONS[[ir.x1, ir.x2, laySize.x], xs];
ys ← CONS[[ir.y1, ir.y2, laySize.y], ys] ENDLOOP;
locsX ← ConsolidatePPDs[xs];
locsY ← ConsolidatePPDs[ys];
frm ← NEW[MosaicFormRec[SizeLocSchLayList[locsY]]];
CoreProperties.PutCellTypeProp[cellType, mosaicFormProp, frm];
frm.cellType ← cellType;
frm.data   ← data;
[frm.vertLayer, frm.horizLayer] ← CoreRoute.GetCellTypePropLayer[cellType, $VerticalMetal];
frm.ignoreNWell ← CoreProperties.GetCellTypeProp[cellType, $IgnoreNWell];
FOR row: INT IN [0..frm.size) DO
xlist: LIST OF LocSchLay ← locsX;
frm[row] ← NEW[MosaicRowRec[SizeLocSchLayList[locsX]]];
FOR col: INT IN [0..frm[row].size) DO
frm[row][col].schPos ← [xlist.first.sch, locsY.first.sch];
frm[row][col].layPos ← [xlist.first.lay, locsY.first.lay];
frm[row][col].ctInst ← -1;
xlist ← xlist.rest ENDLOOP;
locsY ← locsY.rest ENDLOOP;
FOR i: NAT IN [0..data.size) DO
ir:   CD.Rect ← RoundedIR[i];
ir.x2  ← ir.x2 - lambda; -- 2* lambda/2
ir.y2  ← ir.y2 - lambda; -- 2* lambda/2
FOR row: INT IN [0..frm.size-1) DO
FOR col: INT IN [0..frm[row].size-1) DO
IF ~CDBasics.InsidePos[frm[row][col].schPos, ir] THEN LOOP;
IF frm[row][col].ctInst#-1 THEN ERROR;
frm[row][col].ctInst ← i ENDLOOP ENDLOOP ENDLOOP};
ConsolidatePPDs:  PROC[list: LIST OF PPDist] RETURNS[locs: LIST OF LocSchLay] = {
GetNode: PROC[schLoc: INT] RETURNS[node: REF Node] = {
node ← NARROW[IntHashTable.Fetch[nodeTab, schLoc].value];
IF node=NIL
THEN {node ← NEW[Node←[]]; []←IntHashTable.Store[nodeTab, schLoc, node]}};
SetLayLoc: PROC[schLoc, layLoc: INT] = {
node: REF Node ← GetNode[schLoc];
IF node.layLoc#-1 THEN {IF node.layLoc=layLoc THEN RETURN ELSE ERROR};
node.layLoc ← layLoc;
locs ← CONS[[schLoc, layLoc], locs];
FOR lst: LIST OF LocSchLay ← locs, lst.rest WHILE lst#NIL AND lst.rest#NIL DO
TwoLocSchLays: TYPE = RECORD[l1,l2: LocSchLay];
IF lst.first.sch <= lst.rest.first.sch THEN
{IF lst.first.sch = lst.rest.first.sch OR lst.first.lay >= lst.rest.first.lay THEN ERROR; EXIT};
[lst.first, lst.rest.first] ← TwoLocSchLays[lst.rest.first, lst.first] ENDLOOP;
FOR links: LIST OF Link ← node.links, links.rest WHILE links#NIL DO
SetLayLoc[links.first.schLoc, layLoc + links.first.layDist] ENDLOOP};
Node:  TYPE = RECORD[layLoc: INT ← -1, links: LIST OF Link ← NIL];
Link:  TYPE = RECORD[schLoc, layDist: INT ← -1];
nodeTab: IntHashTable.Table ← IntHashTable.Create[];
min:  INTLAST[INT];
FOR list ← list, list.rest WHILE list#NIL DO
nodeUp: REF Node ← GetNode[list.first.schP1];
nodeDn: REF Node ← GetNode[list.first.schP2];
nodeUp.links ← CONS[[schLoc: list.first.schP2, layDist: +list.first.layDist], nodeUp.links];
nodeDn.links ← CONS[[schLoc: list.first.schP1, layDist: -list.first.layDist], nodeDn.links];
min   ← MIN[min, list.first.schP1] ENDLOOP;
SetLayLoc[min, 0]};
CheckInterfaces:  PROC[frm: MosaicForm] = {
IF CoreProperties.GetCellTypeProp[frm.cellType, $TrustMe]#NIL THEN RETURN;
FOR row: INT IN [0..frm.size-2) DO
FOR col: INT IN [0..frm[row].size-2) DO
IF frm[row][col].ctInst  # frm[row][col+1].ctInst AND
frm[row][col].ctInst  # -1 AND
frm[row][col+1].ctInst  # -1 THEN {
l1: WirePins ← GetLayoutPins[frm, row, col+1, left];
l2: WirePins ← GetLayoutPins[frm, row, col, right];
IF NOT EqualWirePins[l1, l2] THEN ERROR};
IF frm[row][col].ctInst  # frm[row+1][col].ctInst AND
frm[row][col].ctInst  # -1 AND
frm[row+1][col].ctInst  # -1 THEN {
l1: WirePins ← GetLayoutPins[frm, row+1, col, bottom];
l2: WirePins ← GetLayoutPins[frm, row, col, top];
IF NOT EqualWirePins[l1, l2] THEN ERROR};
ENDLOOP ENDLOOP};
BuildSBoxs:    PROC[frm: MosaicForm] = {
name:  IO.ROPE  ← CoreOps.GetCellTypeName[frm.cellType];
globals: Core.Wires ← CoreRoute.GlobalWires[frm.cellType];
FOR row: INT IN [0..frm.size-1) DO
FOR col: INT IN [0..frm[row].size-1) DO
IF OriginRowColOf[frm, row, col] # [row, col] THEN LOOP;
IF IsSBox[frm, row, col] THEN {
lim:  RowCol ← LimitRowColOf[frm, row, col];
laySize: CD.Position ←
CDBasics.SubPoints[frm[lim.row][lim.col].layPos, frm[row][col].layPos];
pinAry: WirePinAry ← GetSBBrotherPins[frm, row, col, lim.row, lim.col];
wireAry: ARRAY Side OF Wires ← GetSBParentWires[frm, row, col, lim.row, lim.col];
TerminalIO.PutF["SBox at (%g, %g)\n", IO.int[col], IO.int[row]];
FOR side: Side IN Side DO
IF pinAry[side] # NIL THEN LOOP;
pinAry[side] ← CoreRoute.FilterPins[
pinAry[ DABasics.OtherSide[side]], wireAry[side], globals];
pinAry[side] ← AddMissingPins [frm, side, laySize, pinAry, wireAry[side] ]
ENDLOOP;
frm[row][col].sBox ← MakeSwitchBox[
name:    IO.PutFR["%gSBox%gx%g", IO.rope[name],IO.int[col],IO.int[row]],
routingRect:  [0, 0, laySize.x, laySize.y],
horizLayer:  frm.horizLayer,
vertLayer:  frm.vertLayer,
root:    frm.data.internal,
pinAry:   pinAry,
fastRoute:   CoreProperties.GetCellTypeProp[frm.cellType, $FastRoute]#NIL ]};
ENDLOOP ENDLOOP;
FOR i: NAT IN [0..frm.data.size) DO
CoreRoute.FlushLayPinCache[frm.data[i].type];
CoreRoute.FlushSchPinCache[frm.data[i].type] ENDLOOP;
CoreRoute.FlushSchPinCache[frm.cellType]};
AddMissingPins:  PROC
[frm: MosaicForm, side: Side, laySize: CD.Position, pinAry: WirePinAry, wires: Core.Wires]
RETURNS[new: WirePins ← NIL] = {
range: INT ← (IF side=left OR side=right THEN laySize.y ELSE laySize.x);
layer: CD.Layer ← (IF side=left OR side=right THEN frm.horizLayer ELSE frm.vertLayer);
pins: WirePinspinAry[side];
FOR wires ← wires, wires.rest WHILE wires#NIL DO
size:   INT ← 3*lambda;
space:   INT ← 4*lambda;
spaceEnd: INT ← 8*lambda;
done:   BOOLFALSE;
inMins, inMaxs: BOOLFALSE;
FOR test: WirePins ← pins, test.rest WHILE test#NIL DO
IF test.first.wire=wires.first THEN GOTO Loop REPEAT Loop => LOOP ENDLOOP;
FOR test: WirePins ← pinAry[MinSide[side]], test.rest WHILE test#NIL DO
IF test.first.wire=wires.first THEN
{inMins ← TRUE; size ← MAX[size, test.first.max - test.first.min]} ENDLOOP;
FOR test: WirePins ← pinAry[MaxSide[side]], test.rest WHILE test#NIL DO
IF test.first.wire=wires.first THEN
{inMaxs ← TRUE; size ← MAX[size, test.first.max - test.first.min]} ENDLOOP;
IF NOT (inMins OR inMaxs) THEN ERROR;
IF size=4*lambda AND layer=CMosB.met THEN size ← 3*lambda;
IF size=3*lambda AND layer=CMosB.met2 THEN size ← 4*lambda;
IF inMins
THEN {
IF (pins=NIL) AND (spaceEnd+size+spaceEnd <= range) OR
(pins#NIL) AND (spaceEnd+size+space <= pins.first.min) THEN {
pins ← CONS[[wires.first, spaceEnd, spaceEnd+size, layer], pins];
done ← TRUE};
IF NOT done THEN FOR test: WirePins ← pins, test.rest WHILE test#NIL DO
IF (test.rest=NIL) AND (test.first.max + space+size+spaceEnd <= range) OR
(test.rest#NIL) AND (test.first.max + space+size+space<=test.rest.first.min) THEN{
pos: INT ← test.first.max+space;
test.rest ← CONS[[wires.first, pos, pos+size, layer], test.rest];
done ← TRUE; EXIT} ENDLOOP}
ELSE {
pins ← CoreRoute.ReverseWirePins[pins];
IF (pins=NIL) AND (     spaceEnd+size+spaceEnd <= range) OR
(pins#NIL) AND (pins.first.max + space+size+spaceEnd <= range) THEN {
pins ← CONS[[wires.first, range-size-spaceEnd, range-spaceEnd, layer], pins];
done ← TRUE};
IF NOT done THEN FOR test: WirePins ← pins, test.rest WHILE test#NIL DO
IF (test.rest=NIL) AND (      space+size+spaceEnd <= test.first.min) OR
(test.rest#NIL) AND (test.rest.first.max+space+size+space <= test.first.min) THEN {
pos: INT ← test.first.min- space-size;
test.rest ← CONS[[wires.first, pos, pos+size, layer], test.rest];
done ← TRUE; EXIT} ENDLOOP;
pins ← CoreRoute.ReverseWirePins[pins]};
IF NOT done THEN {
TerminalIO.PutF["\n*** A switchbox in the Mosaic layout: %g does not have enough space in which to put all of the %g side wires. Proceeding returns an incomplete route.\n",
IO.rope[CoreOps.GetCellTypeName[frm.cellType]], IO.rope[SideNm[side]]];
Signal["Insufficient space on switchbox side. See Terminal Viewer."]; EXIT};
ENDLOOP;
RETURN[pins]};
Secondary Procs
EqualWirePins:  PROC[w1, w2: WirePins] RETURNS[equal: BOOLTRUE] = {
DO
IF w1=NIL OR w2=NIL THEN RETURN[w1=w2];
IF w1.first#w2.first THEN RETURN[FALSE];
w1←w1.rest;
w2←w2.rest ENDLOOP};
GetLayoutPins: PROC[frm: MosaicForm, row, col: INT, side: Side, filtered: BOOLFALSE]
RETURNS[wirePins: WirePins ← NIL] = {
layer: CD.Layer ← IF LeftRight[side] THEN frm.horizLayer ELSE frm.vertLayer;
IF row IN [0..frm.size-1) AND col IN [0..frm[0].size-1) THEN {
origin: RowCol ← OriginRowColOf[frm, row, col];
inst: CoreClasses.CellInstance ← frm.data[frm[row][col].ctInst];
temp: WirePins ← IF filtered
THEN CoreRoute.FilteredInstanceLayoutPins[inst, side]
ELSE CoreRoute.LayPins[inst.type, side];
bias: INT ← IF LeftRight[side]
THEN frm[row][col].layPos.y - frm[origin.row][origin.col].layPos.y
ELSE frm[row][col].layPos.x - frm[origin.row][origin.col].layPos.x;
max: INT ← IF LeftRight[side]
THEN frm[row+1][col].layPos.y - frm[row][col].layPos.y
ELSE frm[row][col+1].layPos.x - frm[row][col].layPos.x;
bindings:  RefTab.Ref ← CoreOps.CreateBindingTable[inst.type.public, inst.actual];
FOR temp ← temp, temp.rest WHILE temp#NIL DO
p: WirePin ← [temp.first.wire, temp.first.min-bias, temp.first.max-bias, temp.first.layer];
IF frm.ignoreNWell#NIL AND p.layer=CMosB.nwell THEN LOOP;
IF filtered
THEN {
IF layer=CD.commentLayer THEN {
IF p.layer#CMosB.met AND p.layer#CMosB.met2 THEN LOOP;
IF LeftRight[side] = (p.layer = CMosB.met2)
THEN {frm.horizLayer ← CMosB.met2; frm.vertLayer ← CMosB.met}
ELSE {frm.horizLayer ← CMosB.met; frm.vertLayer ← CMosB.met2};
layer ← IF LeftRight[side] THEN frm.horizLayer ELSE frm.vertLayer};
IF p.layer#layer THEN LOOP}
ELSE IF (p.wire ← NARROW[RefTab.Fetch[bindings, p.wire].val]) = NIL THEN ERROR;
IF p.max <=0  THEN LOOP;
IF p.min >=max THEN EXIT;
wirePins ← CONS[p, wirePins] ENDLOOP;
wirePins ← CoreRoute.ReverseWirePins[wirePins]}};
GetSBBrotherPins: PROC[frm: MosaicForm, row1, col1, row2, col2: INT]
RETURNS[pinAry: WirePinAryALL[NIL]] = {
FOR row: INT IN [row1..row2) DO
bias: INT ← frm[row][col1].layPos.y - frm[row1][col1].layPos.y;
temp: WirePins ← GetLayoutPins[frm, row, col1-1, right, TRUE];
FOR temp ← temp, temp.rest WHILE temp#NIL DO
p: WirePin ← temp.first;
pinAry[left] ← CONS[[p.wire,p.min+bias,p.max+bias,p.layer],pinAry[left]] ENDLOOP;
temp ← GetLayoutPins[frm, row, col2, left, TRUE];
FOR temp ← temp, temp.rest WHILE temp#NIL DO
p: WirePin ← temp.first;
pinAry[right] ← CONS[[p.wire,p.min+bias,p.max+bias,p.layer],pinAry[right]] ENDLOOP;
ENDLOOP;
FOR col: INT IN [col1..col2) DO
bias: INT ← frm[row1][col].layPos.x - frm[row1][col1].layPos.x;
temp: WirePins ← GetLayoutPins[frm, row1-1, col, top, TRUE];
FOR temp ← temp, temp.rest WHILE temp#NIL DO
p: WirePin ← temp.first;
pinAry[bottom]←CONS[[p.wire,p.min+bias,p.max+bias,p.layer],pinAry[bottom]] ENDLOOP;
temp ← GetLayoutPins[frm, row2, col, bottom, TRUE];
FOR temp ← temp, temp.rest WHILE temp#NIL DO
p: WirePin ← temp.first;
pinAry[top] ← CONS[[p.wire,p.min+bias,p.max+bias,p.layer],pinAry[top]] ENDLOOP;
ENDLOOP;
FOR side: Side IN Side DO
pinAry[side] ← CoreRoute.ReverseWirePins[pinAry[side]] ENDLOOP};
GetSBParentWires: PROC[frm: MosaicForm, row1, col1, row2, col2: INT]
RETURNS[wireAry: ARRAY Side OF Wires ← ALL[NIL]] = {
ir: CD.Rect ← CDBasics.ToRect[frm[row1][col1].schPos, frm[row2][col2].schPos];
pir: CD.Rect ← CD.InterestRect[CoreGeometry.GetObject[Sisyph.mode.decoration, frm.cellType]];
ir ← CDBasics.MoveRect[ir, CDBasics.NegOffset[CDBasics.BaseOfRect[pir]]];
IF row1=0 THEN
wireAry[bottom] ← CoreRoute.OrderedAtomicSchWires[frm.cellType, bottom, ir.x1, ir.x2];
IF col1=0 THEN
wireAry[left] ← CoreRoute.OrderedAtomicSchWires[frm.cellType, left, ir.y1, ir.y2];
IF row2=frm.size-1 THEN
wireAry[top]  ← CoreRoute.OrderedAtomicSchWires[frm.cellType, top, ir.x1, ir.x2];
IF col2=frm[0].size-1 THEN
wireAry[right] ← CoreRoute.OrderedAtomicSchWires[frm.cellType, right, ir.y1, ir.y2]};
IsSBox:     PROC[frm: MosaicForm, row, col: INT] RETURNS[BOOL] =
{RETURN[
(row < (frm.size-1)) AND (col < (frm[row].size-1)) AND (frm[row][col].ctInst = -1)]};
LeftRight:    PROC[side: Side] RETURNS[BOOL] =
{RETURN[side=left OR side=right]};
LimitRowColOf:  PROC[frm: MosaicForm, row, col: INT] RETURNS[rowCol: RowCol] = {
rowI: INT ← row;
colI: INT ← col;
FOR row ← row+1, row+1
WHILE row<frm.size-1 AND frm[row-1][colI].ctInst = frm[row][colI].ctInst DO ENDLOOP;
FOR col ← col+1, col+1
WHILE col<frm[row].size-1 AND frm[rowI][col-1].ctInst=frm[rowI][col].ctInst DO ENDLOOP;
RETURN[[row, col]]};
MaxSide:    PROC[side: Side] RETURNS[Side] =
{RETURN[DABasics.OtherSide[MinSide[side]]]};
MinSide:    PROC[side: Side] RETURNS[Side] =
{RETURN[IF LeftRight[side] THEN bottom ELSE left]};
OriginRowColOf:  PROC[frm: MosaicForm, row, col: INT] RETURNS[rowCol: RowCol] = {
FOR row ← row, row-1 WHILE row#0 AND frm[row-1][col].ctInst = frm[row][col].ctInst
DO ENDLOOP;
FOR col ← col, col-1 WHILE col#0 AND frm[row][col-1].ctInst = frm[row][col].ctInst
DO ENDLOOP;
RETURN[[row, col]]};
ShowMosaicForm:  PROC[frm: MosaicForm] = {
TerminalIO.PutF["Mosaic Layout: %g", IO.rope[CoreOps.GetCellTypeName[frm.cellType]]];
TerminalIO.PutF["\n Sch "];
FOR col: INT IN [0..frm[0].size-1) DO
TerminalIO.PutF["%8g", IO.int[frm[0][col].schPos.x]] ENDLOOP;
TerminalIO.PutF["\n Lay "];
FOR col: INT IN [0..frm[0].size-1) DO
TerminalIO.PutF["%8g", IO.int[frm[0][col].layPos.x]] ENDLOOP;
FOR row: INT DECREASING IN [0..frm.size-1) DO
TerminalIO.PutF["\n%8g\n%8g",
IO.int[frm[row][0].schPos.y], IO.int[frm[row][0].layPos.y]];
FOR col: INT IN [0..frm[row].size-1) DO
IF frm[row][col].ctInst#-1
THEN TerminalIO.PutF["%8g", IO.int[frm[row][col].ctInst]]
ELSE TerminalIO.PutRope[" x"] ENDLOOP ENDLOOP;
TerminalIO.PutRope["\n"]};
ShowPins:  PROC[pins: WirePins, root: Wire ← NIL] = {
index: INT ← 0;
FOR pins ← pins, pins.rest WHILE pins#NIL DO
TerminalIO.PutF["%2g: %-20g min:%5g max:%5g %g\n",
IO.int[index],
IO.rope[WireName[pins.first.wire, root]],
IO.int[pins.first.min],
IO.int[pins.first.max],
IO.atom[CD.LayerKey[pins.first.layer]]];
index ← index +1;
ENDLOOP};
ShowWires:  PROC[wires: Wires, root: Wire ← NIL] = {
index: INT ← 0;
FOR wires ← wires, wires.rest WHILE wires#NIL DO
TerminalIO.PutF["%2g: %-20g\n", IO.int[index], IO.rope[WireName[wires.first, root]] ]
ENDLOOP};
SideNm: ARRAY Side OF IO.ROPE
[bottom: "Bottom",  top: "Top",  left: "Left",  right: "Right"];
SizeIntList:    PROC[list: LIST OF INT] RETURNS[size: INT ← 0] =
{FOR list ← list, list.rest WHILE list#NIL DO size ← size+1 ENDLOOP};
SizeLocSchLayList: PROC[list: LIST OF LocSchLay] RETURNS[size: INT ← 0] =
{FOR list ← list, list.rest WHILE list#NIL DO size ← size+1 ENDLOOP};
SortIntList:    PROC[intList: LIST OF INT] = {
TwoInts: TYPE = RECORD[i0, i1: INT];
DO
done: BOOLTRUE;
list: LIST OF INT ← intList;
FOR list ← list, list.rest WHILE list#NIL AND list.rest#NIL DO
SELECT Basics.CompareInt[list.first, list.rest.first] FROM
equal  => {done←FALSE; list.rest ← list.rest.rest};
greater => {done←FALSE; [list.first, list.rest.first] ← TwoInts[list.rest.first, list.first]};
ENDCASE ENDLOOP;
IF done THEN EXIT ENDLOOP};
WireName:  PROC[wire, root: Wire ← NIL] RETURNS[rope: IO.ROPE] = {
RETURN[(IF root#NIL
THEN CoreRoute.LabelInternal[root, wire]
ELSE CoreOps.GetShortWireName[wire])]};
SBox generator
MakeSwitchBox:    PROC[
name:    IO.ROPE,
routingRect:  CD.Rect,
horizLayer:  CD.Layer,
vertLayer:  CD.Layer,
root:    Wire,-- for consistant labels
pinAry:   WirePinAry,
fastRoute:   BOOLFALSE]
RETURNS[switchBox: CD.Object] = {
priority:   CedarProcess.Priority ← CedarProcess.GetPriority[];
rulesParameters: Route.DesignRulesParameters = Route.DefaultDesignRulesParameters[
technologyHint: technologyKey,
horizLayer:  horizLayer,
vertLayer:  vertLayer,
trunkDirection: horizontal];
intermediateResult: Route.IntermediateResult;
nets:     SymTab.Ref ← SymTab.Create[]; -- Label -> NetInfo
FOR side: Side IN Side DO
FOR pins: WirePins ← pinAry[side], pins.rest WHILE pins#NIL DO
netInfo: NetInfo ← FetchNetInfo[nets, root, pins.first.wire];
netInfo.pins ← CONS [[side, pins.first.min, pins.first.max, pins.first.layer], netInfo.pins];
IF pins.first.wire.size#0 THEN ERROR ENDLOOP ENDLOOP;
CedarProcess.CheckAbort[];
CedarProcess.SetPriority[background];
DO
ENABLE Route.Signal => {
TerminalIO.PutF["*** Route switchBox %g preliminary warning:\n %g\n",
IO.rope[name], IO.rope[explanation]];
IF rulesParameters.trunkDirection=horizontal AND (
explanation.Find["Multiple channel exits"]#-1 OR
explanation.Find["unable to find a place to dogleg"]#-1)
THEN {
TerminalIO.PutRope[" Will try again using vertical trunk.\n"];
rulesParameters.trunkDirection ← vertical; LOOP}
ELSERESUME};
intermediateResult ← Route.SwitchBoxRoute[
name:    name,
enumerateNets: EnumerateSwitchBoxNets,
routingRect:  routingRect,
rulesParameters: rulesParameters,
rules:    Route.DefaultDesignRules[rulesParameters],
enumerateObstructions: NIL,
signalSinglePinNets:  FALSE,
signalCoincidentPins: FALSE,
okToDiddleLLPins:  FALSE,
okToDiddleURPins:  FALSE,
optimization:    IF fastRoute THEN noIncompletes ELSE full,
switchBoxData:   nets ];
EXIT ENDLOOP;
CedarProcess.CheckAbort[];
IF intermediateResult=NIL THEN ERROR;
switchBox ← Route.SwitchBoxRetrieve[intermediateResult ! Route.Signal => {
TerminalIO.PutF["*** Route switchBox %g final warning:\n %g\n",
IO.rope[name], IO.rope[explanation]];
RESUME} ].object;
IF switchBox=NIL THEN ERROR;
CedarProcess.SetPriority[priority]};
FetchNetInfo:     PROC[nets: SymTab.Ref, root, wire: Wire]
RETURNS[netInfo: NetInfo] = {
label: Route.Label = CoreRoute.LabelInternal[root, wire];
rw: REF INT = NARROW [CoreProperties.GetWireProp[wire, wireWidthProp]];
netInfo ← NARROW [SymTab.Fetch[nets, label].val];
IF netInfo#NIL THEN RETURN;
netInfo ← NEW [NetInfoRec ← [trunkSize: IF rw=NIL THEN 0 ELSE rw^*lambda]];
[] ← SymTab.Store[nets, label, netInfo]};
EnumerateSwitchBoxNets: Route.EnumerateSwitchBoxNetsProc = {
nets: SymTab.Ref = NARROW [switchBoxData];
EachNet: SymTab.EachPairAction = {
label:  Route.Label = key;
netInfo: NetInfo  = NARROW[val];
eachNet[
name:     label,
enumeratePins:  EnumerateSwitchBoxPins,
trunkSize:   netInfo.trunkSize,
switchBoxData:  NIL,
netData:    netInfo]};
[] ← SymTab.Pairs[nets, EachNet]};
EnumerateSwitchBoxPins: Route.EnumerateSwitchBoxPinsProc = {
netInfo: NetInfo = NARROW [netData];
FOR pins: LIST OF PinInfo ← netInfo.pins, pins.rest WHILE pins#NIL DO
pin: PinInfo = pins.first;
eachPin[
side:  pin.side,
min:  pin.min,
max:  pin.max,
layer:  pin.layer] ENDLOOP };
Register layout atoms
[] ← PWCore.RegisterLayoutAtom
[mosaicLayoutProp, MosaicLayout, MosaicDecorate, MosaicAttributes];
END.