SCUtilImpl.mesa
Copyright Ó 1985, 1986, 1987 by Xerox Corporation. All rights reserved.
Bryan Preas, November 3, 1987 3:17:15 pm PST
Christian Le Cocq September 27, 1988 4:00:08 pm PDT
Cong, August 27, 1987 2:58:51 pm PDT
Jean-Marc Frailong October 11, 1987 3:11:18 pm PDT
DIRECTORY
Ascii, Basics, CD, CDSymbolicObjects, Core, CoreGeometry, CoreProperties, IO, RedBlackTree, Rope, Rsh, RTBasic, RTCoreUtil, SC, SCInstUtil, SCPrivate, SCUtil, TerminalIO, UnixRemoteFile, UserCredentials;
SCUtilImpl: CEDAR PROGRAM
IMPORTS Ascii, Basics, CoreProperties, IO, RedBlackTree, Rope, Rsh, RTBasic, RTCoreUtil, SC, SCInstUtil, TerminalIO, UnixRemoteFile, UserCredentials
EXPORTS SCUtil
SHARES SC =
BEGIN
twDoGlobalRoute: BOOLEANFALSE;
RowArray: TYPE = REF RowArrayRec;
RowArrayRec: TYPE = ARRAY SCPrivate.MaxChanSr OF SC.Number;
fileHost: Rope.ROPE ← "palain-NFS";
cpuHost: Rope.ROPE ← "palain";
serverDir: Rope.ROPE ← "/timberwolf/";
remoteServer: Rope.ROPE ← "/palain/";
remoteServerDir: Rope.ROPE ← Rope.Cat[remoteServer, GuessUnixName[], serverDir];
twCmd: Rope.ROPE ← "/usr/datools/TimberWolfSCrsh ";
fileMode: UnixRemoteFile.Mode ← 0666B;
Not yet converted
FindPin: PUBLIC PROC [object: SCPrivate.Object, pinName: Rope.ROPE] RETURNS [pin: SCPrivate.ObjectPin ← NIL] =
BEGIN
pins: SCPrivate.ObjectPins ← object.pins;
FOR pinIndex: NAT IN [0 .. object.numPins) WHILE pin = NIL DO
IF Rope.Equal[pinName, pins.p[pinIndex].name] THEN pin ← pins.p[pinIndex];
ENDLOOP;
END;
FindPinByWire: PUBLIC PROC [object: SCPrivate.Object, wire: Core.Wire] RETURNS [pin: SCPrivate.ObjectPin ← NIL] =
BEGIN
pins: SCPrivate.ObjectPins ← object.pins;
FOR pinIndex: NAT IN [0 .. object.numPins) WHILE pin = NIL DO
IF wire = pins.p[pinIndex].publicWire THEN pin ← pins.p[pinIndex];
ENDLOOP;
END;
FindInstance: PUBLIC PROC [handle: SC.Handle, instanceName: Rope.ROPE] RETURNS [instance: SCPrivate.Instance ← NIL] =
BEGIN
structureData: SCPrivate.StructureData ← NARROW[handle.structureData];
instances: SCPrivate.Instances ← structureData.instances;
FOR instanceIndex: NAT IN [1 .. instances.count] WHILE instance = NIL DO
IF Rope.Equal[instanceName, instances.inst[instanceIndex].name] THEN instance ← instances.inst[instanceIndex];
ENDLOOP;
END;
IsPowerName: PUBLIC PROC [handle: SC.Handle, name: Rope.ROPE] RETURNS [found: BOOLEANFALSE] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
powerBuses: SCPrivate.PowerBuses ← layoutData.powerBuses;
IF Rope.Equal[name, powerBuses[left].name, FALSE] OR Rope.Equal[name, powerBuses[right].name, FALSE] THEN found ← TRUE};
DirectionFromSide: PUBLIC PROC [side: CoreGeometry.Side] RETURNS [CDSymbolicObjects.Direction] ~ {
RETURN[SELECT side FROM
bottom=> south, right => east, top => north, left => west, ENDCASE => SC.Error[callingError, "Not suppose to happen."]]};
WriteResults: PUBLIC PROC [title: Rope.ROPE, handle: SC.Handle, startArea: SC.Number] RETURNS [area: SC.Number] = {
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
lambda: SC.Number ← handle.rules.rowParms.technology.lambda;
width: SC.Number ← layoutData.totWidth/lambda;
height: SC.Number ← layoutData.totHeight/lambda;
area ← width*height;
TerminalIO.PutRope[title];
TerminalIO.PutF1[" width = %g", IO.int[width]];
TerminalIO.PutF1[", height = %g", IO.int[height]];
TerminalIO.PutF1[", area = %g", IO.int[area]];
IF startArea > 0 THEN {
reduction: SC.Number ← (startArea - area)*100/startArea;
TerminalIO.PutRope[IO.PutFR[" reduction = %g%%\n", IO.real[reduction]]]};
TerminalIO.PutRope["\n"];
};
WriteStructure: PUBLIC PROC [handle: SC.Handle] = {
EachInstance: SCInstUtil.EachInstanceProc = {
EachPin: SCInstUtil.EachPinProc = {
TerminalIO.PutRope[Rope.Cat[" Pin: ", netPin.pin.name, " Net: ", netPin.net.name, "\n"]]};
TerminalIO.PutRope[Rope.Cat[" Instance: ", instance.name, " Object: ", instance.object.name, "\n"]];
[] ← SCInstUtil.EnumeratePinsOnInst[instance, EachPin]};
TerminalIO.PutRope[Rope.Cat["Handle: ", handle.name, "\n"]];
[] ← SCInstUtil.EnumerateAllInstances[handle, EachInstance]};
XYToPQ: PUBLIC PROC [handle: SC.Handle, pos: SC.Pos] RETURNS [pqPos: RTBasic.PQPos] = {
convert a position from x-y to p-q space.
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
rowDirection: SC.Direction ← layoutData.layoutParms.rowDirection;
RETURN[RTBasic.XYToPQ[rowDirection, pos]]};
PQToXY: PUBLIC PROC [handle: SC.Handle, pqPos: RTBasic.PQPos] RETURNS [pos: SC.Pos] = {
convert a position from p-q to x-y space.
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
rowDirection: SC.Direction ← layoutData.layoutParms.rowDirection;
RETURN[RTBasic.PQToXY[rowDirection, pqPos]]};
DestroyRules: PUBLIC PROC [handle: SC.Handle] ~ {
rules: SC.DesignRules ← handle.rules;
rules.rowRules.technology ← NIL;
rules.rowRules ← NIL;
rules.sideRules.technology ← NIL;
rules.sideRules ← NIL;
handle.rules ← NIL};
DestroyParms: PUBLIC PROC [handle: SC.Handle] = {
parms: SCPrivate.Parms ← NARROW[handle.parms];
parms.libDesign ← NIL;
parms.ftObject ← NIL;
parms.portObject ← NIL;
handle.parms ← NIL};
Memb: PROC [rope: Rope.ROPE, list: LIST OF Rope.ROPE] RETURNS [BOOL] = {
UNTIL list = NIL DO
IF Rope.Equal[list.first, rope] THEN RETURN[TRUE];
list ← list.rest;
ENDLOOP;
RETURN[FALSE];
};
GetCoreInvestmentProp: PUBLIC PROC [cellType: Core.CellType, prop: ATOM] RETURNS [SC.HowLongToWork] ~ {
get an investment property from a cell
value: ATOMNARROW[CoreProperties.GetCellTypeProp[cellType, prop]];
investment: SC.HowLongToWork ← SELECT value FROM
SC.veryLongValue => veryLong,
SC.longValue => long,
SC.mediumValue => medium,
SC.shortValue => short,
SC.veryShortValue => veryShort,
ENDCASE => noInvestmentProp;
RETURN[investment]};
WriteTWFiles: PUBLIC PROC [handle: SC.Handle] ~ {
write the timberWolf files
EachInstance: SCInstUtil.EachInstanceProc ~ {
PROC [instance: SCPrivate.Instance] RETURNS [quit: BOOLFALSE];
EachPin: SCInstUtil.EachPinProc ~ {
PROC [instance: SCPrivate.Instance, pin: NAT, netPin: SCPrivate.PinNet] RETURNS [quit: BOOLFALSE];
IF netPin.net # NIL THEN
AddPin[celStream, instance, netPin.pin, netPin.net, ~SeenBefore[netPin.net, netsOnInst], handle]; -- for TimberWolf .cel file
netsOnInst ← CONS[netPin.net, netsOnInst]};
netsOnInst: LIST OF SCPrivate.Net ← NIL;
IF instance.whichClass = logic THEN { -- for TimberWolf .cel file
AddCell[celStream, instance, handle, instNumber, offsetsOnRow]; instNumber ← instNumber+1;
[] ← SCInstUtil.EnumeratePinsOnInst[instance, EachPin]}
ELSE IF instance.whichClass = io THEN
AddPad[padTable, instance]};
attPerCell: CARD ← RTCoreUtil.GetCoreIntProp[handle.coreCellType, $TWattPerCell, 0];
filePathName: Rope.ROPE ← Rope.Cat[remoteServerDir, handle.name];
server: UnixRemoteFile.UnixServerHandle ← UnixRemoteFile.CreateHandle[fileHost];
netStream: IO.STREAM ← UnixRemoteFile.OpenWriteStream[server, [Rope.Cat[filePathName, ".net"]], fileMode];
parStream: IO.STREAM ← UnixRemoteFile.OpenWriteStream[server, [Rope.Cat[filePathName, ".par"]], fileMode];
blkStream: IO.STREAM ← UnixRemoteFile.OpenWriteStream[server, [Rope.Cat[filePathName, ".blk"]], fileMode];
celStream: IO.STREAM ← UnixRemoteFile.OpenWriteStream[server, [Rope.Cat[filePathName, ".cel"]], fileMode];
padTable: RedBlackTree.Table ← RedBlackTree.Create[GetKey, Compare];
parms: SCPrivate.Parms ← NARROW[handle.parms];
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
instNumber: NAT ← 1; -- used to number instances of cells & pads in the TW file ???
offsetsOnRow: RowArray ← NEW[RowArrayRec ← ALL[0]];
first the net file
IO.Put[netStream, IO.rope["allnets HVweights 1.0 1.0\l"]];
IO.Flush[netStream];
IO.Close[netStream];
next the parameter file
IF attPerCell>0 THEN IO.PutF[parStream, "att.per.cell %d\l", IO.card[attPerCell]];
IO.Put[parStream, IO.rope["rowSep 2.0\l"]];
IO.Put[parStream, IO.rope["indent 0.85\l"]];
IO.Put[parStream, IO.rope["addFeeds\l"]];
IO.Put[parStream, IO.rope["feedThruWidth "], ScaleOut[parms.ftObject.size.p, handle], IO.rope["\l"]];
IO.Put[parStream, IO.rope["implicit.feed.thru.range 0.25\l"]];
IF twDoGlobalRoute THEN IO.Put[parStream, IO.rope["do.global.route\l"]];
IO.Flush[parStream];
IO.Close[parStream];
next the row definitions
FOR row: INT IN [1 .. layoutData.lgRows.count] DO
IO.Put[blkStream, IO.rope["block height "], ScaleOut[parms.ftObject.size.q, handle], IO.rope[" class 1\l"]];
ENDLOOP;
IO.Flush[blkStream];
IO.Close[blkStream];
finally the connectivity
[] ← SCInstUtil.EnumerateAllInstances[handle, EachInstance];
CopyPadToCel[celStream, padTable, handle, instNumber]; -- pads must go at the end in position order
IO.Flush[celStream];
IO.Close[celStream];
UnixRemoteFile.DestroyHandle[server];
};
SeenBefore: PROC [net: SCPrivate.Net, netList: LIST OF SCPrivate.Net] RETURNS [BOOL] ~ {
RETURN TRUE iff net is on netList
UNTIL netList = NIL DO
IF netList.first = net THEN RETURN [TRUE];
netList ← netList.rest;
ENDLOOP;
RETURN [FALSE]};
AddCell: PROC [celStream: IO.STREAM, instance: SCPrivate.Instance, handle: SC.Handle, number: NAT, offsetsOnRow: RowArray] ~ {
add a cell to the .cel file
middleX: INT ← instance.object.orgin.p + instance.object.size.p/2;
middleY: INT ← instance.object.orgin.q + instance.object.size.q/2;
layoutData: SCPrivate.LayoutData ← NARROW[handle.layoutData];
IO.Put[celStream, IO.rope["cell "], IO.int[number]];
IO.Put[celStream, IO.rope[" "], IO.rope[instance.name]];
IO.Put[celStream, IO.rope["\l"]];
IF 1 <= instance.fnlRow AND instance.fnlRow <= layoutData.rowChans.count THEN {
put instance on specified row
IO.Put[celStream, IO.rope[" initially fixed "], ScaleOut[offsetsOnRow[instance.fnlRow], handle]];
offsetsOnRow[instance.fnlRow] ← offsetsOnRow[instance.fnlRow] + SCInstUtil.InstWidth[instance];
IO.Put[celStream, IO.rope[" from left of block "], IO.int[instance.fnlRow]];
IO.Put[celStream, IO.rope["\l"]]};
IO.Put[celStream, IO.rope[" left "], ScaleOut[instance.object.orgin.p - middleX, handle]];
IO.Put[celStream, IO.rope[" right "], ScaleOut[instance.object.orgin.p + instance.object.size.p - middleX, handle]];
IO.Put[celStream, IO.rope[" bottom "], ScaleOut[instance.object.orgin.q - middleY, handle]];
IO.Put[celStream, IO.rope[" top "], ScaleOut[instance.object.orgin.q + instance.object.size.q - middleY, handle], IO.rope["\l"]]};
AddPin: PROC [celStream: IO.STREAM, instance: SCPrivate.Instance, pin: SCPrivate.ObjectPin, net: SCPrivate.Net, first: BOOLEAN, handle: SC.Handle] ~ {
add a pin to the .cel file
middleX: INT ← instance.object.orgin.p + instance.object.size.p/2;
middleY: INT ← instance.object.orgin.q + instance.object.size.q/2;
pinPos: CD.Position ← SELECT pin.pinPos.side FROM
bottom => [pin.pinPos.location - middleX, instance.object.orgin.q - middleY],
top => [pin.pinPos.location - middleX, instance.object.orgin.q + instance.object.size.q - middleY],
left => [instance.object.orgin.p - middleX, pin.pinPos.location - middleY],
right => [instance.object.orgin.p + instance.object.size.p - middleX, pin.pinPos.location - middleY],
ENDCASE => SC.Error[callingError, "pin on invalid side"];
IF first THEN {
IO.Put[celStream, IO.rope[" pin name "], IO.rope[pin.name]];
IO.Put[celStream, IO.rope[" signal "], IO.rope[net.name]]}
ELSE
IO.Put[celStream, IO.rope[" equiv name "], IO.rope[pin.name]];
IO.Put[celStream, IO.rope[" "], ScaleOut[pinPos.x, handle]];
IO.Put[celStream, IO.rope[" "], ScaleOut[pinPos.y, handle]];
IO.Put[celStream, IO.rope["\l"]]};
record to save pad information; TimberWolf requires the pads to be sorted
Pad: TYPE = REF PadRec;
PadRec: TYPE = RECORD [
instance: SCPrivate.Instance,
pathName: Rope.ROPE];
AddPad: PROC [padTable: RedBlackTree.Table, instance: SCPrivate.Instance] ~ {
insert a pad into an ordered table
pad: Pad ← NEW[PadRec ← [instance: instance, pathName: instance.name]];
RedBlackTree.Insert[padTable, pad, instance]};
CopyPadToCel: PROC [celStream: IO.STREAM, padTable: RedBlackTree.Table, handle: SC.Handle, instNumber: NAT] ~ {
pads must be at the end of the .cel file; write to .cel from the ordered symbol table
WriteNode: RedBlackTree.EachNode ~ {
PROC [data: UserData] RETURNS [stop: BOOLFALSE];
pad: Pad ← NARROW[data];
sideRope: Rope.ROPESELECT pad.instance.curSide FROM
bottom => "B", right => "R", top => "T", left => "L", ENDCASE => "NONE";
orient: INTSELECT pad.instance.curSide FROM
bottom => 0, right => 6, top => 3, left => 7, ENDCASE => 0;
IO.Put[celStream, IO.rope["pad "], IO.int[instNumber]]; instNumber ← instNumber+1;
IO.Put[celStream, IO.rope[" "], IO.rope[pad.pathName]];
IO.Put[celStream, IO.rope[" orient "], IO.int[orient], IO.rope["\l"]];
IO.Put[celStream, IO.rope[" padside "], IO.rope[sideRope], IO.rope["\l"]];
IO.Put[celStream, IO.rope[" left "], ScaleOut[-pad.instance.object.size.p, handle]];
IO.Put[celStream, IO.rope[" right "], ScaleOut[pad.instance.object.size.p, handle]];
IO.Put[celStream, IO.rope[" bottom "], ScaleOut[-pad.instance.object.size.q, handle]];
IO.Put[celStream, IO.rope[" top "], ScaleOut[pad.instance.object.size.q, handle], IO.rope["\l"]];
IO.Put[celStream, IO.rope[" pin name io signal "], IO.rope[pad.pathName]];
IO.Put[celStream, IO.rope[" "], IO.int[0]];
IO.Put[celStream, IO.rope[" "], ScaleOut[pad.instance.object.size.q, handle]];
IO.Put[celStream, IO.rope["\l"]]};
RedBlackTree.EnumerateIncreasing[padTable, WriteNode]};
GetKey: RedBlackTree.GetKey ~ {
Callback proc: Given the user data in a node, return the key
PROC [data: UserData] RETURNS [Key];
pad: Pad ← NARROW[data];
RETURN[pad.instance]};
Compare: RedBlackTree.Compare ~ {
Callback proc type: Given a key and the user data in a node, return the comparison of the keys
PROC [k: Key, data: UserData] RETURNS [Basics.Comparison];
instance: SCPrivate.Instance ← NARROW[k];
pad: Pad ← NARROW[data];
instanceSide: Rope.ROPESELECT instance.curSide FROM
bottom => "B", right => "R", top => "T", left => "L", ENDCASE => "NONE";
padSide: Rope.ROPESELECT pad.instance.curSide FROM
bottom => "B", right => "R", top => "T", left => "L", ENDCASE => "NONE";
result: Basics.Comparison ← Rope.Compare[padSide, instanceSide];
IF result = Basics.Comparison[equal] THEN result ← Basics.CompareInt[instance.fnlPos, pad.instance.fnlPos];
IF result = Basics.Comparison[equal] THEN result ← Rope.Compare[instance.name, pad.instance.name];
RETURN[result]};
ReadTWPlace: PUBLIC PROC [handle: SC.Handle]~ {
read timberWolf placement
EachInstance: SCInstUtil.EachInstanceProc ~ {
PROC [instance: SCPrivate.Instance] RETURNS [quit: BOOLFALSE];
the Timberwolf documentation states positions will not be 0 but Version 4.2 returns valid placements with position = 0; hence the check was removed BTP August 1, 1988
IF instance.whichClass = logic THEN { -- check for TimberWolf .cel file entry
IF instance.fnlRow = 0 -- OR instance.fnlPos = 0 -- THEN SC.Signal[programmingError, Rope.Cat["Missing instance in Timberwolf .cell file: ", instance.name]]}
ELSE IF instance.whichClass = io THEN {
IF instance.fnlSide = none -- OR instance.fnlPos = 0 -- THEN SC.Signal[programmingError, Rope.Cat["Missing public in Timberwolf .cell file: ", instance.name]]}};
server: UnixRemoteFile.UnixServerHandle ← UnixRemoteFile.CreateHandle[fileHost];
placeStream: IO.STREAM ← UnixRemoteFile.OpenReadStream[server, [Rope.Cat[remoteServerDir, handle.name, ".pl1"]]];
[] ← IO.SkipWhitespace[placeStream];
WHILE ~IO.EndOf[placeStream] DO
name: Rope.ROPEIO.GetTokenRope[placeStream, IO.IDProc].token;
left: INT ← ScaleIn[placeStream, handle];
lower: INT ← ScaleIn[placeStream, handle];
right: INT ← ScaleIn[placeStream, handle];
upper: INT ← ScaleIn[placeStream, handle];
orient: INTIO.GetInt[placeStream];
row: INTIO.GetInt[placeStream];
dontCare: INTIO.SkipWhitespace[placeStream];
instance: SCPrivate.Instance ← FindInstance[handle, name];
IF instance # NIL THEN {
SELECT instance.whichClass FROM
logic =>
{instance.fnlRow ← row; instance.fnlPos ← left};
io =>
HACK !!! TimberWolf does not provide side information. Have to use orientation
BUG: TimberWolf sometimes provides identical locations for pads on same side!!
{SELECT orient FROM
0 => {instance.fnlPos ← left; instance.fnlSide ← bottom};
6 => {instance.fnlPos ← lower; instance.fnlSide ← right};
3 => {instance.fnlPos ← left; instance.fnlSide ← top};
7 => {instance.fnlPos ← lower; instance.fnlSide ← left};
ENDCASE => {instance.fnlPos ← 0; instance.fnlSide ← none}};
ENDCASE}
ELSE SC.Error[programmingError, Rope.Cat["Timberwolf .cell file instance is not in extraction: ", instance.name]]; -- the TW file & the extraction disagree...
ENDLOOP;
IO.Close[placeStream];
UnixRemoteFile.DestroyHandle[server];
check to see if everything is placed
[] ← SCInstUtil.EnumerateAllInstances[handle, EachInstance]};
ScaleOut: PROC [int: INT, h: SC.Handle] RETURNS [IO.Value] ~ {
lambda: INT ← h.rules.rowParms.technology.lambda;
IF ABS[int] MOD lambda # 0 THEN SC.Signal[explanation: "Scaling inaccuracies in TW files"];
RETURN[IO.int[int/lambda]];
};
ScaleIn: PROC [s: IO.STREAM, h: SC.Handle] RETURNS [int: INT] ~ {
lambda: INT ← h.rules.rowParms.technology.lambda;
RETURN[IO.GetInt[s]*lambda];
};
TWOps
MyLower: Rope.TranslatorType ~ {RETURN[Ascii.Lower[old]]};
GuessUnixName: PROC RETURNS [unixName: Rope.ROPE] ~ {
get rid of the ".pa" & truncate to 8 char, put in lower case.
unixName ← UserCredentials.Get[].name;
unixName ← Rope.Substr[unixName, 0, MIN[8, Rope.Index[unixName, 0, "."]]];
unixName ← Rope.Translate[base: unixName, translator: MyLower];
};
TWIt: PUBLIC PROC [id: Rope.ROPE] RETURNS [msg: Rope.ROPE] ~ {
submits the placement to TimberWolfSC on the unix server.
msgStream: IO.STREAM ← TerminalIO.TOS[];
msg ← Rsh.RSH[
remoteMachine: cpuHost,
command: Rope.Cat[twCmd, id],
in: IO.noInputStream, out: msgStream
];
};
translate: PUBLIC ARRAY SC.Side OF ARRAY SCPrivate.OrientationOrNone OF SC.Side;
translate[bottom] ← [bottom, bottom, left, top, right, bottom, top, left, right];
translate[left] ← [left, left, top, right, bottom, right, left, bottom, top];
translate[top] ← [top, top, right, bottom, left, top, bottom, right, left];
translate[right] ← [right, right, bottom, left, top, left, right, top, bottom];
END.