OnionImpl.mesa 
Copyright © 1985 by Xerox Corporation. All rights reversed.
Created by Bertrand Serlet, November 14, 1985 6:45:33 pm PST
Last Edited by: Sindhu, July 7, 1985 1:40:04 am PDT
Barth, January 24, 1986 4:13:24 pm PST
DIRECTORY
CD, CDBasics, CDCells, CDDirectory, CDOrient, CDPinObjects, CDProperties, CDRects, CDSimpleRules,
CMos,
Core, CoreOps,
IO,
Onion, OnionArc,
PW, PWCore, PWPins,
RefTab, Rope,
TerminalIO;
OnionImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCells, CDDirectory, CDOrient, CDPinObjects, CDProperties, CDRects, CDSimpleRules, CMos, CoreOps, IO, OnionArc, PW, PWCore, PWPins, RefTab, Rope, TerminalIO
EXPORTS Onion =
BEGIN OPEN Onion;
defaultLayersParameters: PUBLIC LayersParameters = NEW [LayersParametersRec ← [
radialLayer: CMos.met,
ringLayer: CMos.met2,
ringWidth: RingWidthIs8,
wireExtendProc: WireExtendMetToMet
]];
channelDefaultParameters: PUBLIC LayersParameters = NEW [LayersParametersRec ← [
radialLayer: CMos.met,
ringLayer: CMos.met2,
ringWidth: RingWidthIs8,
wireExtendProc: WireExtendMetToMet
]];
WireExtendMetToMet: PUBLIC WireExtendProc = {
wire ← CDRects.CreateRect[[length, width], CMos.met];
};
WireExtendPolToMetForPads: PUBLIC WireExtendProc = {
nb: INTMAX[8, width]; -- for computing how many!
wire ← CDCells.CreateEmptyCell[];
[] ← PW.IncludeInCell[wire, CDRects.CreateRect[[length-14, width], CMos.met], [0, 0]];
FOR i: INT IN [0 .. nb/8) DO
[] ← PW.IncludeInCell[wire, CDSimpleRules.Contact[CMos.pol, CMos.met], [length-14, 8*i]]
ENDLOOP;
[] ← PW.IncludeInCell[wire, CDRects.CreateRect[[6, width], CMos.pol], [length-6, 0]];
CDCells.SetInterestRect[wire, [0, 0, length, width]];
[] ← CDCells.RepositionCell[wire, NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, wire, "WireExtendPolToMetForPads"];
};
RingWidthIs8: PUBLIC RingWidthProc = {ringWidth ← 8};
Arc: TYPE = OnionArc.Arc;
RotateSide: PROC [side: Side] RETURNS [Side] = {
RETURN [SELECT side FROM
bottom => right,
right  => top,
top  => left,
left  => bottom,
ENDCASE => ERROR];
};
This type is internally used by the implementation and so does not instear in the interface
Net: TYPE = REF NetRec;
NetRec: TYPE = RECORD [
name: ROPENIL,          -- name of the net. Unicity not guaranteed
chosen: BOOLFALSE,         -- chosen for being routed
eval: INT ← 0,            -- evaluation function
arc: Arc ← NIL,           -- arc used by this net
innerPins, outerPins: LIST OF CD.Instance ← NIL-- pins of the net
];
FetchNet: PROC [nets: RefTab.Ref, wire: Wire] RETURNS [net: Net] = {
found: BOOL; val: RefTab.Val;
[found, val] ← RefTab.Fetch[nets, wire];
net ← IF found THEN NARROW [val] ELSE NEW [NetRec];
};
IncludePin: PUBLIC PROC [cell: CD.Object, wire: Wire, layer: CD.Layer, size, position: CD.Position, orientation: CD.Orientation ← 0] RETURNS [newInst: CD.Instance] = {
nets: RefTab.Ref ← NARROW [CDProperties.GetPropFromObject[cell, PWCore.netsProp]];
pins: LIST OF CD.Instance;
newInst ← PW.IncludeInCell[cell: cell, obj: CDPinObjects.CreatePinOb[size], position: position, orientation: orientation].newInst;
pins ← CONS [newInst, NARROW [RefTab.Fetch[nets, wire].val]];
[] ← RefTab.Store[nets, wire, pins];
CDPinObjects.SetLayer[newInst, layer];
CDPinObjects.SetName[newInst, CoreOps.GetShortWireName[wire]];
};
IncludeContact: PUBLIC PROC [cell: CD.Object, side: Side, layer1, layer2: CD.Layer, size: INT, position: CD.Position, orientation: CD.Orientation ← 0] = {
contact: CD.Object ← CDSimpleRules.Contact[layer1, layer2];
contactSize: INT ← contact.size.x; -- **** WRONG
nb: INTMAX[contactSize, size]; -- **** WRONG
FOR i: INT IN [0..nb/contactSize) DO
[] ← PW.IncludeInCell[
cell, contact,
SELECT side FROM
left   => [position.x, position.y+i*contactSize],
right   => [position.x-contactSize, position.y+i*contactSize],
bottom  => [position.x+i*contactSize, position.y],
top   => [position.x+i*contactSize, position.y-contactSize],
ENDCASE => ERROR];
ENDLOOP;
};
Returns the innerPos needed for centering the inner in the outer
Center: PUBLIC PROC [inner, outer: CD.Object] RETURNS [innerPos: CD.Position] = {
innerPos ← CDBasics.SubPoints[
CDBasics.SizeOfRect[CD.InterestRect[outer]],
CDBasics.SizeOfRect[CD.InterestRect[inner]]];
innerPos.x ← innerPos.x/2; innerPos.y ← innerPos.y/2;
};
Extends the wires of obj to make an proper inner. The extension takes into account the layer of outside pins.
MakeInner: PUBLIC PROC [design: CD.Design, obj: CD.Object] RETURNS [inner: CD.Object] = {
dist: INT ← 18; ---????
ExtendPinOnEdge: PWCore.EachNetProc = {
FOR insts: LIST OF CD.Instance ← pins, insts.rest WHILE insts#NIL DO
inst: CD.Instance ← insts.first;
newInst: CD.Instance;
location: CD.Position ← CDBasics.SubPoints[
inst.location, CDBasics.BaseOfRect[CD.InterestRect[obj]]];
realSize: CD.Position ← CDOrient.OrientedSize[inst.ob.size, inst.orientation];
side: Side ← PWPins.GetSide[obj, inst].side;
newInst ← IncludePin[
inner, wire, CMos.met, realSize,
SELECT side FROM
right    => [location.x+dist, location.y],
left    => [location.x-dist, location.y],
top    => [location.x, location.y+dist],
bottom   => [location.x, location.y-dist],
ENDCASE => ERROR];
newApclass.properties ← CDProperties.CopyProps[inst.properties]; -- drole de stuff on layer
[] ← PW.IncludeInCell[
inner,
CDRects.CreateRect[
SELECT side FROM
left, right   => [dist, realSize.y],
top, bottom   => [realSize.x, dist],
ENDCASE   => ERROR,
CDPinObjects.GetLayer[inst]],
SELECT side FROM
left   => [location.x-dist, location.y],
right   => [location.x+realSize.x, location.y],
bottom  => [location.x, location.y-dist],
top   => [location.x, location.y+realSize.y],
ENDCASE => ERROR];
Now the contact(s)!
SELECT CDPinObjects.GetLayer[inst] FROM
CMos.met       => {};
CMos.met2, CMos.pol   => {
IncludeContact[inner, side, CMos.met, CDPinObjects.GetLayer[inst], (SELECT side FROM
left, right   => realSize.y,
bottom, top   => realSize.x,
ENDCASE => ERROR),
SELECT side FROM
left   => [location.x-dist, location.y],
right   => [location.x+realSize.x+dist, location.y],
bottom  => [location.x, location.y-dist],
top   => [location.x, location.y+realSize.y+dist],
ENDCASE => ERROR];
};
ENDCASE       => TerminalIO.WriteRopes["**** MakeInner: Layer unknown for extending pin ", CoreOps.GetShortWireName[wire], ". Extension WRONG!!!\n"];
ENDLOOP;
};
inst: CD.Instance;
inner ← CDCells.CreateEmptyCell[];
CDProperties.PutPropOnObject[inner, PWCore.netsProp, RefTab.Create[]];
inst ← PW.IncludeInCell[inner, obj];
CDProperties.PutPropOnInstance[inst, $StopEnumerateDeepPins, $StopEnumerateDeepPins];
[] ← PWCore.EnumerateNets[PWCore.FindNets[obj], ExtendPinOnEdge];
CDCells.SetInterestRect[inner, CDBasics.Extend[
CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[obj]]], dist]];
[] ← CDCells.RepositionCell[inner, NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, inner, Rope.Cat[CDDirectory.Name[obj], "@MadeInner"]];
};
-- innerPos is the location of the origin of inner in the coord system of outer
LRSRouteOnce: PUBLIC PROC [design: CD.Design, inner, outer: CD.Object, innerPos: CD.Position, params: LayersParameters ← defaultLayersParameters] RETURNS [cell: CD.Object, newInnerPos: CD.Position, status: Status] = {
contactWidth: INT;
innerRect: CD.Rect = CDBasics.MoveRect[CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[inner]]], innerPos]; -- in the outer coord system
Returns the position of the innerPin in the coordinate system of the interestRect of the outer
InnerPinLocation: PROC [pin: CD.Instance] RETURNS [location: CD.Position] = {
location ← CDBasics.AddPoints[CDBasics.SubPoints[pin.location, CDBasics.BaseOfRect[CD.InterestRect[inner]]], innerPos];
};
Returns the position of the outerPin in the coordinate system of the interestRect of the outer
OuterPinLocation: PROC [pin: CD.Instance] RETURNS [location: CD.Position] = {
location ← CDBasics.SubPoints[pin.location, CDBasics.BaseOfRect[CD.InterestRect[outer]]];
};
Returns the bi-projection on the correct side of the innerPin in the coordinate system of the interestRect of the outer. Size of the pin is taken into account so that the pin always represent an extension in the direct rotation.
InnerPinBiProjection: PROC [pin: CD.Instance] RETURNS [min, max: INT] = {
rect: CD.Rect ← CDOrient.RectAt[InnerPinLocation[pin], pin.ob.size, pin.orientation];
SELECT PWPins.GetSide[inner, pin].side FROM
bottom, top  => {min ← rect.x1; max ← rect.x2};
left, right  => {min ← rect.y1; max ← rect.y2};
ENDCASE   => ERROR;
};
Returns the bi-projection on the correct side of the outerPin in the coordinate system of the interestRect of the outer. Size of the pin is taken into account so that the pin always represent an extension in the direct rotation.
OuterPinBiProjection: PROC [pin: CD.Instance] RETURNS [min, max: INT] = {
rect: CD.Rect ← CDOrient.RectAt[OuterPinLocation[pin], pin.ob.size, pin.orientation];
SELECT PWPins.GetSide[outer, pin].side FROM
bottom, top  => {min ← rect.x1; max ← rect.x2};
left, right  => {min ← rect.y1; max ← rect.y2};
ENDCASE   => ERROR;
};
OuterCoordsToCellCoords: PROC [outerPos: CD.Position] RETURNS [cellPos: CD.Position] = {
cellPos ← CDBasics.SubPoints[outerPos, CDBasics.BaseOfRect[assignedArc.rect]];
};
-- Procs for parsing the pins into nets
AddInnerPinToNets: PWCore.EachNetProc = {
net: Net ← FetchNet[nets, wire];
IF net.name=NIL THEN net.name ← CoreOps.GetShortWireName[wire];
FOR insts: LIST OF CD.Instance ← pins, insts.rest WHILE insts#NIL DO
inst: CD.Instance ← insts.first;
name: ROPE ← CDPinObjects.GetName[inst];
IF PWPins.GetSide[inner, inst]=none THEN ERROR;
IF CDPinObjects.GetLayer[inst]#params.radialLayer
THEN TerminalIO.WriteF["*** Inner Pin %g on net %g discarded: not of radialLayer material.\n", IO.rope[name], IO.rope[CoreOps.GetShortWireName[wire]]]
ELSE net.innerPins ← CONS [inst, net.innerPins];
ENDLOOP;
[] ← RefTab.Store[nets, wire, net];
};
AddOuterPinToNets: PWCore.EachNetProc = {
net: Net ← FetchNet[nets, wire];
IF net.name=NIL THEN net.name ← CoreOps.GetShortWireName[wire];
FOR insts: LIST OF CD.Instance ← pins, insts.rest WHILE insts#NIL DO
inst: CD.Instance ← insts.first;
name: ROPE ← CDPinObjects.GetName[inst];
IF PWPins.GetSide[outer, inst]=none THEN ERROR;
IF CDPinObjects.GetLayer[inst]#params.radialLayer
THEN TerminalIO.WriteF["*** Outer Pin %g on net %g discarded: not of radialLayer material.\n", IO.rope[name], IO.rope[CoreOps.GetShortWireName[wire]]]
ELSE net.outerPins ← CONS [inst, net.outerPins];
ENDLOOP;
[] ← RefTab.Store[nets, wire, net];
};
-- Choice of possible nets
Computation of the Arc of a Net
ComputeArc: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = {
net: Net ← NARROW [val];
wire: Wire ← NARROW [key];
pitch: INT = MAX [contactWidth, params.ringWidth[wire]]+CDSimpleRules.MinDist[params.ringLayer, params.ringLayer];
quit ← FALSE;
net.arc ← OnionArc.EmptyArc[CDBasics.Extend[innerRect, pitch]];
FOR innerPins: LIST OF CD.Instance ← net.innerPins, innerPins.rest WHILE innerPins#NIL DO
side: Side ← PWPins.GetSide[inner, innerPins.first].side;
min, max: INT;
[min, max] ← InnerPinBiProjection[innerPins.first];
SELECT side FROM
bottom, right  => max ← MAX[max, min+contactWidth];
top, left    => min ← MIN[min, max-contactWidth];
ENDCASE   => ERROR;
net.arc ← OnionArc.ConnectSegBitToArc[min, max, side, net.arc];
ENDLOOP;
FOR outerPins: LIST OF CD.Instance ← net.outerPins, outerPins.rest WHILE outerPins#NIL DO
side: Side ← PWPins.GetSide[outer, outerPins.first].side;
min, max: INT;
[min, max] ← OuterPinBiProjection[outerPins.first];
SELECT side FROM
bottom, right  => max ← MAX[max, min+contactWidth];
top, left    => min ← MIN[min, max-contactWidth];
ENDCASE   => ERROR;
net.arc ← OnionArc.ConnectSegBitToArc[min, max, side, net.arc];
ENDLOOP;
quit ← FALSE;
};
-- Computation of the evaluation function of a Net, i.e. LAST[INT]/2+Length if there is an innerPin roughly (less than design rules) in front of some outerPin of the net, LAST[INT] if all pins of the net are matching some pins of the same net, Length else. Length is OnionArc.Length[arc]+ Perimeter[Arc.rect].
ComputeEval: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = {
net: Net ← NARROW [val];
allOuterPinsMatchSomeInnerPin: BOOLTRUE;
quit ← FALSE;
FOR outerPins: LIST OF CD.Instance ← net.outerPins, outerPins.rest WHILE outerPins#NIL DO
matches: BOOLFALSE;
FOR innerPins: LIST OF CD.Instance ← net.innerPins, innerPins.rest WHILE innerPins#NIL DO
IF Faces[innerPins.first, outerPins.first] THEN {matches ← TRUE; EXIT};
ENDLOOP;
IF ~matches THEN {allOuterPinsMatchSomeInnerPin ← FALSE; EXIT};
ENDLOOP;
IF allOuterPinsMatchSomeInnerPin THEN {net.eval ← LAST[INT]; RETURN};
net.eval ← OnionArc.Length[net.arc] + net.arc.rect.x2 - net.arc.rect.x1 + net.arc.rect.y2 - net.arc.rect.y1;
FOR outerPins: LIST OF CD.Instance ← net.outerPins, outerPins.rest WHILE outerPins#NIL DO
FindDifferentNetFacing: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = {
thisNet: Net ← NARROW[val];
quit ← FALSE;
IF thisNet=net THEN RETURN;
FOR innerPins: LIST OF CD.Instance ← thisNet.innerPins, innerPins.rest WHILE innerPins#NIL DO
IF RoughlyFaces[innerPins.first, outerPins.first] THEN {quit ← TRUE; RETURN};
ENDLOOP;
};
We look if a different net is facing
IF RefTab.Pairs[nets, FindDifferentNetFacing]
THEN {net.eval ← net.eval + LAST [INT] /2; RETURN};
ENDLOOP;
};
-- Given two pins, checks if they faces each other
Faces: PROC [innerPin, outerPin: CD.Instance] RETURNS [faces: BOOL] = {
side: Side ← PWPins.GetSide[inner, innerPin].side;
faces ← side=PWPins.GetSide[outer, outerPin].side AND OuterPinBiProjection[outerPin]=InnerPinBiProjection[innerPin];
};
-- Given two pins, checks if they faces each other, taking into account design rules
RoughlyFaces: PROC [innerPin, outerPin: CD.Instance] RETURNS [faces: BOOL] = {
side: Side ← PWPins.GetSide[inner, innerPin].side;
innerMin, innerMax, outerMin, outerMax: INT;
[innerMin, innerMax] ← InnerPinBiProjection[innerPin];
[outerMin, outerMax] ← OuterPinBiProjection[outerPin];
innerMax ← MAX [innerMax, innerMin + contactWidth] + CDSimpleRules.MinDist[params.ringLayer, params.ringLayer];
outerMax ← MAX [outerMax, outerMin + contactWidth] + CDSimpleRules.MinDist[params.ringLayer, params.ringLayer];
faces ← side=PWPins.GetSide[outer, outerPin].side AND (innerMin IN [outerMin .. outerMax] OR outerMin IN [innerMin .. innerMax]);
};
ChooseMinEval: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = {
net: Net ← NARROW [val];
wire: Wire ← NARROW [key];
quit ← FALSE;
IF net.chosen OR net.eval>minEval OR net.eval=LAST [INT] THEN RETURN;
IF assignedArc#NIL AND (net.eval>=LAST[INT]/2 OR ~CDBasics.Inside[net.arc.rect, assignedArc.rect] OR ~OnionArc.NotOverlinsting[assignedArc, net.arc, CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] OR params.ringWidth[wire]#netRingWidth) THEN RETURN;
minEval ← net.eval; minNet ← net; minKey ← wire;
};
-- Generation of the geometry
Same as PW.IncludeInCell, but takes into account the size of the object and the side in which they are inserted. Also converts position which is given in the outer cell coord system.
IncludeInCellSide: PROC [ob: CD.Object, side: Side, position: CD.Position, orientation: CD.Orientation ← 0] = {
position ← OuterCoordsToCellCoords[position];
SELECT side FROM
left  => position.y ← position.y-ob.size.y;
right  => position.x ← position.x-ob.size.x;
bottom => {};
top  => {position.x ← position.x-ob.size.x; position.y ← position.y-ob.size.y};
ENDCASE => ERROR;
[] ← PW.IncludeInCell[cell: cell, obj: ob, position: position, orientation: orientation];
};
IncludePinSide: PROC [wire: Wire, side: Side, size, position: CD.Position] = {
pinDeep: INT ← 2;
position ← OuterCoordsToCellCoords[position];
SELECT side FROM
left  => position.y ← position.y-size.y;
right  => position.x ← position.x-size.x;
bottom => {};
top  => {position.x ← position.x-size.x; position.y ← position.y-size.y};
ENDCASE => ERROR;
[] ← IncludePin[cell, wire, params.radialLayer, size, position];
};
IncludeContactSide: PROC [side: Side, size: INT, position: CD.Position] = {
nb: INTMAX[contactWidth, size];
FOR i: INT IN [0..nb/contactWidth) DO
IncludeInCellSide[CDSimpleRules.Contact[params.radialLayer, params.ringLayer], side,
SELECT side FROM
left   => [position.x, position.y-contactWidth*i],
right   => [position.x, position.y+contactWidth*i],
bottom  => [position.x+contactWidth*i, position.y],
top   => [position.x-contactWidth*i, position.y],
ENDCASE => ERROR];
ENDLOOP
};
DrawRingBit: OnionArc.EachSegBitProc -- [min: D2Basic.Number, max: D2Basic.Number, side: Onion.Side] -- = {
SELECT side FROM
bottom => [] ← PW.IncludeInCell[cell, CDRects.CreateRect[[max-min, netRingWidth], params.ringLayer], [min-assignedArc.rect.x1, 0]];
right  => [] ← PW.IncludeInCell[cell, CDRects.CreateRect[[netRingWidth, max-min], params.ringLayer], [assignedArc.rect.x2-assignedArc.rect.x1-netRingWidth, min-assignedArc.rect.y1]];
top  => [] ← PW.IncludeInCell[cell, CDRects.CreateRect[[max-min, netRingWidth], params.ringLayer], [min-assignedArc.rect.x1, assignedArc.rect.y2-assignedArc.rect.y1-netRingWidth]];
left  => [] ← PW.IncludeInCell[cell, CDRects.CreateRect[[netRingWidth, max-min], params.ringLayer], [0, min-assignedArc.rect.y1]];
ENDCASE => ERROR;
};
DepositOuterContacts: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = {
DrawOuterPin: PROC [inst: CD.Instance, wire: Wire] = {
Add a contact and a pin
side: Side ← PWPins.GetSide[outer, inst].side;
size: CD.Position ← CDOrient.OrientedSize[inst.ob.size, inst.orientation];
position: CD.Position ← OuterPinLocation[inst];
pos: CD.Position ← SELECT side FROM
left   => [assignedArc.rect.x1, position.y + size.y],
right   => [assignedArc.rect.x2, position.y],
bottom  => [position.x, assignedArc.rect.y1],
top   => [position.x + size.x, assignedArc.rect.y2],
ENDCASE => ERROR;
IncludeContactSide[side, (SELECT side FROM
left, right   => size.y,
bottom, top   => size.x,
ENDCASE => ERROR), pos];
IncludePinSide[wire, side, size, pos];
};
net: Net ← NARROW [val];
wire: Wire ← NARROW [key];
quit ← FALSE;
IF ~net.chosen THEN {IF net.eval#LAST[INT] THEN TerminalIO.WriteRopes[net.name, " "]; RETURN};
FOR outerPins: LIST OF CD.Instance ← net.outerPins, outerPins.rest WHILE outerPins#NIL DO
DrawOuterPin[outerPins.first, wire];
ENDLOOP;
};
Draws wires in metal for inner pins, and if the pin belongs to the net, then add a contact, else add a pin.
DepositInnerWiresEtAl: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = {
DrawInnerPin: PROC [inst: CD.Instance, chosen: BOOL, wire: Wire] = {
side: Side ← PWPins.GetSide[inner, inst].side;
size: CD.Position ← CDOrient.OrientedSize[inst.ob.size, inst.orientation];
rectSize: CD.Position ← size;
pos: CD.Position; -- base of wire in the outer coord system
position: CD.Position ← InnerPinLocation[inst];
SELECT side FROM
left => {
pos ← [assignedArc.rect.x1, position.y + size.y]; -- origin of wire and Al in the outer coord system
rectSize.x ← innerRect.x1-assignedArc.rect.x1;
};
right => {
pos ← [assignedArc.rect.x2, position.y]; -- origin of wire and Al in the outer coord system
rectSize.x ← assignedArc.rect.x2-innerRect.x2;
};
bottom => {
pos ← [position.x, assignedArc.rect.y1]; -- origin of wire and Al in the outer coord system
rectSize.y ← innerRect.y1-assignedArc.rect.y1;
};
top => {
pos ← [position.x + size.x, assignedArc.rect.y2]; -- origin of wire and Al in the outer coord system
rectSize.y ← assignedArc.rect.y2-innerRect.y2;
};
ENDCASE => ERROR;
IF rectSize.x#0 AND rectSize.y#0 THEN IncludeInCellSide[CDRects.CreateRect[rectSize, params.radialLayer], side, pos];
IF chosen
THEN -- add contact(s)
IncludeContactSide[side, (SELECT side FROM
left, right   => size.y,
bottom, top   => size.x,
ENDCASE => ERROR), pos]
ELSE -- add a pin -- IncludePinSide[wire, side, size, pos];
};
net: Net ← NARROW [val];
wire: Wire ← NARROW [key];
quit ← FALSE;
FOR innerPins: LIST OF CD.Instance ← net.innerPins, innerPins.rest WHILE innerPins#NIL DO
DrawInnerPin[innerPins.first, net.chosen, wire];
ENDLOOP;
};
ExtendAllWires: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = {
net: Net ← NARROW [val];
quit ← FALSE;
IF net.outerPins#NIL AND net.outerPins.rest=NIL AND net.innerPins=NIL
THEN RETURN; -- only 1 outerPin and 0 innerPin
FOR outerPins: LIST OF CD.Instance ← net.outerPins, outerPins.rest WHILE outerPins#NIL DO
FOR innerPins: LIST OF CD.Instance ← net.innerPins, innerPins.rest WHILE innerPins#NIL DO
IF Faces[innerPins.first, outerPins.first] THEN {
innerPos: CD.Position ← InnerPinLocation[innerPins.first];
outerPos: CD.Position ← OuterPinLocation[outerPins.first];
innerSize: CD.Position ← CDOrient.OrientedSize[innerPins.first.ob.size, innerPins.first.orientation];
outerSize: CD.Position ← CDOrient.OrientedSize[outerPins.first.ob.size, outerPins.first.orientation];
side: Side ← PWPins.GetSide[inner, innerPins.first].side;
length: INTSELECT side FROM
left  => innerPos.x - outerPos.x - outerSize.x,
right  => outerPos.x - innerPos.x - innerSize.x,
bottom => innerPos.y - outerPos.y - outerSize.y,
top  => outerPos.y - innerPos.y - innerSize.y,
ENDCASE => ERROR;
width: INTSELECT side FROM
left, right  => MIN[innerSize.y, outerSize.y],
bottom, top  => MIN[innerSize.x, outerSize.x],
ENDCASE => ERROR;
wire: CD.Object ← params.wireExtendProc[design, width, length];
[] ← PW.IncludeInCell[
cell: cell, obj: wire,
position: SELECT side FROM
left  => [outerPos.x + outerSize.x, outerPos.y],
right  => [outerPos.x - length, outerPos.y],
bottom => [outerPos.x, outerPos.y + outerSize.y],
top  => [outerPos.x, outerPos.y - length],
ENDCASE => ERROR,
orientation: SELECT side FROM
left  => CDOrient.rotate180,
right  => CDOrient.original,
bottom => CDOrient.rotate270,
top  => CDOrient.rotate90,
ENDCASE => ERROR
];
EXIT;
};
ENDLOOP;
ENDLOOP;
};
assignedArc: Arc ← NIL;
nets: RefTab.Ref ← RefTab.Create[];
minEval: INT; minNet: Net; minKey: Wire; -- for choosing the nets
netRingWidth: INT ← 0; -- all nets on the same track have the same width
cell ← CDCells.CreateEmptyCell[];
CDProperties.PutPropOnObject[cell, PWCore.netsProp, RefTab.Create[]];
can we find the minimal size of a contact
IF CDSimpleRules.Contact[params.radialLayer, params.ringLayer]=NIL THEN {
TerminalIO.WriteRope["ImpossibleTechnology: I do not know how to contact radialLayer and ringLayer!\n"]; ERROR;
};
contactWidth ← CDBasics.SizeOfRect[CD.InterestRect[CDSimpleRules.Contact[params.radialLayer, params.ringLayer]]].x; -- ****** ??W?!?!?!?? WRONG!
-- Emergency break
IF ~CDBasics.Inside[innerRect, CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[outer]]]] THEN {TerminalIO.WriteRope["**** Routing Impossible (Too big) ****\n**** Current state returned! ****\n"]; RETURN[inner, innerPos, impossible];};
-- Parsing all the pins to sort them by nets
[] ← PWCore.EnumerateNets[PWCore.FindNets[inner], AddInnerPinToNets];
[] ← PWCore.EnumerateNets[PWCore.FindNets[outer], AddOuterPinToNets];
-- We delete all nets containing only 1 pin
BEGIN
deletedNets: LIST OF Wire ← NIL;
ToBeDeleted: RefTab.EachPairAction -- [key: RefTab.Key, val: RefTab.Val] RETURNS [quit: BOOL] -- = {
wire: Wire ← NARROW [key];
net: Net ← NARROW [val];
quit ← FALSE;
IF (net.innerPins#NIL AND net.innerPins.rest=NIL AND net.outerPins=NIL) OR (net.outerPins#NIL AND net.outerPins.rest=NIL AND net.innerPins=NIL) THEN deletedNets ← CONS [wire, deletedNets];
};
[] ← RefTab.Pairs[nets, ToBeDeleted];
WHILE deletedNets#NIL DO
TerminalIO.WriteRopes["*** Net: ", CoreOps.GetShortWireName[deletedNets.first], " has only 1 pin. Not routed\n"];
[] ← RefTab.Delete[nets, deletedNets.first]; deletedNets ← deletedNets.rest;
ENDLOOP;
END;
-- We compute the Arc necessited by the net for being routed
[] ← RefTab.Pairs[nets, ComputeArc];
We compute evaluation function, i.e. LAST[INT]/2+Length[Arc] if there is an innerPin in front of some outerPin of the net, LAST[INT] if all pins of the net are matching some pins of the same net, Length[Arc] else.
[] ← RefTab.Pairs[nets, ComputeEval];
We choose the mininum of this evaluation function over each non-chosen net non intersecting (using the design rules) assignedArc and being inside assignedArc.rect (only if someNetAssigned), set assignedArc to the corresponding value, and set the chosen bit of the chosen net. We start again and again until no more net is found.
TerminalIO.WriteRope["Allocating a new track\n"];
DO
Count: PROC [pins: LIST OF CD.Instance] RETURNS [count: INT ← 0] = {
WHILE pins#NIL DO count ← count+1; pins ← pins.rest ENDLOOP;
};
minEval ← LAST [INT]; minNet ← NIL;
[] ← RefTab.Pairs[nets, ChooseMinEval];
IF minEval=LAST [INT] THEN EXIT;
IF minEval>=LAST [INT]/2 THEN TerminalIO.WriteRope["****** ROUTING IS WRONG: at least 2 different nets are facing each other. No cure possible until Dogleg is introduced in Onion!\n"];
IF assignedArc=NIL THEN netRingWidth ← params.ringWidth[minKey];
assignedArc ← IF assignedArc=NIL THEN minNet.arc ELSE OnionArc.Union[assignedArc, minNet.arc];
minNet.chosen ← TRUE;
TerminalIO.WriteF["Routing the net : %g innerPins: %g outerPins: %g Cost: %g\n", IO.rope[minNet.name], IO.int[Count[minNet.innerPins]], IO.int[Count[minNet.outerPins]], IO.int[minNet.eval]];
ENDLOOP;
-- We now generate geometry
IF assignedArc=NIL THEN {
Finished: now we extend all the wires using the wireExtendProc
IF params.wireExtendProc#NIL THEN [] ← RefTab.Pairs[nets, ExtendAllWires];
And we position the inner cell
[] ← PW.IncludeInCell[cell, inner, innerPos];
IF params.wireExtendProc#NIL THEN [] ← PW.IncludeInCell[cell, outer, [0, 0]];
[] ← CDCells.RepositionCell[cell, NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, cell, "LastRoutingRing"];
RETURN[cell, [0, 0], finishedAll];
}
ELSE {
-- We shrink the assignedArc.rect if some sides are unused
IF OnionArc.NotOverlinsting[assignedArc, NEW[OnionArc.ArcRec ← [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec ← [assignedArc.rect.y2, assignedArc.rect.y1, left, left]]]]],
CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] THEN assignedArc.rect.x1 ← innerRect.x1;
IF OnionArc.NotOverlinsting[assignedArc, NEW[OnionArc.ArcRec ← [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec ← [assignedArc.rect.y1, assignedArc.rect.y2, right, right]]]]], CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] THEN assignedArc.rect.x2 ← innerRect.x2;
IF OnionArc.NotOverlinsting[assignedArc, NEW[OnionArc.ArcRec ← [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec ← [assignedArc.rect.x1, assignedArc.rect.x2, bottom, bottom]]]]], CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] THEN assignedArc.rect.y1 ← innerRect.y1;
IF OnionArc.NotOverlinsting[assignedArc, NEW[OnionArc.ArcRec ← [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec ← [assignedArc.rect.x2, assignedArc.rect.x1, top, top]]]]], CDSimpleRules.MinDist[params.ringLayer, params.ringLayer]+contactWidth] THEN assignedArc.rect.y2 ← innerRect.y2;
-- We position the inner cell
CDProperties.PutPropOnInstance[
PW.IncludeInCell[cell, inner, CDBasics.SubPoints[
CDBasics.BaseOfRect[innerRect],
CDBasics.BaseOfRect[assignedArc.rect]]],
$StopEnumerateDeepPins, $StopEnumerateDeepPins];
-- We place the sides of the routing (in metal2)
OnionArc.EnumerateSegBits[assignedArc, DrawRingBit];
-- We deposit contacts facing the outer pins which touch the routing ring. By the way we print the names of non-chosen nets
TerminalIO.WriteRope["Non routed nets: "];
[] ← RefTab.Pairs[nets, DepositOuterContacts];
TerminalIO.WriteRope["\n"];
-- We deposit wires in metal for inner pins and if the pin belongs to the net, then add a contact, else add a pin.
[] ← RefTab.Pairs[nets, DepositInnerWiresEtAl];
-- We reposition and include in the design
CDCells.SetInterestRect[cell, [0, 0, assignedArc.rect.x2-assignedArc.rect.x1, assignedArc.rect.y2-assignedArc.rect.y1]];
[] ← CDCells.RepositionCell[cell, NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, cell, "RoutingRing-"];
RETURN[cell, CDBasics.BaseOfRect[assignedArc.rect], doneOnce];
};
};
LRSRoute: PUBLIC PROC [design: CD.Design, inner, outer: CD.Object, innerPos: CD.Position, params: LayersParameters ← defaultLayersParameters] RETURNS [cell: CD.Object, status: Status] = {
status ← doneOnce;
WHILE status=doneOnce DO
[inner, innerPos, status] ← LRSRouteOnce[design, inner, outer, innerPos, params];
ENDLOOP;
cell ← inner;
};
SwitchBox: PUBLIC PROC [design: CD.Design, bottomOb, rightOb, topOb, leftOb: CD.Object, params: LayersParameters ← channelDefaultParameters] RETURNS [cell: CD.Object, status: Status] = {
inner: CD.Object ← CDCells.CreateEmptyCell[];
outer: CD.Object ← CDCells.CreateEmptyCell[];
currentSide: Side; currentOb: CD.Object;
size: CD.Position ← [
MAX[
CDBasics.SizeOfRect[CD.InterestRect[bottomOb]].x,
CDBasics.SizeOfRect[CD.InterestRect[topOb]].x],
MAX[
CDBasics.SizeOfRect[CD.InterestRect[rightOb]].y,
CDBasics.SizeOfRect[CD.InterestRect[leftOb]].y]];
AddPin: PWPins.InstanceEnumerator -- [inst: CD.Instance] RETURNS [quit: BOOL ← FALSE] -- = {
name: ROPE ← CDPinObjects.GetName[inst];
realSize: CD.Position ← CDOrient.OrientedSize[inst.ob.size, inst.orientation];
location: CD.Position ← CDBasics.SubPoints[inst.location, CDBasics.BaseOfRect[CD.InterestRect[currentOb]]];
IF PWPins.GetSide[currentOb, inst].side#RotateSide[RotateSide[currentSide]] THEN RETURN;
IF CDPinObjects.GetLayer[inst]#params.radialLayer THEN {
TerminalIO.WriteRope["*** Pin ", name, " discarded: not of radialLayer material.\n"] ;
RETURN;
};
[] ← IncludePin[outer, name, CDPinObjects.GetLayer[inst], realSize, SELECT currentSide FROM
bottom => [location.x, 0],
top  => [location.x, size.y-realSize.y],
left  => [0, location.y],
right  => [size.x-realSize.x, location.y],
ENDCASE   => ERROR];
};
[] ← PW.IncludeInCell[inner, CDRects.CreateRect[[8, 8], params.ringLayer]];
[] ← CDCells.RepositionCell[inner, NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, inner, "EmptyCellForHeartOfSwitchBox"];
currentSide ← bottom; currentOb ← bottomOb;
[] ← PWPins.EnumerateEdgePins[currentOb, AddPin];
currentSide ← top; currentOb ← topOb;
[] ← PWPins.EnumerateEdgePins[currentOb, AddPin];
currentSide ← left; currentOb ← leftOb;
[] ← PWPins.EnumerateEdgePins[currentOb, AddPin];
currentSide ← right; currentOb ← rightOb;
[] ← PWPins.EnumerateEdgePins[currentOb, AddPin];
CDCells.SetInterestRect[outer, [0, 0, size.x, size.y]];
[] ← CDCells.RepositionCell[outer, NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, outer, "EmptyCellForSkinOfSwitchBox"];
[cell, status] ← LRSRoute[design, inner, outer, Center[inner, outer], params];
};
Channel: PUBLIC PROC [design: CD.Design, left, right: CD. Object, size: INT, params: LayersParameters ← channelDefaultParameters] RETURNS [cell: CD.Object, status: Status] = {
top: CD.Object ← CDCells.CreateEmptyCell[];
[] ← PW.IncludeInCell[top, CDRects.CreateRect[[size, 8], params.ringLayer]];
[] ← CDCells.RepositionCell[top, NIL];
IF design#NIL THEN [] ← CDDirectory.Include[design, top, "EmptyTopForChannel"];
[cell, status] ← SwitchBox[design, top, right, top, left, params];
};
END.