RouteUtilImpl.mesa
Copyright © 1985, 1987 by Xerox Corporation. All rights reserved.
by Bryan Preas July 10, 1985 6:57:00 pm PDT
last edited by Bryan Preas February 5, 1987 8:08:43 pm PST
DIRECTORY
Basics, CD, CDBasics, CDCells, CDRects, CDSymbolicObjects, CDProperties, D2Orient, HashTable, Properties, Real, RealOps, Rope, Route, RoutePrivate, RouteChannel, RouteTechnology, RouteUtil, RTBasic;
RouteUtilImpl: CEDAR PROGRAM
IMPORTS CDBasics, CDCells, CDRects, CDSymbolicObjects, CDProperties, HashTable, Properties, Real, RealOps, Route, RouteChannel, RouteTechnology, RouteUtil, RTBasic
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: REF ATOM, default: Route.Number] RETURNS [Route.Number] =
BEGIN
valRef: REF ANY ← Properties.GetProp[properties, key];
IF valRef # NIL THEN default ← NARROW[valRef, REF Route.Number]^;
RETURN [default];
END;
PutNumberProp: PUBLIC PROC [properties: Route.PropList, key: REF ATOM, number: Route.Number] RETURNS [Route.PropList] =
BEGIN
valRef: REF Route.Number ← NEW[Route.Number ← number];
RETURN[Properties.PutProp[properties, key, 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] RETURNS [cdPin: CD.Instance] = {
Create a ChipNDale pin. Calls CDSymbolicObjects.CreatePin but normalizes th rectangle first.
r: CD.Rect ← CDBasics.ReInterpreteRect[rect];
cdPinObj: Route.Object ← CDSymbolicObjects.CreatePin[[r.x2-r.x1, r.y2-r.y1]];
cdPin ← CDSymbolicObjects.CreateSymInst[name, r, 0, lev];
CDSymbolicObjects.SetName[cdPin, name];
CDSymbolicObjects.SetLayer[cdPin, 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];
size: CD.Position ← CDBasics.OrientedSize[CDBasics.SizeOfRect[old.pin.ob.bbox], old.pin.trans.orient];
SELECT old.side FROM
bottom, top => oldWidth ← size.x;
left, right => oldWidth ← 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: D2Orient.Orientation←original] RETURNS [application: CD.Instance] = {
include an object in a design
application ← CDCells.IncludeOb[design: NIL, cell: cell, ob: ob, trans: [off: position, orient: orientation], mode: dontResize].newInst};
AddPin: PUBLIC PROC [obj: Route.Object, pin: Route.Pin] = {
pinLayer: Route.Layer ← CDSymbolicObjects.GetLayer[pin.pin];
pinName: Rope.ROPE ← CDSymbolicObjects.GetName[pin.pin];
size: CD.Position ← CDBasics.SizeOfRect[pin.pin.ob.bbox];
location: CD.Position ← CDBasics.BaseOfRect[CDBasics.MapRect[pin.pin.ob.bbox, pin.pin.trans]];
pinObj: Route.Object ← CDSymbolicObjects.CreatePin[size];
application: CD.Instance ← RouteUtil.Include[obj, pinObj, location];
CDSymbolicObjects.SetName[application, pinName];
CDSymbolicObjects.SetLayer[application, pinLayer]};
AddVia: PUBLIC PROC [obj: Route.Object, name: Rope.ROPE, pos, size: Route.Position, layer1, layer2: Route.Layer, cdLambda: Route.Number, viaTable: HashTable.Table] = {
value: HashTable.Value ← IF viaTable = NIL THEN NIL ELSE HashTable.Fetch[viaTable, NEW[Route.Position ← size]].value;
cell: Route.Object ← IF value # NIL THEN NARROW[value, Route.Object]
ELSE StitchVias[size, layer1, layer2, cdLambda, viaTable];
ReallyAddVia[obj, cell, name, pos]};
GetVia: PUBLIC PROC [size: Route.Position, layer1, layer2: Route.Layer, cdLambda: Route.Number] RETURNS [cell: Route.Object ← NIL] = {
this is technology dependent; this needs to be fixed
cmosB via rules are used if 'Big Contacts" exist
minBigContact: Route.Object ← RouteTechnology.GetBigContact[[1, 1], layer1, layer2];
IF minBigContact = NIL THEN
no big contacts, must do it with small ones
cell ← RouteTechnology.GetContact[layer1, layer2]
ELSE { -- big contact exists, determine size to use
contactSize: CD.Position ← CDBasics.SizeOfRect[minBigContact.bbox];
IF contactSize.x <= size.x AND contactSize.y <= size.y THEN {
use 2, 3, or 4 lambda square vias tha give largest perimeter
perim2x2: Route.Number ← RealOps.RoundLI[size.x/(6*cdLambda), RealOps.FixMode]*RealOps.RoundLI[size.y/(6*cdLambda), RealOps.FixMode]*8*cdLambda; -- 2x2 contacts go in a 6x6 square
perim3x3: Route.Number ← RealOps.RoundLI[size.x/(7*cdLambda), RealOps.FixMode]*RealOps.RoundLI[size.y/(7*cdLambda), RealOps.FixMode]*12*cdLambda; -- 3x3 contacts go in a 7x7 square
perim4x4: Route.Number ← RealOps.RoundLI[size.x/(8*cdLambda), RealOps.FixMode]*RealOps.RoundLI[size.y/(8*cdLambda), RealOps.FixMode]*16*cdLambda; -- 4x4 contacts go in a 8x8 square
SELECT TRUE FROM
perim4x4 >= perim2x2 AND perim4x4 >= perim3x3 =>
cell ← RouteTechnology.GetBigContact[[8*cdLambda, 8*cdLambda], layer1, layer2];
perim3x3 >= perim2x2 AND perim3x3 >= perim4x4 =>
cell ← RouteTechnology.GetBigContact[[7*cdLambda, 7*cdLambda], layer1, layer2];
perim2x2 >= perim4x4 AND perim2x2 >= perim3x3 =>
cell ← RouteTechnology.GetBigContact[[6*cdLambda, 6*cdLambda], layer1, layer2];
ENDCASE}
ELSE -- big contact too big, must do it with small ones
cell ← RouteTechnology.GetContact[layer1, layer2]
}};
StitchVias: PUBLIC PROC [size: Route.Position, layer1, layer2: Route.Layer, cdLambda: Route.Number, viaTable: HashTable.Table] RETURNS [obj: Route.Object] = {
contact: Route.Object ← GetVia[size, layer1, layer2, cdLambda];
contactSize: CD.Position ← CDBasics.SizeOfRect[contact.bbox];
minSize: Route.Number ← 6*cdLambda; -- technology dependent!!! this needs to be fixed
value: HashTable.Value ← IF viaTable = NIL THEN NIL ELSE HashTable.Fetch[viaTable, NEW[Route.Position ← size]].value;
IF value # NIL THEN obj ← NARROW[value]
ELSE IF contactSize.x >= size.x AND contactSize.y >= size.y THEN
obj ← contact -- special case for performance
ELSE {
sizeX: Route.Number ← MAX[contactSize.x, minSize];
sizeY: Route.Number ← MAX[contactSize.y, minSize];
numYInts: Route.Number ← MAX[1, size.y/sizeY];
lastYLoc: Route.Number ← 0;
lastXLoc: Route.Number;
cover: Route.Position;
obj ← CDCells.CreateEmptyCell[];
FOR index: Route.Number IN [1 .. numYInts] DO
numXInts: Route.Number ← MAX[1, size.x/sizeX];
lastXLoc ← 0;
FOR index: Route.Number IN [1 .. numXInts] DO
[] ← RouteUtil.Include[obj, contact, [lastXLoc, lastYLoc]];
lastXLoc ← lastXLoc + sizeX;
ENDLOOP;
lastYLoc ← lastYLoc + sizeY;
ENDLOOP;
cover ← [lastXLoc - sizeX + contactSize.x, lastYLoc - sizeY + contactSize.y];
[] ← RouteUtil.Include[obj, CDRects.CreateRect[cover, layer1]];
[] ← RouteUtil.Include[obj, CDRects.CreateRect[cover, layer2]];
RTBasic.RepositionCell[obj]}};
ReallyAddVia : PROC [obj: Route.Object, cell: Route.Object, name: Rope.ROPE, pos: Route.Position] = {
cellSize: CD.Position ← CDBasics.SizeOfRect[cell.bbox];
position: CD.Position ← [pos.x - cellSize.x/2, pos.y - cellSize.y/2];
application: CD.Instance ← RouteUtil.Include[obj, cell, position];
CDProperties.PutProp[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.