SCRouteImpl.mesa: Implementation of SC.DetailedRoute
Frank Bowers November 20, 1985 4:40:40 pm PST
DIRECTORY
CD,
CDBasics,
CDCells,
CDDirectory,
CDOrient,
CDPinObjects,
CDProperties,
CDRects,
PW,
PWPins,
PWRoute,
Rope,
Route,
RouteTechnology,
RTBasic,
SC,
SCChanUtil,
SCInstUtil,
SCPrivate,
SCRowUtil,
SCUtil;
SCRouteImpl: CEDAR PROGRAM
IMPORTS CDBasics, CDCells, CDDirectory, CDPinObjects, CDProperties, CDRects, PW, PWRoute, Rope, Route, RouteTechnology, SCChanUtil, SCInstUtil, SCRowUtil, SCUtil
EXPORTS SCPrivate
SHARES SC = BEGIN
RowCellArray: TYPE = ARRAY [1..SCPrivate.maxLgRows] OF PW.Object;
RowCells: TYPE = REF RowCellArray;
NumSeqRec: TYPE = RECORD [
c: SEQUENCE size: NAT OF REF SC.Number];
NumSeq: TYPE = REF NumSeqRec;
LRSide: TYPE = SCPrivate.LRSide;
TBSide: TYPE = SCPrivate.TBSide;
LayoutData: TYPE = SCPrivate.LayoutData;
ROPE: TYPE = Rope.ROPE;
PQPos: TYPE = RTBasic.PQPos;
CreatePinsForChannel: PROC [handle: SC.Handle, chan: NAT, rowCells: RowCells] =
BEGIN
side: SC.Side;
row: NAT ← 0;
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
lgRows: SCPrivate.LgRows ← layoutData.lgRows;
MakeNetPin: SCInstUtil.EachPinProc = {
[instance: SCPrivate.Instance, pin: NAT, netPin: SCPrivate.PinNet]
IF side = SCInstUtil.PosOf[instance, netPin.pin].sideOn THEN {
rect: CD.Rect ← SCInstUtil.RotateRect[instance, netPin.pin.rect];
pinOb: CD.Object ← CDPinObjects.CreatePinOb[CDBasics.SizeOfRect[rect]];
pinInst: CD.Instance;
position: CD.Position ← SCUtil.PQToXY[handle, [p: instance.offset + rect.x1, q: rect.y1]];
pinInst ← PW.IncludeInCell[cell: rowCells[row], obj: pinOb, position: position];
CDPinObjects.SetName[pinInst, netPin.net.name];
CDPinObjects.SetLayer[pinInst, netPin.pin.layer];
};
};
ForEachInstance: SCRowUtil.EachInstProc = {
[] ← SCInstUtil.EnumeratePinsOnInst[instance, MakeNetPin]};
IF chan = 1 THEN {
side ← bottom; row ← 1;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachInstance]}
ELSE IF chan = lgRows.count + 1 THEN {
side ← top; row ← lgRows.count;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachInstance]}
ELSE {
side ← top; row ← chan - 1;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachInstance];
side ← bottom; row ← chan;
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachInstance]};
END;
CreateExitsForChannel: PROC [handle: SC.Handle, rowChan: SCPrivate.RowChan, exitCells: REF ARRAY LRSide OF PW.ListOb] =
BEGIN
cell: CD.Object ← NIL;
parms: SCPrivate.Parms ← NARROW[handle.parms];
design: CD.Design ← parms.cdDesign;
CreateNewExit: SCChanUtil.EachExitProc = {
pinOb: CD.Object ← CDPinObjects.CreatePinOb[size: [0, 0]];
pinInst: CD.Instance ← PW.IncludeInCell[cell: cell, obj: pinOb];
CDPinObjects.SetName[pinInst, exit.net.name];
CDPinObjects.SetLayer[pinInst, exit.layer];
};
FOR side: LRSide IN LRSide DO
cell ← PW.CreateEmptyCell[];
[] ← SCChanUtil.EnumerateExits[handle, rowChan, side, CreateNewExit];
PW.IncludeInDirectory[design, cell, "Exits"];
exitCells[side] ← CONS[cell, exitCells[side]];
ENDLOOP;
END;
RouteChannelRetrieveImpl.StitchVias accross where branch overlaps trunk
CreateWireAndContact: PROC [
handle: SC.Handle, pin: PW.Instance, length: CD.Number, trunkLayer: CD.Layer]
RETURNS [obj: CD.Object] =
BEGIN
parms: SCPrivate.Parms ← NARROW[handle.parms];
design: CD.Design ← parms.cdDesign;
wire, contact: CD.Object;
obj ← PW.CreateEmptyCell[];
wire ← CreateWireFromPin[handle, pin, length, design];
contact ← RouteTechnology.GetContact[handle.rules.sideRules, CDPinObjects.GetLayer[pin], trunkLayer];
[] ← PW.IncludeInCell[obj, wire];
[] ← PW.IncludeInCell[obj, contact, [length-contact.size.x, 0]];
PW.IncludeInDirectory[design, obj, "Wire"];
END;
CreateWireFromPin: PROC [handle: SC.Handle, pin: PW.Instance, length: CD.Number, design: CD.Design]
RETURNS [wire: CD.Object] =
BEGIN
wx: CD.Number ← length;
wy: CD.Number ← pin.ob.size.y;
wSize: CD.Position ← SCUtil.PQToXY[handle, [wx, wy]];
layer: CD.Layer ← CDPinObjects.GetLayer[pin];
wire ← CDRects.CreateRect[wSize, layer];
END;
GetPinPos: PROC [handle: SC.Handle, wireLen: CD.Number, inst: PW.Instance, side: LRSide]
RETURNS [pos: CD.Position] =
BEGIN
pos ← [0, 0];
pos.x ← SELECT side FROM
left => 0,
right => wireLen - inst.ob.size.x,
ENDCASE => ERROR;
pos ← SCUtil.PQToXY[handle, [pos.x, pos.y]];
END;
AlwaysExtendPin: PROC [handle: SC.Handle, inst: PW.Instance, extLen: CD.Number]
RETURNS [obj: CD.Object] =
BEGIN
create wire and copy pin to end of wire
parms: SCPrivate.Parms ← NARROW[handle.parms];
design: CD.Design ← parms.cdDesign;
pinOb, wire: CD.Object;
pinInst: CD.Instance;
pinSize: CD.Position ← SCUtil.PQToXY[handle, [inst.ob.size.x, inst.ob.size.y]];
obj ← PW.CreateEmptyCell[];
wire ← CreateWireFromPin[handle, inst, extLen, design];
pinOb ← CDPinObjects.CreatePinOb[pinSize];
[] ← PW.IncludeInCell[obj, wire];
pinInst ← PW.IncludeInCell[obj, pinOb, [extLen-inst.ob.size.x, 0]];
CDPinObjects.SetName[pinInst, CDPinObjects.GetName[inst]];
CDPinObjects.SetLayer[pinInst, CDPinObjects.GetLayer[inst]];
PW.IncludeInDirectory[design, obj, "Wire"];
END;
ExtendPowerBuses: PROC [handle: SC.Handle, design: CD.Design, rowList: PW.ListOb]
RETURNS [rows: PW.ListOb ← NIL] =
BEGIN
extend power buses to length of longest row
ext: ARRAY LRSide OF PW.Object ← ALL[NIL];
extLen: CD.Number;
side: LRSide;
rl: PW.ListOb ← NIL;
abutOb: PW.Object;
pwSide: PWPins.Side;
layout: LayoutData ← NARROW[handle.layoutData];
maxRowLength: CD.Number ← SCRowUtil.FindMaxRow[handle].maxRowWidth;
ExtendPin: PW.ForEachPinProc = {
obj ← AlwaysExtendPin[handle, inst, extLen]};
FOR rl ← rowList, rl.rest UNTIL rl = NIL DO
rowLength: CD.Number ← PW.IRSize[rl.first].x;
ext ← ALL[NIL];
IF rowLength < maxRowLength THEN
FOR side IN LRSide DO
extLen ← SELECT side FROM
left => (maxRowLength - rowLength)/2,
right => maxRowLength - rowLength - (maxRowLength - rowLength)/2,
ENDCASE => ERROR;
pwSide ← SELECT side FROM right => right, left => left, ENDCASE => ERROR;
ext[side] ← PW.TransferCell[design: design, template: rl.first, objSide: pwSide, width: extLen, objProc: ExtendPin];
ENDLOOP;
abutOb ← PW.AbutListX[design, LIST [ext[left], rl.first, ext[right]]];
rows ← CONS[CDDirectory.Expand[me: abutOb, to: design, from: design], rows];
ENDLOOP;
END;
CreateRowCell: PROC [handle: SC.Handle, row: NAT, rowList: PW.ListOb, rowCells: RowCells]
RETURNS [PW.ListOb] =
BEGIN
parms: SCPrivate.Parms ← NARROW[handle.parms];
design: CD.Design ← parms.cdDesign;
rowOb: PW.Object ← NIL;
listOb: PW.ListOb ← NIL;
rCell: CD.Object ← NIL; -- cell obtained from rowOb
ForEachInstance: SCRowUtil.EachInstProc = {
thisObj: CD.Object ← instance.object.cdOb;
listOb ← CONS[thisObj, listOb]};
[] ← SCRowUtil.EnumerateAllInstsOnRow[handle, row, ForEachInstance];
listOb ← PW.Reverse[listOb];
rowOb ← PW.AbutListX[design: design, listOb: listOb];
rCell ← CDDirectory.Expand[me: rowOb, from: design, to: design];
rowList ← CONS[rCell, rowList];
rowCells[row] ← rCell;
RETURN[rowList];
END;
EnablePinDeepEnumeration: PROC [rowList: PW.ListOb] =
BEGIN
FOR rl: PW.ListOb ← rowList, rl.rest UNTIL rl = NIL DO
cellPtr: CD.CellPtr ← NARROW[rl.first.specificRef];
FOR list: CD.InstanceList ← cellPtr.contents, list.rest UNTIL list = NIL DO
IF CDCells.IsCell[list.first.ob] THEN {
cp: CD.CellPtr ← NARROW[list.first.ob.specificRef];
FOR iList: CD.InstanceList ← cp.contents, iList.rest UNTIL iList = NIL DO
IF CDCells.IsCell[iList.first.ob] THEN
CDProperties.PutPropOnInstance[iList.first, $StopEnumerateDeepPins, NIL];
ENDLOOP;
};
ENDLOOP;
ENDLOOP;
END;
DisablePinDeepEnumeration: PROC [rowList: PW.ListOb] =
BEGIN
FOR rl: PW.ListOb ← rowList, rl.rest UNTIL rl = NIL DO
cellPtr: CD.CellPtr ← NARROW[rl.first.specificRef];
FOR list: CD.InstanceList ← cellPtr.contents, list.rest UNTIL list = NIL DO
IF CDCells.IsCell[list.first.ob] THEN {
cp: CD.CellPtr ← NARROW[list.first.ob.specificRef];
FOR iList: CD.InstanceList ← cp.contents, iList.rest UNTIL iList = NIL DO
IF CDCells.IsCell[iList.first.ob] THEN
CDProperties.PutPropOnInstance[iList.first, $StopEnumerateDeepPins, $TRUE];
ENDLOOP;
};
ENDLOOP;
ENDLOOP;
END;
LogicRoute: PROC [handle: SC.Handle, design: CD.Design] RETURNS [logicOb: PW.Object] =
BEGIN
exitCells: REF ARRAY LRSide OF PW.ListOb ← NEW[ARRAY LRSide OF PW.ListOb ← ALL[NIL]];
rowList: PW.ListOb ← NIL;
rowCells: RowCells ← NEW[RowCellArray];
abutOb: PW.Object;
ForEachRow: SCRowUtil.EachRowProc = {
rowList ← CreateRowCell[handle, row, rowList, rowCells];
};
ForEachChannel: SCChanUtil.EachRowChanProc = {
CreatePinsForChannel[handle: handle, chan: chan, rowCells: rowCells];
CreateExitsForChannel[handle: handle, rowChan: rowChan, exitCells: exitCells];
};
SCInstUtil.AllOffsets[handle];
[] ← SCRowUtil.EnumerateRows[handle: handle, eachRow: ForEachRow];
[] ← SCChanUtil.EnumerateRowChans[handle: handle, eachRowChan: ForEachChannel];
rowList ← ExtendPowerBuses[handle, design, rowList];
logicOb ← rowCells[1];
DisablePinDeepEnumeration[rowList];
abutOb ← PWRoute.AbutChRouteListY[
design: design, listOb: rowList, rightListOb: exitCells[right], leftListOb: exitCells[left]
! Route.Signal => RESUME];
logicOb ← CDDirectory.Expand[me: abutOb, to: design, from: design];
EnablePinDeepEnumeration[rowList];
END;
IncludeTrunkPin: PROC [handle: SC.Handle, cell: CD.Object, name: ROPE, tbSide: TBSide, trunkSize, trunkPos: PQPos, layer: CD.Layer] =
BEGIN
pin: CD.Object ← CDPinObjects.CreatePinOb[[trunkSize.p, trunkSize.p]];
pos: CD.Position;
pinInst: CD.Instance;
trunkPos.q ← trunkPos.q + (IF tbSide = top THEN trunkSize.q - trunkSize.p ELSE 0);
pos ← SCUtil.PQToXY[handle, trunkPos];
pinInst ← PW.IncludeInCell[cell, pin, pos];
CDPinObjects.SetName[pinInst, name];
CDPinObjects.SetLayer[pinInst, layer];
END;
PowerRoute: PROC [handle: SC.Handle, pwOb: PW.Object, design: CD.Design]
RETURNS [ob: PW.Object] =
BEGIN
ext end power pins on edges and put in power rails
ext: ARRAY LRSide OF PW.Object ← ALL[NIL];
trunkLayer: CD.Layer ← handle.rules.sideRules.trunkLayer;
pwSide: PWPins.Side;
pBus: SCPrivate.PowerBus;
side: LRSide;
trunk, abutOb: CD.Object;
trunkSize, trunkPos: PQPos;
extLen, width, trunkWidth: SC.Number;
layout: LayoutData ← NARROW[handle.layoutData];
ExtendPin: PW.ForEachPinProc = {
name: ROPE ← CDPinObjects.GetName[inst];
otherPBus: SCPrivate.PowerBus = layout.powerBuses[IF side = right THEN left ELSE right];
SELECT TRUE FROM
Rope.Equal[name, pBus.name] =>
obj ← CreateWireAndContact[handle, inst, width, trunkLayer];
Rope.Equal[name, otherPBus.name] => NULL;
ENDCASE => obj ← AlwaysExtendPin[handle, inst, width]};
FOR side IN LRSide DO
pBus ← layout.powerBuses[side];
width ← 20; -- pBus.width; (width was 0)?
trunkWidth ← 10; -- pBus.net.trunkWidth; (net was NIL)?
extLen ← width - trunkWidth;
trunkSize ← [p: trunkWidth, q: PW.IRSize[pwOb].y];
trunkPos ← [IF side = right THEN extLen ELSE 0, 0];
pwSide ← SELECT side FROM right => right, left => left, ENDCASE => ERROR;
ext[side] ← PW.TransferCell[design: design, template: pwOb, objSide: pwSide, width: width, objProc: ExtendPin];
trunk ← MakeTrunk[handle: handle, trunkSize: trunkSize, lev: trunkLayer];
[] ← PW.IncludeInCell[ext[side], trunk, SCUtil.PQToXY[handle, trunkPos]];
FOR tbSide: TBSide IN TBSide DO
IncludeTrunkPin[handle, ext[side], pBus.name, tbSide, trunkSize, trunkPos , trunkLayer];
ENDLOOP;
ENDLOOP;
abutOb ← PW.AbutListX[design, LIST [ext[left], pwOb, ext[right]]];
ob ← CDDirectory.Expand[me: abutOb, to: design, from: design];
END;
MakeTrunk: PROC [handle: SC.Handle, trunkSize: PQPos, lev: CD.Layer]
RETURNS [obj: CD.Object] =
BEGIN
parms: SCPrivate.Parms ← NARROW[handle.parms];
design: CD.Design ← parms.cdDesign;
obj ← CDRects.CreateRect[SCUtil.PQToXY[handle, trunkSize], lev];
END;
AcBusForName: PROC [handle: SC.Handle, side: LRSide, name: ROPE] RETURNS [acBus: SCPrivate.AcBus ← NIL, i: NAT] =
BEGIN
layout: LayoutData ← NARROW[handle.layoutData];
sigs: SCPrivate.AcBusSigs ← layout.acBuses[side].sigs;
FOR i IN [0..sigs.size) DO
IF Rope.Equal[name, sigs[i].name] THEN RETURN [sigs[i], i];
ENDLOOP;
END;
ComputeTrunkEnd: PROC [trunkEnd: NumSeq, q: SC.Number, index: NAT, fromTB: TBSide] =
BEGIN
prev: REF SC.Number ← trunkEnd[index];
trunkEnd[index] ← NEW[SC.Number];
trunkEnd[index]^ ← IF prev = NIL THEN q ELSE SELECT fromTB FROM
top => MIN[q, prev^],
bottom => MAX[q, prev^],
ENDCASE => ERROR;
END;
CreateAcTrunks: PROC [handle: SC.Handle, cell: CD.Object, acBusSide: SCPrivate.AcBusSides, trunkEnd: NumSeq, layer: CD.Layer] =
BEGIN
side: LRSide;
trunk: CD.Object;
trunkSize, trunkPos: PQPos;
bus: SCPrivate.AcBus;
parms: SCPrivate.Parms ← NARROW[handle.parms];
design: CD.Design ← parms.cdDesign;
FOR i: NAT IN [0..acBusSide.sigs.size) DO
bus ← acBusSide.sigs[i];
side ← bus.onSide;
trunkPos.p ← SELECT side FROM
left => PW.IRSize[cell].x - bus.depth, right => bus.depth, ENDCASE => ERROR;
trunkPos.q ← SELECT bus.fromTB FROM
bottom => 0, top => trunkEnd[i]^, ENDCASE => ERROR;
trunkSize.p ← bus.net.trunkWidth;
trunkSize.q ← SELECT bus.fromTB FROM
bottom => trunkEnd[i]^, top => PW.IRSize[cell].y - trunkEnd[i]^, ENDCASE => ERROR;
trunk ← MakeTrunk[handle: handle, trunkSize: trunkSize, lev: layer];
[] ← PW.IncludeInCell[cell, trunk, SCUtil.PQToXY[handle, trunkPos]];
IncludeTrunkPin[handle, cell, bus.name, bus.fromTB, trunkSize, trunkPos, layer];
ENDLOOP;
END;
ClockRoute: PROC [handle: SC.Handle, pwOb: PW.Object, design: CD.Design]
RETURNS [ob: PW.Object] =
BEGIN
trunkEnd: NumSeq; -- "q" coordinate of trunk end point
ext: ARRAY LRSide OF PW.Object ← ALL[NIL];
trunkLayer: CD.Layer ← handle.rules.sideRules.trunkLayer;
side: LRSide;
abutOb: CD.Object;
pwSide: PWPins.Side;
width: SC.Number;
layout: LayoutData ← NARROW[handle.layoutData];
ExtendPin: PW.ForEachPinProc = {
[inst: Instance] RETURNS [obj: Object];
pinName: ROPE ← CDPinObjects.GetName[inst];
acBus: SCPrivate.AcBus;
sigIndex: NAT;
[acBus, sigIndex] ← AcBusForName[handle, side, pinName];
IF acBus = NIL THEN obj ← AlwaysExtendPin[handle, inst, width]
ELSE {
ComputeTrunkEnd[trunkEnd: trunkEnd, q: inst.location.y, index: sigIndex, fromTB: acBus.fromTB];
obj ← CreateWireAndContact[handle, inst, acBus.depth, trunkLayer]};
};
FOR side IN LRSide DO
acBusSide: SCPrivate.AcBusSides ← layout.acBuses[side];
IF acBusSide = NIL OR acBusSide.sigs = NIL THEN LOOP;
trunkEnd ← NEW[NumSeqRec[acBusSide.sigs.size]];
FOR i: NAT IN [0..trunkEnd.size) DO trunkEnd[i] ← NIL; ENDLOOP;
pwSide ← SELECT side FROM right => right, left => left, ENDCASE => ERROR;
width ← acBusSide.width;
ext[side] ← PW.TransferCell[design: design, template: pwOb, objSide: pwSide, width: width, objProc: ExtendPin];
CreateAcTrunks[handle, ext[side], acBusSide, trunkEnd, trunkLayer];
ENDLOOP;
abutOb ← PW.AbutListX[design, LIST [ext[left], pwOb, ext[right]]];
ob ← CDDirectory.Expand[me: abutOb, to: design, from: design];
END;
IORoute: PROC [handle: SC.Handle, pwOb: PW.Object, design: CD.Design]
RETURNS [ob: PW.Object] =
BEGIN
layout: LayoutData ← NARROW[handle.layoutData];
bpRows: SCPrivate.BpRows ← layout.bpRows;
FOR side: SC.Side IN SC.Side DO
IF bpRows[side].fnlBpFxd THEN {
expand bprow to length of corresponding cell's side.
PWRoute.AbutRoute to pwOb
SCInstutil.BpPos
right side => position in bp
bottom => origin lower left hand side
top => lower right hand side origin
left => upper left side
};
ENDLOOP;
BpRowRec: TYPE = RECORD [
bpSpacing: INT ← 0,
size, sideOrg: PQPos ← [0, 0], -- sideorg is origin of side
dimInvalid: BOOLEANTRUE,
initMaxBpsOnSide, maxBpsOnSide, nBpsOnSide: ZMaxPosSr ← 0,
bpsOnSide: ARRAY ZMaxPosSr OF Instance ← ALL[NIL],
fnlBpFxd, initBpFxd, routeSideChans: BOOLEANFALSE];
handle: for each side for which side.fnlBpFxd invoke PWRoute.AbutRoute else
extend exit pins to edge of cell
END;
DetailRoute: PUBLIC PROC [handle: SC.Handle] RETURNS [result: SC.Result] =
BEGIN
pwOb: PW.Object ← NIL;
parms: SCPrivate.Parms ← NARROW[handle.parms];
design: CD.Design ← parms.cdDesign;
pwOb ← LogicRoute[handle, design];
pwOb ← PowerRoute[handle, pwOb, design];
pwOb ← ClockRoute[handle, pwOb, design];
result ← NEW[SC.ResultRec ← []];
result.object ← pwOb;
result.handle ← handle;
pwOb ← IORoute[handle, pwOb, design];
END;
END.