PWCoreRouteImpl:
CEDAR
PROGRAM
IMPORTS CD, CDBasics, CDInstances, CDSimpleRules, CDSymbolicObjects, CedarProcess, CoreClasses, CoreOps, CoreProperties, CoreGeometry, IO, PW, PWCore, PWObjects, PWRoute, Route, Sisyph, SymTab, TerminalIO
EXPORTS PWCoreRoute =
BEGIN OPEN PWCoreRoute;
technologyKey: PUBLIC ATOM ← $cmosB;
wireWidthProp: ATOM = $w;
lambda: INT ← CDSimpleRules.GetTechnology[technologyKey].lambda;
SpecifiedWidthProc: PWRoute.WireWidthProc = {
widthTab: SymTab.Ref ← NARROW[context];
ref: REF ← SymTab.Fetch[widthTab, netName].val;
wireWidth ← IF ref=NIL THEN CDSimpleRules.MinWidth[CDSimpleRules.GetLayer[technologyKey, "metal2"]] ELSE lambda*NARROW[ref, REF INT]^;
};
TrunkDim:
PROC [obj:
CD.Object, inX:
BOOL]
RETURNS [
INT] ~ {
RETURN[IF inX THEN CD.InterestSize[obj].y ELSE CD.InterestSize[obj].x]
};
BranchDim:
PROC [obj:
CD.Object, inX:
BOOL]
RETURNS [
INT] ~ {
RETURN[IF inX THEN CD.InterestSize[obj].x ELSE CD.InterestSize[obj].y]
};
Channel:
PUBLIC PWCore.LayoutProc = {
widthTab: SymTab.Ref ← SymTab.Create[]; -- net name -> wire width in lambdas
data: CoreClasses.RecordCellType;
leftOrBottomCT, rightOrTopCT: CellType;
leftOrBottom, rightOrTop: CD.Object;
obj1, obj2, bottomOrLeftObj, topOrRightObj, channel, extended1, extended2: PW.Object;
params: PWRoute.RouterParams;
channelData: ChannelData;
inX: BOOL;
leftOrBottomHeight, rightOrTopHeight, leftOrBottomExtend, rightOrTopExtend: INT;
trLayer, brLayer: CD.Layer;
priority: CedarProcess.Priority;
retrieveRect: PWRoute.RefRect ← NIL;
lambda: INT ← CDSimpleRules.GetTechnology[technologyKey].lambda;
-- Looks for the property wireWidthProp on atomic wires (current restriction)
FindWidth:
PROC [wire: Wire] ~ {
ref: REF ← CoreProperties.GetWireProp[wire, wireWidthProp];
IF ref#NIL THEN [] ← SymTab.Store[widthTab, CoreOps.GetShortWireName[wire], ref];
};
channelData ← NARROW [CoreProperties.GetCellTypeProp[cellType, $ChannelData]];
inX ← channelData.inX;
data ← NARROW [cellType.data];
IF data.size#2 THEN ERROR;
[] ← CoreOps.VisitRootAtomics[data.internal, FindWidth];
leftOrBottomCT ← data[0].type;
rightOrTopCT ← data[1].type;
leftOrBottom ← PWCore.Layout[leftOrBottomCT];
rightOrTop ← PWCore.Layout[rightOrTopCT];
leftOrBottomHeight ← TrunkDim[leftOrBottom, inX];
leftOrBottomHeight ← IF inX THEN CD.InterestSize[leftOrBottom].y ELSE CD.InterestSize[leftOrBottom].x;
rightOrTopHeight ← TrunkDim[rightOrTop, inX];
rightOrTopHeight ← IF inX THEN CD.InterestSize[rightOrTop].y ELSE CD.InterestSize[rightOrTop].x;
leftOrBottomExtend ← IF channelData.extend THEN MAX[leftOrBottomHeight, rightOrTopHeight] - leftOrBottomHeight ELSE 0;
rightOrTopExtend ← IF channelData.extend THEN MAX[leftOrBottomHeight, rightOrTopHeight] - rightOrTopHeight ELSE 0;
trLayer ← CDSimpleRules.GetLayer[technologyKey, channelData.trunkLayer];
brLayer ← CDSimpleRules.GetLayer[technologyKey, channelData.branchLayer];
priority ← CedarProcess.GetPriority[];
extended1 ← Filler[leftOrBottomCT, inX, trLayer, leftOrBottomExtend, channelData.extendTopOrRight];
extended2 ← Filler[rightOrTopCT, inX, trLayer, rightOrTopExtend, channelData.extendTopOrRight];
obj1 ← MakeOutline[data[0], data.internal, IF inX THEN right ELSE top, brLayer, CD.InterestSize[extended1], IF channelData.extendTopOrRight THEN 0 ELSE leftOrBottomExtend];
obj2 ← MakeOutline[data[1], data.internal, IF inX THEN left ELSE bottom, brLayer, CD.InterestSize[extended2], IF channelData.extendTopOrRight THEN 0 ELSE rightOrTopExtend];
-- check if interestRects do not match
IF TrunkDim[obj1, inX]#TrunkDim[obj2, inX] THEN ERROR;
IF (IF inX THEN CD.InterestSize[obj1].y ELSE CD.InterestSize[obj1].x)#(IF inX THEN CD.InterestSize[obj2].y ELSE CD.InterestSize[obj2].x) THEN ERROR;
-- Make fake objects
bottomOrLeftObj ← MakeFakeObject[data.internal, channelData.bottomOrLeftWires, channelData.inX, trLayer, IF inX THEN bottom ELSE left];
topOrRightObj ← MakeFakeObject[data.internal, channelData.topOrRightWires, channelData.inX, trLayer, IF inX THEN top ELSE right];
params ←
NEW [PWRoute.RouterParamsRec ← [
context: widthTab,
trunkLayer: channelData.trunkLayer,
branchLayer: channelData.branchLayer,
wireWidthProc: SpecifiedWidthProc,
technologyKey: technologyKey,
signalSinglePinNets: FALSE, -- SIGNAL if there are any single pin nets
signalCoincidentPins: FALSE, -- SIGNAL if there any pins are coincident
opt: noIncompletes -- return the first correct routing
]];
IF channelData.totalWidth#0
THEN retrieveRect ←
NEW[PWRoute.Rect ←
[0, -- x1
0, -- y1
MAX[leftOrBottomHeight, rightOrTopHeight], -- x2
channelData.totalWidth*lambda-BranchDim[obj1, inX]-BranchDim[obj2, inX] -- y2
]];
CedarProcess.CheckAbort[];
CedarProcess.SetPriority[background];
channel ← PWRoute.MakeChannel[
obj1: obj1, obj2: obj2,
bottomOrLeftObj: bottomOrLeftObj, topOrRightObj: topOrRightObj,
retrieveRect: retrieveRect,
params: params,
isX: channelData.inX ! Route.Signal => {TerminalIO.PutF["*** Routing warning: %g\n", IO.rope[explanation]]}];
CedarProcess.SetPriority[priority];
IF channel=NIL THEN ERROR;
obj ← (IF inX THEN PW.AbutX ELSE PW.AbutY)[extended1, channel, extended2];
};
DecorateChannel: PWCore.DecorateProc = {
channelData: ChannelData ← NARROW [CoreProperties.GetCellTypeProp[cellType, $ChannelData]];
PWCore.DecorateFlatten[cellType, obj, IF channelData.inX THEN PWCore.SortInX ELSE PWCore.SortInY];
We make a sanity check that all wires appearing in bottomOrLeftWires and topOrRightWires have pins on their relative sides.
SanityCheck[cellType, channelData.bottomOrLeftWires, IF channelData.inX THEN bottom ELSE left];
SanityCheck[cellType, channelData.topOrRightWires, IF channelData.inX THEN top ELSE right];
};
Base:
PROC [cellInstance: CoreClasses.CellInstance]
RETURNS [CD.Position] ~ {
RETURN[CDBasics.BaseOfRect[
CDBasics.MapRect[
CD.InterestRect[CoreGeometry.GetObject[Sisyph.mode.decoration, cellInstance.type]],
CoreGeometry.GetTrans[Sisyph.mode.decoration, cellInstance]
]
]];
};
-- the cellType is a record with exactly two instances
SchChannel: PWCore.AttributesProc = {
-- inX if dx>dy; I know that tis implementation is bogus; used CDBasics
DecideIfInX:
PROC [i1, i2:
CD.Position]
RETURNS [inX:
BOOL] ~ {
dx: INT ← ABS[i1.x-i2.x];
dy: INT ← ABS[i1.y-i2.y];
RETURN[dx>dy];
};
CheckEachPin: CoreGeometry.EachWirePinProc = {
-- remember to include only atomic wires!!!
SELECT side
FROM
bottom => IF inX THEN bottomOrLeftWires ← CONS[wire, bottomOrLeftWires];
top => IF inX THEN topOrRightWires ← CONS[wire, topOrRightWires];
right => IF ~inX THEN topOrRightWires ← CONS[wire, topOrRightWires];
left => IF ~inX THEN bottomOrLeftWires ← CONS[wire, bottomOrLeftWires];
ENDCASE => ERROR;
};
channelData: ChannelData;
inX, verticalM2, flushTopOrRight: BOOL;
prop: REF;
bottomOrLeftWires, topOrRightWires: Wires ← NIL;
data: CoreClasses.RecordCellType ← NARROW[cellType.data];
width: INT;
prop ← CoreProperties.GetCellTypeProp[cellType, $VerticalMetal];
verticalM2 ←
IF prop#
NIL
THEN
NARROW[prop,
ATOM]=$Metal2
ELSE
TRUE;
-- default: metal2
prop ← CoreProperties.GetCellTypeProp[cellType, $FlushTopOrRight];
flushTopOrRight ←
IF prop#
NIL
THEN
NARROW[prop,
REF
BOOL]^
ELSE
TRUE;
-- default: flush the small guy to the right or to the top
prop ← CoreProperties.GetCellTypeProp[cellType, $TotalWidth];
width ←
IF prop#
NIL
THEN
NARROW[prop,
REF
INT]^
ELSE 0;
-- default: the router computes the width
IF data.size#2 THEN ERROR; -- exactly two cells per channel
inX ← DecideIfInX[Base[data.instances[0]], Base[data.instances[1]]];
PWCore.SortInstances[Sisyph.mode.decoration, cellType, IF inX THEN PWCore.SortInX ELSE PWCore.SortInY];
[] ← CoreGeometry.EnumerateWireSides[Sisyph.mode.decoration, cellType, CheckEachPin];
channelData ←
NEW[ChannelDataRec ← [
inX: inX,
extend: TRUE,
extendTopOrRight: flushTopOrRight,
bottomOrLeftWires: bottomOrLeftWires,
topOrRightWires: topOrRightWires,
trunkLayer: IF verticalM2=inX THEN "metal2" ELSE "metal",
branchLayer: IF verticalM2=inX THEN "metal" ELSE "metal2",
totalWidth: width]];
CoreProperties.PutCellTypeProp[cellType, $ChannelData, channelData];
};
SanityCheck:
PROC [cellType: CellType, wires: Wires, side: CoreGeometry.Side] = {
WHILE wires#
NIL
DO
EachSortedPin: CoreGeometry.EachSortedPinProc = {quit ← wire=wires.first};
IF wires.first.size=0 AND NOT CoreGeometry.EnumerateSortedSides[PWCore.extractMode.decoration, cellType, side, EachSortedPin] THEN SIGNAL SanityFailed[];
wires ← wires.rest;
ENDLOOP;
};
SanityFailed:
SIGNAL [] =
CODE;
-- call implementor
-- Given the layout associated with the cellType, this proc extracts all the pins located on the edge of the channel which have the appropriate layer and are part (full name) of the public of the channel; it assemble these pins into a fake object passed to the router.
MakeOutline:
PROC [cellInstance: CoreClasses.CellInstance, internal: Wire, iSide: CoreGeometry.Side, iLayer:
CD.Layer, iSize:
CD.Position, displacement:
INT]
RETURNS [obj:
CD.Object] ~ {
instances: CD.InstanceList ← NIL;
AddPinToOutline: CoreGeometry.EachWirePinProc ~ {
name: ROPE;
pos: CD.Position;
IF wire.size#0 THEN ERROR;
name ← CoreOps.GetFullWireNames[internal, CoreClasses.CorrespondingActual[cellInstance, wire]].first;
IF side#iSide OR layer#iLayer THEN RETURN;
pos ←
SELECT side
FROM
left => [0, min+displacement],
right => [iSize.x-minW, min+displacement],
top => [min+displacement, iSize.y-minW],
bottom => [min+displacement, 0],
ENDCASE => ERROR;
instances ←
CONS [
CDInstances.NewInst[CDSymbolicObjects.CreatePin[IF side=left OR side=right THEN [minW, max-min] ELSE [max-min, minW]], [pos]],
instances
];
CDSymbolicObjects.SetLayer[instances.first, layer];
CDSymbolicObjects.SetName[instances.first, name];
};
minW: INT ← CDSimpleRules.MinWidth[iLayer]-1;
[] ← PWCore.InterestRect[cellInstance.type]; -- to make sure the cellType is decorated
[] ← CoreGeometry.EnumerateNonOverlappingSides[PWCore.extractMode.decoration, cellInstance.type, AddPinToOutline];
obj ← PWObjects.CreateCell[instances, [0, 0, iSize.x, iSize.y]];
};
-- A cell containing only pins (plus a rectangle; hack!) whose posiiton and size does not matter; used to specify the sides of the channel to the router.
MakeFakeObject:
PROC [internal: Wire, sideWires:
LIST
OF Wire, inX:
BOOL, layer:
CD.Layer, purposeSide: CoreGeometry.Side]
RETURNS [obj:
PW.Object] ~ {
AppendPin:
PROC [wire: Wire] ~ {
name: ROPE ← CoreOps.GetFullWireNames[internal, wire].first;
instances ←
CONS [
CDInstances.NewInst[CDSymbolicObjects.CreatePin[[minW, minW]], [pos]],
instances
];
CDSymbolicObjects.SetLayer[instances.first, layer];
CDSymbolicObjects.SetName[instances.first, name];
pos ← IF inX THEN [pos.x+delta, pos.y] ELSE [pos.x, pos.y+delta];
};
minW: INT ← CDSimpleRules.MinWidth[layer];
delta: INT ← CDSimpleRules.MinDist[layer, layer]+minW;
pos: CD.Position ← [0, 0];
instances: CD.InstanceList ← LIST [CDInstances.NewInst[CDSimpleRules.Rect[[1, 1], CD.undefLayer], [[1, 1]]]]; -- to avoid reposionning empty cell
FOR list:
LIST
OF Wire ← sideWires, list.rest
WHILE list#
NIL
DO
IF list.first.size=0
THEN AppendPin[list.first]
ELSE [] ← CoreOps.VisitRootAtomics[list.first, AppendPin];
ENDLOOP;
obj ← PWObjects.CreateCell[instances, IF inX THEN [-minW, IF purposeSide=top THEN 0 ELSE -5*minW, pos.x, IF purposeSide=top THEN 10*minW ELSE minW] ELSE [IF purposeSide=left THEN -5*minW ELSE 0, -minW, IF purposeSide=left THEN minW ELSE 10*minW, pos.y]];
};
Filler:
PROC [sourceCT: CellType, inX:
BOOL, extLayer:
CD.Layer, extension:
INT, extendTopOrRight:
BOOL]
RETURNS [extended:
CD.Object] = {
source: CD.Object ← PWCore.Layout[sourceCT];
instances: CD.InstanceList ← NIL;
AddPinToExtension: CoreGeometry.EachWirePinProc = {
IF wire.size#0 THEN ERROR;
IF side#(IF inX THEN (IF extendTopOrRight THEN top ELSE bottom) ELSE (IF extendTopOrRight THEN right ELSE left)) OR layer#extLayer THEN RETURN;
instances ←
CONS [
CDInstances.NewInst[CDSimpleRules.Rect[IF inX THEN [max-min, extension] ELSE [extension, max-min], layer], [IF inX THEN [min, 0] ELSE [0, min]]],
instances
];
};
obj: CD.Object;
size: CD.Position ← CD.InterestSize[source];
IF extension=0 THEN RETURN [source];
[] ← PWCore.InterestRect[sourceCT]; -- to make sure the cellType is decorated
[] ← CoreGeometry.EnumerateNonOverlappingSides[PWCore.extractMode.decoration, sourceCT, AddPinToExtension];
obj ← PWObjects.CreateCell[instances, IF inX THEN [0, 0, size.x, extension] ELSE [0, 0, extension, size.y]];
extended ← (IF inX THEN PW.AbutY ELSE PW.AbutX)[IF extendTopOrRight THEN source ELSE obj, IF extendTopOrRight THEN obj ELSE source];
};
[] ← PWCore.RegisterLayoutAtom[$Channel, Channel, DecorateChannel];
[] ← PWCore.RegisterLayoutAtom[$CR, Channel, DecorateChannel, SchChannel];
END.