RouteUtilImpl:
CEDAR
PROGRAM
IMPORTS CDBasics, CDCells, CDPinObjects, CDProperties, Properties, Real, Route, RouteChannel, RouteTechnology, RouteUtil
EXPORTS RouteUtil =
BEGIN
LayerToRoutingLayer:
PUBLIC
PROC [routingArea: Route.RoutingArea, layer: Route.Layer]
RETURNS [routingLayer: RoutePrivate.RoutingLayer] =
BEGIN
trunkLayer: Route.Layer ← routingArea.rules.trunkLayer;
branchLayer: Route.Layer ← routingArea.rules.branchLayer;
IF layer = trunkLayer THEN routingLayer ← trunk
ELSE IF layer = branchLayer THEN routingLayer ← branch
ELSE Route.Error[programmingError, "Invalid layer"];
END;
RoutingLayerToLayer:
PUBLIC
PROC [routingArea: Route.RoutingArea, routingLayer: RoutePrivate.RoutingLayer]
RETURNS [layer: Route.Layer] =
BEGIN
trunkLayer: Route.Layer ← routingArea.rules.trunkLayer;
branchLayer: Route.Layer ← routingArea.rules.branchLayer;
IF routingLayer = trunk THEN layer ← trunkLayer
ELSE IF routingLayer = branch THEN layer ← branchLayer
ELSE Route.Error[programmingError, "Invalid routing layer"];
END;
GetNumberProp:
PUBLIC
PROC [properties: Route.PropList, key:
ATOM, default: Route.Number]
RETURNS [Route.Number] =
BEGIN
atomRef: REF ATOM ← NEW[ATOM ← key];
valRef: REF ANY ← Properties.GetProp[properties, atomRef];
IF valRef # NIL THEN default ← NARROW[valRef, REF Route.Number]^;
RETURN [default];
END;
PutNumberProp:
PUBLIC
PROC [properties: Route.PropList, key:
ATOM, number: Route.Number] RETURNS [Route.PropList] =
BEGIN
keyRef: REF ATOM ← NEW[ATOM ← key];
valRef: REF Route.Number ← NEW[Route.Number ← number];
RETURN[Properties.PutProp[properties, keyRef, valRef]];
END;
Length:
PUBLIC
PROC [pos1, pos2: Route.Position]
RETURNS [length: Route.Number] = {
return lent of line segment from pos1 to pos2.
length ← Real.RoundLI[Real.SqRt[Real.FAdd[Real.FMul[Real.FSub[pos1.x, pos2.x], Real.FSub[pos1.x, pos2.x]], Real.FMul[Real.FSub[pos1.y, pos2.y], Real.FSub[pos1.y, pos2.y]]]]]};
XYToPQ:
PUBLIC
PROC [routingArea: Route.RoutingArea, pos: Route.Position]
RETURNS [pqPos: RoutePrivate.PQPosition] =
convert a position from x-y to p-q space.
BEGIN
chanDirection: Route.Direction ← routingArea.rules.trunkDirection;
SELECT chanDirection
FROM
horizontal => RETURN[[pos.x, pos.y]];
vertical => RETURN[[pos.y, pos.x]];
ENDCASE;
END;
PQToXY:
PUBLIC
PROC [routingArea: Route.RoutingArea, pqPos: RoutePrivate.PQPosition]
RETURNS [pos: Route.Position] =
convert a position from p-q to x-y space.
BEGIN
chanDirection: Route.Direction ← routingArea.rules.trunkDirection;
SELECT chanDirection
FROM
horizontal => RETURN[[pqPos.p, pqPos.q]];
vertical => RETURN[[pqPos.q, pqPos.p]];
ENDCASE;
END;
SimpleCompare:
PUBLIC
PROCEDURE [result1, result2: Route.Number]
RETURNS [result: Basics.Comparison] = {
result ← IF result1 < result2 THEN less
ELSE IF result1 > result2 THEN greater
ELSE equal
};
CompareResult:
PUBLIC PROCEDURE [result1, result2: Route.RoutingResult]
RETURNS [result: Basics.Comparison] = {
result ← RouteUtil.SimpleCompare[result1.numIncompletes, result2.numIncompletes];
IF result # equal THEN RETURN;
result ← RouteUtil.SimpleCompare[result1.numTrunkTracks, result2.numTrunkTracks];
IF result # equal
THEN
RETURN;
result ← RouteUtil.SimpleCompare[result1.polyLength, result2.polyLength];
IF result # equal
THEN
RETURN;
result ← RouteUtil.SimpleCompare[result1.polyToMetal, result2.polyToMetal];
IF result # equal
THEN
RETURN;
result ← RouteUtil.SimpleCompare[result1.metalToMetal2, result2.metalToMetal2];
IF result # equal
THEN
RETURN;
result ← RouteUtil.SimpleCompare[result1.metalLength, result2.metalLength];
IF result # equal
THEN
RETURN;
result ← RouteUtil.SimpleCompare[result1.metal2Length, result2.metal2Length];
RETURN;
}; -- CompareResult
CreateCDPin:
PUBLIC
PROC [name: Rope.
ROPE, rect:
CD.Rect, lev:
CD.Layer←
CD.combined]
RETURNS [cdPin:
CD.Instance] = {
Create a ChipNDale pin. Calls CDPinObjects.CreatePinInstance but normalizes th rectangle first.
r: CD.Rect ← CDBasics.NormalizeRect[rect];
cdPin ← CDPinObjects.CreatePinInstance[name, r, lev]};
GetPinWidth:
PUBLIC
PROC [routingArea: Route.RoutingArea, connections: Route.PinList, channelDirection: Route.Direction]
RETURNS [widestBranchPin, widestTrunkPin: Route.Number ← 0] = {
Find the widest pin in connections in channelDirection.
FOR list: Route.PinList ← connections, list.rest
WHILE list #
NIL
DO
old: Route.Pin ← list.first;
oldWidth: Route.Number;
chanSide: RouteChannel.ChanSide ← RouteChannel.ExtSideToIntSide[routingArea, old.side];
SELECT old.side
FROM
bottom, top => oldWidth ← old.pin.ob.size.x;
left, right => oldWidth ← old.pin.ob.size.y;
ENDCASE;
SELECT chanSide
FROM
chanBottom, chanTop => widestBranchPin ← MAX[widestBranchPin, oldWidth];
chanLeft, chanRight => widestTrunkPin ← MAX[widestTrunkPin, oldWidth];
ENDCASE;
ENDLOOP};
Include:
PUBLIC PROC [cell:
CD.Object←
NIL, ob:
CD.Object,
position: CD.Position←[0, 0], orientation: CD.Orientation𡤀] RETURNS [application: CD.Instance] = {
include an object in a design
application ← CDCells.IncludeOb[design: NIL, cell: cell, ob: ob, position: position, orientation: orientation, cellCSystem: originCoords, obCSystem: originCoords, mode: dontPropagate].newInst};
AddPin:
PUBLIC PROC [obj: Route.Object, pin: Route.Pin] = {
pinLayer: Route.Layer ← CDPinObjects.GetLayer[pin.pin];
pinName: Rope.ROPE ← CDPinObjects.GetName[pin.pin];
pinObj: CD.Object ← CDPinObjects.CreatePinOb[pin.pin.ob.size];
application: CD.Instance ← RouteUtil.Include[obj, pinObj, pin.pin.location];
CDPinObjects.SetName[application, pinName];
CDPinObjects.SetLayer[application, pinLayer]};
AddVia:
PUBLIC PROC [obj: Route.Object, name: Rope.
ROPE, pos, size: Route.Position, layer1, layer2: Route.Layer] = {
cell: Route.Object;
minBigContact: Route.Object ← RouteTechnology.GetBigContact[[1, 1], layer1, layer2];
IF minBigContact =
NIL
THEN
no big contacts, must do it with small ones
cell ← StitchVias[RouteTechnology.GetContact[layer1, layer2], size]
ELSE {
-- big contact exists, see if it is amall enough
IF minBigContact.size.x <= size.x
AND minBigContact.size.y <= size.y
THEN
cell ← RouteTechnology.GetBigContact[size, layer1, layer2]
ELSE
-- big contact too big, must do it with small ones
cell ← StitchVias[RouteTechnology.GetContact[layer1, layer2], size]
};
ReallyAddVia[obj, cell, name, pos]
};
StitchVias:
PROC [contact: Route.Object, size: Route.Position]
RETURNS [obj: Route.Object ← CDCells.CreateEmptyCell[]] = {
MakeXStrip:
PROC [cell: Route.Object, size: Route.Position]
RETURNS [obj: Route.Object ← CDCells.CreateEmptyCell[]] = {
numXInts: Route.Number ← MAX[1, size.x/(cell.size.x*2)];
lastXLoc: Route.Number ← 0;
FOR index: Route.Number IN [1 .. numXInts]
DO
[] ← RouteUtil.Include[obj, cell, [0, lastXLoc]];
lastXLoc ← lastXLoc + cell.size.x*2;
ENDLOOP;
[] ← CDCells.RepositionCell[obj, NIL]};
intermediate: Route.Object ← MakeXStrip[contact, size];
numYInts: Route.Number ← MAX[1, size.y/(intermediate.size.y*2)];
lastYLoc: Route.Number ← 0;
FOR index: Route.Number IN [1 .. numYInts]
DO
[] ← RouteUtil.Include[obj, intermediate, [0, lastYLoc]];
lastYLoc ← lastYLoc + intermediate.size.y*2;
ENDLOOP;
[] ← CDCells.RepositionCell[obj, NIL]};
ReallyAddVia:
PROC [obj: Route.Object, cell: Route.Object, name: Rope.
ROPE, pos: Route.Position] = {
position: CD.Position ← [pos.x - cell.size.x/2, pos.y - cell.size.y/2];
application: CD.Instance ← RouteUtil.Include[obj, cell, position];
CDProperties.PutPropOnInstance[application, $SignalName, name]};
LineToRect:
PUBLIC PROC [pos1, pos2: Route.Position, width: Route.Number]
RETURNS [position:
CD.Position, size:
CD.Position] = {
convert a line and a width to a rectangle and an orgin
SELECT
TRUE
FROM
pos1.x = pos2.x => {
-- line is vertical
size ← [width, ABS[pos1.y - pos2.y]];
position ← [pos1.x - width/2, MIN[pos1.y, pos2.y]]};
pos1.y = pos2.y => {
-- line is horizontal
size ← [ABS[pos1.x - pos2.x], width];
position ← [MIN[pos1.x, pos2.x], pos1.y - width/2]};
ENDCASE => Route.Error[programmingError, "Diagional lines not allowed."];
};
END.