Channel:
PUBLIC PWCore.LayoutProc = {
data: CoreClasses.RecordCellType ← NARROW [cellType.data];
leftOrBottomCT: CellType ← data[0].type;
rightOrTopCT: CellType ← data[1].type;
leftOrBottom: CD.Object ← PWCore.Layout[leftOrBottomCT];
rightOrTop: CD.Object ← PWCore.Layout[rightOrTopCT];
obj1, obj2, bottomOrLeftObj, topOrRightObj, channel, extended1, extended2: PW.Object;
params: PWRoute.RouterParams;
channelData: ChannelData ← NARROW [CoreProperties.GetCellTypeProp[cellType, $ChannelData]];
inX: BOOL ← channelData.inX;
leftOrBottomHeight: INT ← IF inX THEN CD.InterestSize[leftOrBottom].y ELSE CD.InterestSize[leftOrBottom].x;
rightOrTopHeight: INT ← IF inX THEN CD.InterestSize[rightOrTop].y ELSE CD.InterestSize[rightOrTop].x;
leftOrBottomExtend: INT ← IF channelData.extend THEN MAX[leftOrBottomHeight, rightOrTopHeight] - leftOrBottomHeight ELSE 0;
rightOrTopExtend: INT ← IF channelData.extend THEN MAX[leftOrBottomHeight, rightOrTopHeight] - rightOrTopHeight ELSE 0;
trLayer: CD.Layer ← CDSimpleRules.GetLayer[technologyKey, channelData.trunkLayer];
brLayer: CD.Layer ← CDSimpleRules.GetLayer[technologyKey, channelData.branchLayer];
IF data.size#2 THEN ERROR;
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 (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 ← [
trunkLayer: channelData.trunkLayer,
branchLayer: channelData.branchLayer,
technologyKey: technologyKey,
signalSinglePinNets: FALSE, -- SIGNAL if there are any single pin nets
opt: noIncompletes -- return the first correct routing
]];
channel ← PWRoute.MakeChannel[
obj1: obj1, obj2: obj2,
bottomOrLeftObj: bottomOrLeftObj, topOrRightObj: topOrRightObj,
params: params,
isX: channelData.inX ! Route.Signal => {IF errorType=callingError THEN RESUME ELSE PW.WriteF["*** Routing warning: %g\n", IO.rope[explanation]]}];
IF channel=NIL OR NARROW [channel.specificRef, CD.CellPtr].contents=NIL THEN ERROR;
obj ← (IF inX THEN PW.AbutX ELSE PW.AbutY)[extended1, channel, extended2];
};
MakeOutline:
PROC [cellInstance: CoreClasses.CellInstance, internal: Wire, iSide: PWCore.Side, iLayer:
CD.Layer, iSize:
CD.Position, displacement:
INT]
RETURNS [obj:
CD.Object] ~ {
AddPinToOutline: PWCore.EachWirePinProc ~ {
inst: CD.Instance;
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;
inst ← PW.IncludeInCell[obj, CDSymbolicObjects.CreatePin[IF side=left OR side=right THEN [minW, max-min] ELSE [max-min, minW]], pos];
CDSymbolicObjects.SetLayer[inst, layer];
CDSymbolicObjects.SetName[inst, name];
};
minW: INT ← CDSimpleRules.MinWidth[iLayer]-1;
obj ← PW.CreateEmptyCell[];
[] ← PWCore.EnumerateWirePins[cellInstance.type, AddPinToOutline];
PW.SetInterestRect[obj, iSize];
PW.RepositionCell[obj];
obj ← obj; -- for debugging
};
MakeFakeObject:
PROC [internal: Wire, sideWires:
LIST
OF Wire, inX:
BOOL, layer:
CD.Layer, purposeSide: PWCore.Side]
RETURNS [obj:
PW.Object] ~ {
AppendPin:
PROC [wire: Wire] ~ {
inst: CD.Instance;
name: ROPE ← CoreOps.GetFullWireNames[internal, wire].first;
inst ← PW.IncludeInCell[obj, CDSymbolicObjects.CreatePin[[minW, minW]], pos];
CDSymbolicObjects.SetLayer[inst, layer];
CDSymbolicObjects.SetName[inst, 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];
obj ← PW.CreateEmptyCell[];
[] ← PW.IncludeInCell[obj, 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
[] ← CoreOps.VisitAtomicWires[list.first, AppendPin];
ENDLOOP;
[] ← CDCells.SetInterestRect[obj, 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]];
PW.RepositionCell[obj];
};
Filler:
PROC [sourceCT: CellType, inX:
BOOL, extLayer:
CD.Layer, extension:
INT, extendTopOrRight:
BOOL]
RETURNS [extended:
CD.Object] = {
source: CD.Object ← PWCore.Layout[sourceCT];
AddPinToExtension: PWCore.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;
[] ←
PW.IncludeInCell[
obj,
CDSimpleRules.Rect[IF inX THEN [max-min, extension] ELSE [extension, max-min], layer],
IF inX THEN [min, 0] ELSE [0, min]
];
};
obj: CD.Object;
size: CD.Position ← CD.InterestSize[source];
IF extension=0 THEN RETURN [source];
obj ← PW.CreateEmptyCell[];
[] ← PWCore.EnumerateWirePins[sourceCT, AddPinToExtension];
PW.SetInterestRect[obj, IF inX THEN [size.x, extension] ELSE [extension, size.y]];
PW.RepositionCell[obj];
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];