QadCR,
QuickandDirtyChannelRouter:
PUBLIC
PROC [design:
CD.Design, left, right:
PW.ObPtr, width:
INT, useGnd:
BOOL ←
TRUE]
RETURNS [channel:
PW.ObPtr] =
BEGIN
ParseLeft: PWPins.AppEnumerator =
BEGIN
side: PWPins.Side ← PWPins.GetSide[left, app].side;
IF side#PWPins.right THEN RETURN;
IF Rope.Equal[CDPinObjects.GetName[app], powerName] THEN RETURN;
IF Rope.Equal[CDPinObjects.GetName[app], otherPower] THEN RETURN;
leftPins[nbL] ← app; nbL ← nbL+1;
END;
ParseRightAndGnd: PWPins.AppEnumerator =
BEGIN
side: PWPins.Side ← PWPins.GetSide[left, app].side;
IF side#PWPins.left THEN RETURN;
IF Rope.Equal[CDPinObjects.GetName[app], otherPower] THEN RETURN;
IF Rope.Equal[CDPinObjects.GetName[app], powerName]
THEN {gndPins[nbG] ← app; nbG ← nbG+1}
ELSE {rightPins[nbR] ← app; nbR ← nbR+1};
END;
SortArray:
PROC [pins: ArrayPins, nb:
INT]
RETURNS [sortedPins: ArrayPins] =
BEGIN
MinY:
PROC
RETURNS [minPin:
CD.ApplicationPtr] =
BEGIN
minY: INT ← LAST[INT]; -- y-coord of minPin
minN: INT ← 0; -- location of minPin in array
FOR i:
INT
IN [0..nb)
DO
IF pins[i]#
NIL
THEN
IF pins[i].location.y<minY
THEN
{minPin ← pins[i]; minN ← i; minY ← minPin.location.y};
ENDLOOP;
pins[minN] ← NIL;
END;
FOR i:
INT
IN [0..nb)
DO
sortedPins[i] ← MinY[];
ENDLOOP;
END;
RouteTrack:
PROC [leftPin, rightPin:
CD.ApplicationPtr] =
BEGIN
reset: BOOL ← FALSE;
prevRightY ← rightY; prevLeftY ← leftY;
rightY ← rightPin.location.y-iRectR.y1;
leftY ← leftPin.location.y-iRectL.y1;
-- Initialize
IF firstTime
THEN
{firstTime ← FALSE;
wasGoingUp ← goingUp ← leftY<rightY;
prevRightY ← rightY; prevLeftY ← leftY;
IF goingUp THEN trackX ← initTackX ELSE trackX ← 6;}
ELSE
{wasGoingUp ← goingUp; goingUp ← leftY<rightY;};
-- Decide if we reset the track position, and if so do it
reset ← (wasGoingUp AND leftY>=prevRightY+okDY) OR (~wasGoingUp AND rightY>=prevLeftY+okDY);
IF reset THEN {IF goingUp THEN trackX ← initTackX ELSE trackX ← 6}
ELSE {IF goingUp THEN trackX ← trackX-incrTrackX ELSE trackX ← trackX+incrTrackX};
-- Draw the m2 wire on the right side
PW.IncludeInCell[design,
channel,
PWCmos.Rect[CMos.met2, [6, 8]],
[width-6, rightY]];
-- via: centered on the m2 wire
PW.IncludeInCell[design,
channel,
PWCmos.Contact[CMos.met2, CMos.met],
[width-16, rightY-1]];
-- "top" horizontal m1 wire
PW.IncludeInCell[design,
channel,
PWCmos.Rect[CMos.met, [width-trackX-16, 8]],
[trackX, rightY]];
-- vertical m1 wire (track)
PW.IncludeInCell[design,
channel,
PWCmos.Rect[CMos.met, [8, ABS[rightY-leftY]+8]],
[trackX, MIN[leftY, rightY]]];
-- "bottom" horizontal m1 wire
PW.IncludeInCell[design,
channel,
PWCmos.Rect[CMos.met, [trackX, leftPin.ob.size.y]],
[0, leftY]];
END;
ArrayPins: TYPE = ARRAY[0..50) OF CD.ApplicationPtr;
leftPins, rightPins, gndPins: ArrayPins;
nbL, nbR, nbG: INT ← 0;
initTackX: INT ← width-24;
incrTrackX: INT ← 16; -- 8 lambdas
okDY: INT ← 16; -- 8 lambdas
trackX, prevLeftY, prevRightY, leftY, rightY: INT;
powerName, otherPower: ROPE;
goingUp, wasGoingUp, firstTime: BOOL ← TRUE;
iRectL, iRectR: CD.Rect;
IF useGnd THEN {powerName ← "gnd"; otherPower ← "vdd"}
ELSE {powerName ← "vdd"; otherPower ← "gnd"};
IF PW.Size[left].y#PW.Size[right].y THEN ERROR;
channel ← PW.CreateEmptyCell[];
iRectL ← CD.InterestRect[left];
iRectR ← CD.InterestRect[right];
CDCells.SetInterestRect[channel, [0, 0, width, PW.Size[left].y]]; -- set interestRect of channel
-- Get the three sets of pins in their respective arrays
[] ← PWPins.EnumerateEdgePins[left, ParseLeft];
[] ← PWPins.EnumerateEdgePins[right, ParseRightAndGnd];
-- Sort them by y-coordinate
IF nbL#nbR THEN ERROR;
leftPins ← SortArray[leftPins, nbL];
rightPins ← SortArray[rightPins, nbR];
-- The gnd pins: a straight m2 wire
FOR i:
INT
IN [0..nbG)
DO
PW.IncludeInCell[design,
channel,
PWCmos.Rect[CMos.met2, [width, gndPins[i].ob.size.y]],
[0, gndPins[i].location.y-iRectR.y1]]; -- where it lands
ENDLOOP;
-- For each pair, put 3 wires of m1, one via, one wire m2, and update the x-coord of the vertical track
FOR i:
INT
IN [0..nbL)
DO
RouteTrack[leftPins[i], rightPins[i]];
ENDLOOP;
PW.IncludeInDirectory[design, channel, "channel"];
END;