OnionImpl:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDCells, CDDirectory, CDOrient, CDPinObjects, CDProperties, CDRects, CDX, CMos, CMosContacts, OnionArc, Convert, PWPins, Rope, SymTab, TerminalIO
EXPORTS Onion =
BEGIN OPEN Onion;
left: PWPins.Side = PWPins.left; right: PWPins.Side = PWPins.right; top: PWPins.Side = PWPins.top; bottom: PWPins.Side = PWPins.bottom;
Output:
PROC [r1, r2, r3, r4, r5, r6, r7, r8:
ROPE ←
NIL] = {
TerminalIO.WriteRope[Rope.Cat[Rope.Cat[r1, r2, r3, r4], Rope.Cat[r5, r6, r7, r8]]];
};
defaultLayersParameters:
PUBLIC LayersParameters =
NEW [LayersParametersRec ← [
radialLayer: CMos.met,
ringLayer: CMos.met2,
ringWidth: RingWidthIs8,
contact: CMosContacts.CreateMmCon[10],
ringRingDist: 8,
wireExtendProc: WireExtendMetToMet
]];
channelDefaultParameters:
PUBLIC LayersParameters =
NEW [LayersParametersRec ← [
radialLayer: CMos.met,
ringLayer: CMos.met2,
ringWidth: RingWidthIs8,
contact: CMosContacts.CreateMmCon[10],
ringRingDist: 8,
wireExtendProc: WireExtendMetToMet
]];
WireExtendMetToMet:
PUBLIC WireExtendProc = {
wire ← CDRects.CreateRect[[length, width], CMos.met];
};
WireExtendPolToMetForPads:
PUBLIC WireExtendProc = {
nb: INT ← MAX[8, width]; -- for computing how many!
wire ← CDCells.CreateEmptyCell[];
[] ← IncludeOb[wire, CDRects.CreateRect[[length-14, width], CMos.met], [0, 0]];
FOR i:
INT
IN [0 .. nb/8)
DO
[] ← IncludeOb[wire, CMosContacts.CreatePolyCon[8], [length-14, 8*i]]
ENDLOOP;
[] ← IncludeOb[wire, CDRects.CreateRect[[6, width], CMos.pol], [length-6, 0]];
CDCells.SetInterestRect[wire, [0, 0, length, width]];
[] ← CDCells.RepositionCell[wire, NIL];
[] ← CDDirectory.Include[design, wire, "WireExtendPolToMetForPads"];
};
RingWidthIs8: PUBLIC RingWidthProc = {ringWidth ← 8};
Arc: TYPE = OnionArc.Arc;
This type is internally used by the implementation and so does not appear in the interface
Net: TYPE = REF NetRec;
NetRec:
TYPE =
RECORD [
chosen: BOOL ← FALSE, -- chosen for being routed
eval: INT ← 0, -- evaluation function
arc: Arc ← NIL, -- arc used by this net
innerPins, outerPins: LIST OF CD.ApplicationPtr ← NIL -- pins of the net
];
FetchNet:
PROC [nets: SymTab.Ref, name:
ROPE]
RETURNS [net: Net] = {
found: BOOL; val: SymTab.Val;
[found, val] ← SymTab.Fetch[nets,name];
net ← IF found THEN NARROW[val] ELSE NEW[NetRec];
};
StoreNet:
PROC [nets: SymTab.Ref, name:
ROPE, net: Net] = {
[] ← SymTab.Store[nets, name, net];
};
Some of this is also temporary
IncludeOb:
PUBLIC
PROC [cell, ob:
CD.ObPtr, position:
CD.Position ← [0, 0], orientation:
CD.Orientation ← 0]
RETURNS [newApp:
CD.ApplicationPtr] = {
newApp ← CDX.IncludeOb[cell: cell, ob: ob, position: position, cellCSystem: interrestCoords, obCSystem: interrestCoords, mode: dontPropagate, orientation: orientation].newApp;
};
IncludePin:
PUBLIC
PROC [cell:
CD.ObPtr, name:
ROPE, layer:
CD.Layer, size, position:
CD.Position, orientation:
CD.Orientation ← 0]
RETURNS [newApp:
CD.ApplicationPtr] = {
newApp ← IncludeOb[cell: cell, ob: CDPinObjects.CreatePinOb[size], position: position, orientation: orientation].newApp;
CDPinObjects.SetName[newApp, name];
CDPinObjects.SetLayer[newApp, layer];
};
Returns the innerPos needed for centering the inner in the outer
Center:
PUBLIC
PROC [inner, outer:
CD.ObPtr]
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.ObPtr]
RETURNS [inner:
CD.ObPtr] = {
dist: INT ← 18; ---????
ExtendPinOnEdge: PWPins.AppEnumerator
-- [app: CD.ApplicationPtr] RETURNS [quit: BOOL ← FALSE] -- = {
newApp: CD.ApplicationPtr;
location:
CD.Position ← CDBasics.SubPoints[
app.location, CDBasics.BaseOfRect[CD.InterestRect[obj]]];
realSize: CD.Position ← CDOrient.OrientedSize[app.ob.size, app.orientation];
side: PWPins.Side ← PWPins.GetSide[obj, app].side;
newApp ← IncludePin[
inner, CDPinObjects.GetName[app], 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];
newApp.properties ← CDProperties.CopyProps[app.properties]; -- drole de stuff on layer
[] ← IncludeOb[
inner,
CDRects.CreateRect[
SELECT side
FROM
left, right => [dist, realSize.y],
top, bottom => [realSize.x, dist],
ENDCASE => ERROR,
CDPinObjects.GetLayer[app]],
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[app]
FROM
CMos.met => {};
CMos.met2 => {
nb:
INT ←
MAX[10, (
SELECT side
FROM
left, right => realSize.y,
bottom, top => realSize.x,
ENDCASE => ERROR)];
FOR i:
INT
IN [0..nb/10)
DO
[] ← IncludeOb[
inner, CMosContacts.CreateMmCon[10],
SELECT side
FROM
left => [location.x-dist, location.y+i*10],
right => [location.x-10+realSize.x+dist, location.y+i*10],
bottom => [location.x+i*10, location.y-dist],
top => [location.x+i*10, location.y-10+realSize.y+dist],
ENDCASE => ERROR];
ENDLOOP;
};
CMos.pol => {
nb:
INT ←
MAX[8, (
SELECT side
FROM
left, right => realSize.y,
bottom, top => realSize.x,
ENDCASE => ERROR)];
FOR i:
INT
IN [0..nb/8)
DO
[] ← IncludeOb[
inner, CMosContacts.CreatePolyCon[8],
SELECT side
FROM
left => [location.x-dist, location.y+i*8],
right => [location.x-8+realSize.x+dist, location.y+i*8],
bottom => [location.x+i*8, location.y-dist],
top => [location.x+i*8, location.y-8+realSize.y+dist],
ENDCASE => ERROR];
ENDLOOP;
};
ENDCASE => Output["**** MakeInner: Layer unknowm for extending pin ", CDPinObjects.GetName[app], ". Extension WRONG!!!\n"];
};
app: CD.ApplicationPtr;
inner ← CDCells.CreateEmptyCell[];
app ← IncludeOb[inner, obj];
CDProperties.PutPropOnApplication[app, $StopEnumerateDeepPins, $StopEnumerateDeepPins];
[] ← PWPins.EnumerateEdgePins[obj, ExtendPinOnEdge];
CDCells.SetInterestRect[inner, CDBasics.Extend[
CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[obj]]], dist]];
[] ← CDCells.RepositionCell[inner, NIL];
[] ← 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.ObPtr, innerPos:
CD.Position, params: LayersParameters ← defaultLayersParameters]
RETURNS [cell:
CD.ObPtr, newInnerPos:
CD.Position, status: Status] = {
contactWidth: INT ← params.contact.size.x;
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.ApplicationPtr]
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.ApplicationPtr]
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.ApplicationPtr]
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.ApplicationPtr]
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: PWPins.AppEnumerator
-- [app: CD.ApplicationPtr] RETURNS [quit: BOOL ← FALSE] -- = {
name: ROPE ← CDPinObjects.GetName[app];
net: Net ← FetchNet[nets, name];
IF CDPinObjects.GetLayer[app]#params.radialLayer
THEN Output["*** Pin ", name, " discarded: not of radialLayer material.\n"]
ELSE net.innerPins ← CONS[app, net.innerPins];
StoreNet[nets, name, net];
};
AddOuterPinToNets: PWPins.AppEnumerator
-- [app: CD.ApplicationPtr] RETURNS [quit: BOOL ← FALSE] -- = {
name: ROPE ← CDPinObjects.GetName[app];
net: Net ← FetchNet[nets, name];
net.outerPins ← CONS[app, net.outerPins];
StoreNet[nets, name, net];
};
-- Choice of possible nets
Computation of the Arc of a Net
ComputeArc: SymTab.EachPairAction
-- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = {
net: Net ← NARROW [val];
pitch: INT = MAX[contactWidth, params.ringWidth[key]]+params.ringRingDist;
net.arc ← OnionArc.EmptyArc[CDBasics.Extend[innerRect, pitch]];
FOR innerPins:
LIST
OF
CD.ApplicationPtr ← net.innerPins, innerPins.rest
WHILE innerPins#
NIL
DO
side: PWPins.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.ApplicationPtr ← net.outerPins, outerPins.rest
WHILE outerPins#
NIL
DO
side: PWPins.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: SymTab.EachPairAction
-- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = {
net: Net ← NARROW [val];
allOuterPinsMatchSomeInnerPin: BOOL ← TRUE;
quit ← FALSE;
FOR outerPins:
LIST
OF
CD.ApplicationPtr ← net.outerPins, outerPins.rest
WHILE outerPins#
NIL
DO
matches: BOOL ← FALSE;
FOR innerPins:
LIST
OF
CD.ApplicationPtr ← 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.ApplicationPtr ← net.outerPins, outerPins.rest
WHILE outerPins#
NIL
DO
FindDifferentNetFacing: SymTab.EachPairAction
-- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = {
thisNet: Net ← NARROW[val];
quit ← FALSE;
IF thisNet=net THEN RETURN;
FOR innerPins:
LIST
OF
CD.ApplicationPtr ← 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 SymTab.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.ApplicationPtr]
RETURNS [faces:
BOOL] = {
side: PWPins.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.ApplicationPtr]
RETURNS [faces:
BOOL] = {
side: PWPins.Side ← PWPins.GetSide[inner, innerPin].side;
innerMin, innerMax, outerMin, outerMax: INT;
[innerMin, innerMax] ← InnerPinBiProjection[innerPin];
[outerMin, outerMax] ← OuterPinBiProjection[outerPin];
innerMax ← MAX [innerMax, innerMin + contactWidth] + params.ringRingDist;
outerMax ← MAX [outerMax, outerMin + contactWidth] + params.ringRingDist;
faces ← side=PWPins.GetSide[outer, outerPin].side AND (innerMin IN [outerMin .. outerMax] OR outerMin IN [innerMin .. innerMax]);
};
ChooseMinEval: SymTab.EachPairAction
-- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = {
net: Net ← NARROW [val];
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.NotOverlapping[assignedArc, net.arc, params.ringRingDist+contactWidth] OR params.ringWidth[key]#netRingWidth) THEN RETURN;
minEval ← net.eval; minNetName ← key;
};
-- Generation of the geometry
Same as IncludeOb, 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.ObPtr, side: PWPins.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;
[] ← IncludeOb[cell: cell, ob: ob, position: position, orientation: orientation];
};
IncludePinSide:
PROC [name:
ROPE, side: PWPins.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, name, params.radialLayer, size, position];
};
DrawRingBit: OnionArc.EachSegBitProc
-- [min: D2Basic.Number, max: D2Basic.Number, side: Onion.PWPins.Side] -- = {
SELECT side
FROM
bottom => [] ← IncludeOb[cell, CDRects.CreateRect[[max-min, netRingWidth], params.ringLayer], [min-assignedArc.rect.x1, 0]];
right => [] ← IncludeOb[cell, CDRects.CreateRect[[netRingWidth, max-min], params.ringLayer], [assignedArc.rect.x2-assignedArc.rect.x1-netRingWidth, min-assignedArc.rect.y1]];
top => [] ← IncludeOb[cell, CDRects.CreateRect[[max-min, netRingWidth], params.ringLayer], [min-assignedArc.rect.x1, assignedArc.rect.y2-assignedArc.rect.y1-netRingWidth]];
left => [] ← IncludeOb[cell, CDRects.CreateRect[[netRingWidth, max-min], params.ringLayer], [0, min-assignedArc.rect.y1]];
ENDCASE => ERROR;
};
DepositOuterContacts: SymTab.EachPairAction
-- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = {
DrawOuterPin:
PROC [app:
CD.ApplicationPtr, name:
ROPE] = {
Add a contact and a pin
side: PWPins.Side ← PWPins.GetSide[outer, app].side;
size: CD.Position ← CDOrient.OrientedSize[app.ob.size, app.orientation];
position: CD.Position ← OuterPinLocation[app];
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;
nb:
INT ←
MAX[contactWidth, (
SELECT side
FROM
left, right => size.y,
bottom, top => size.x,
ENDCASE => ERROR)];
IncludePinSide[name, side, size, pos];
FOR i:
INT
IN [0..nb/contactWidth)
DO
IncludeInCellSide[params.contact, side,
SELECT side
FROM
left => [pos.x, pos.y-contactWidth*i],
right => [pos.x, pos.y+contactWidth*i],
bottom => [pos.x+contactWidth*i, pos.y],
top => [pos.x-contactWidth*i, pos.y],
ENDCASE => ERROR];
ENDLOOP;
};
net: Net ← NARROW [val];
quit ← FALSE;
IF ~net.chosen THEN {IF net.eval#LAST[INT] THEN Output[key, " "]; RETURN};
FOR outerPins:
LIST
OF
CD.ApplicationPtr ← net.outerPins, outerPins.rest
WHILE outerPins#
NIL
DO
DrawOuterPin[outerPins.first, key];
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: SymTab.EachPairAction
-- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = {
DrawInnerPin:
PROC [app:
CD.ApplicationPtr, chosen:
BOOL, name:
ROPE] = {
side: PWPins.Side ← PWPins.GetSide[inner, app].side;
size: CD.Position ← CDOrient.OrientedSize[app.ob.size, app.orientation];
rectSize: CD.Position ← size;
pos: CD.Position; -- base of wire in the outer coord system
position: CD.Position ← InnerPinLocation[app];
nb:
INT ←
MAX[contactWidth, (
SELECT side
FROM
left, right => size.y,
bottom, top => size.x,
ENDCASE => ERROR)];
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)
FOR i:
INT
IN [0..nb/contactWidth)
DO
IncludeInCellSide[params.contact, side,
SELECT side
FROM
left => [pos.x, pos.y-contactWidth*i],
right => [pos.x, pos.y+contactWidth*i],
bottom => [pos.x+contactWidth*i, pos.y],
top => [pos.x-contactWidth*i, pos.y],
ENDCASE => ERROR];
ENDLOOP
ELSE -- add a pin -- IncludePinSide[name, side, size, pos];
};
net: Net ← NARROW [val];
quit ← FALSE;
FOR innerPins:
LIST
OF
CD.ApplicationPtr ← net.innerPins, innerPins.rest
WHILE innerPins#
NIL
DO
DrawInnerPin[innerPins.first, net.chosen, key];
ENDLOOP;
};
ExtendAllWires: SymTab.EachPairAction
-- [key: SymTab.Key, val: SymTab.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.ApplicationPtr ← net.outerPins, outerPins.rest
WHILE outerPins#
NIL
DO
FOR innerPins:
LIST
OF
CD.ApplicationPtr ← 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: PWPins.Side ← PWPins.GetSide[inner, innerPins.first].side;
length:
INT ←
SELECT 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:
INT ←
SELECT side
FROM
left, right => MIN[innerSize.y, outerSize.y],
bottom, top => MIN[innerSize.x, outerSize.x],
ENDCASE => ERROR;
wire: CD.ObPtr ← params.wireExtendProc[design, width, length];
[] ← IncludeOb[
cell: cell, ob: 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: SymTab.Ref ← SymTab.Create[];
minEval: INT; minNetName: ROPE; -- for choosing the nets
netRingWidth: INT ← 0; -- all nets on the same track have the same width
-- Emergency break
IF ~CDBasics.Inside[innerRect, CDBasics.RectAt[[0, 0], CDBasics.SizeOfRect[CD.InterestRect[outer]]]] THEN {Output["**** Routing Impossible (Too big) ****\n**** Current state returned! ****\n"]; RETURN[inner, innerPos, impossible];};
-- Parsing all the pins to sort them by nets
[] ← PWPins.EnumerateEdgePins[inner, AddInnerPinToNets];
[] ← PWPins.EnumerateEdgePins[outer, AddOuterPinToNets];
-- We delete all nets containing only 1 pin
BEGIN
deletedNets: LIST OF ROPE ← NIL;
ToBeDeleted: SymTab.EachPairAction
-- [key: SymTab.Key, val: SymTab.Val] RETURNS [quit: BOOL] -- = {
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[key, deletedNets];
};
[] ← SymTab.Pairs[nets, ToBeDeleted];
WHILE deletedNets#
NIL
DO
Output["*** Net: ", deletedNets.first, " has only 1 pin. Not routed\n"];
[] ← SymTab.Delete[nets, deletedNets.first]; deletedNets ← deletedNets.rest;
ENDLOOP;
END;
-- We compute the Arc necessited by the net for being routed
[] ← SymTab.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.
[] ← SymTab.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.
Output["Allocating a new track\n"];
DO
Count:
PROC [pins:
LIST
OF
CD.ApplicationPtr]
RETURNS [rope:
ROPE] = {
count: INT ← 0;
WHILE pins#NIL DO count ← count+1; pins ← pins.rest ENDLOOP;
rope ← Convert.RopeFromInt[count];
};
minNet: Net;
minEval ← LAST[INT]; minNetName ← NIL;
[] ← SymTab.Pairs[nets, ChooseMinEval];
IF minEval=LAST[INT] THEN EXIT;
IF minEval>=LAST[INT]/2 THEN Output["****** ROUTING IS WRONG: at least 2 different nets are facing each other. No cure possible until Dogleg is introduced in Onion!\n"];
minNet ← FetchNet[nets, minNetName];
IF assignedArc=NIL THEN netRingWidth ← params.ringWidth[minNetName];
assignedArc ← IF assignedArc=NIL THEN minNet.arc ELSE OnionArc.Union[assignedArc, minNet.arc];
minNet.chosen ← TRUE;
Output["Routing the net : ", minNetName, " innerPins: ", Count[minNet.innerPins], Rope.Cat[" outerPins: ", Count[minNet.outerPins], " Cost: ", Convert.RopeFromInt[minNet.eval], "\n"]];
ENDLOOP;
-- We now generate geometry
cell ← CDCells.CreateEmptyCell[];
IF assignedArc=
NIL
THEN {
Finished: now we extend all the wires using the wireExtendProc
IF params.wireExtendProc#NIL THEN [] ← SymTab.Pairs[nets, ExtendAllWires];
And we position the inner cell
[] ← IncludeOb[cell, inner, innerPos];
IF params.wireExtendProc#NIL THEN [] ← IncludeOb[cell, outer, [0, 0]];
[] ← CDCells.RepositionCell[cell, NIL];
[] ← CDDirectory.Include[design, cell, Rope.Cat["RoutingRing-", minNetName]];
RETURN[cell, [0, 0], finishedAll];
}
ELSE {
-- We shrink the assignedArc.rect if some sides are unused
IF OnionArc.NotOverlapping[assignedArc,
NEW[OnionArc.ArcRec ← [rect: assignedArc.rect, segs:
LIST [
NEW[OnionArc.SegRec ← [assignedArc.rect.y2, assignedArc.rect.y1, left, left]]]]],
params.ringRingDist+contactWidth] THEN assignedArc.rect.x1 ← innerRect.x1;
IF OnionArc.NotOverlapping[assignedArc, NEW[OnionArc.ArcRec ← [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec ← [assignedArc.rect.y1, assignedArc.rect.y2, right, right]]]]], params.ringRingDist+contactWidth] THEN assignedArc.rect.x2 ← innerRect.x2;
IF OnionArc.NotOverlapping[assignedArc, NEW[OnionArc.ArcRec ← [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec ← [assignedArc.rect.x1, assignedArc.rect.x2, bottom, bottom]]]]], params.ringRingDist+contactWidth] THEN assignedArc.rect.y1 ← innerRect.y1;
IF OnionArc.NotOverlapping[assignedArc, NEW[OnionArc.ArcRec ← [rect: assignedArc.rect, segs: LIST [NEW[OnionArc.SegRec ← [assignedArc.rect.x2, assignedArc.rect.x1, top, top]]]]], params.ringRingDist+contactWidth] THEN assignedArc.rect.y2 ← innerRect.y2;
-- We position the inner cell
CDProperties.PutPropOnApplication[
IncludeOb[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
Output["Non routed nets: "];
[] ← SymTab.Pairs[nets, DepositOuterContacts];
Output["\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.
[] ← SymTab.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];
[] ← CDDirectory.Include[design, cell, Rope.Cat["RoutingRing-", minNetName]];
RETURN[cell, CDBasics.BaseOfRect[assignedArc.rect], doneOnce];
};
};
LRSRoute:
PUBLIC
PROC [design:
CD.Design, inner, outer:
CD.ObPtr, innerPos:
CD.Position, params: LayersParameters ← defaultLayersParameters]
RETURNS [cell:
CD.ObPtr, 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.ObPtr, params: LayersParameters ← channelDefaultParameters]
RETURNS [cell:
CD.ObPtr, status: Status] = {
inner: CD.ObPtr ← CDCells.CreateEmptyCell[];
outer: CD.ObPtr ← CDCells.CreateEmptyCell[];
currentSide: PWPins.Side; currentOb: CD.ObPtr;
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.AppEnumerator
-- [app: CD.ApplicationPtr] RETURNS [quit: BOOL ← FALSE] -- = {
name: ROPE ← CDPinObjects.GetName[app];
realSize: CD.Position ← CDOrient.OrientedSize[app.ob.size, app.orientation];
location: CD.Position ← CDBasics.SubPoints[app.location, CDBasics.BaseOfRect[CD.InterestRect[currentOb]]];
IF PWPins.GetSide[currentOb, app].side#((currentSide+2 ) MOD 4) THEN RETURN;
IF CDPinObjects.GetLayer[app]#params.radialLayer
THEN {
Output["*** Pin ", name, " discarded: not of radialLayer material.\n"] ;
RETURN;
};
[] ← IncludePin[outer, name, CDPinObjects.GetLayer[app], realSize,
SELECT currentSide
FROM
PWPins.bottom => [location.x, 0],
PWPins.top => [location.x, size.y-realSize.y],
PWPins.left => [0, location.y],
PWPins.right => [size.x-realSize.x, location.y],
ENDCASE => ERROR];
};
[] ← IncludeOb[inner, CDRects.CreateRect[[8, 8], params.ringLayer]];
[] ← CDCells.RepositionCell[inner, NIL];
[] ← CDDirectory.Include[design, inner, "EmptyCellForHeartOfSwitchBox"];
currentSide ← PWPins.bottom; currentOb ← bottomOb;
[] ← PWPins.EnumerateEdgePins[currentOb, AddPin];
currentSide ← PWPins.top; currentOb ← topOb;
[] ← PWPins.EnumerateEdgePins[currentOb, AddPin];
currentSide ← PWPins.left; currentOb ← leftOb;
[] ← PWPins.EnumerateEdgePins[currentOb, AddPin];
currentSide ← PWPins.right; currentOb ← rightOb;
[] ← PWPins.EnumerateEdgePins[currentOb, AddPin];
CDCells.SetInterestRect[outer, [0, 0, size.x, size.y]];
[] ← CDCells.RepositionCell[outer, NIL];
[] ← CDDirectory.Include[design, outer, "EmptyCellForSkinOfSwitchBox"];
[cell, status] ← LRSRoute[design, inner, outer, Center[inner, outer], params];
};
Channel:
PUBLIC
PROC [design:
CD.Design, left, right:
CD. ObPtr, size:
INT, params: LayersParameters ← channelDefaultParameters]
RETURNS [cell:
CD.ObPtr, status: Status] = {
top: CD.ObPtr ← CDCells.CreateEmptyCell[];
[] ← IncludeOb[top, CDRects.CreateRect[[size, 8], params.ringLayer]];
[] ← CDCells.RepositionCell[top, NIL];
[] ← CDDirectory.Include[design, top, "EmptyTopForChannel"];
[cell, status] ← SwitchBox[design, top, right, top, left, params];
};
END.