SoftHdwPlacement.mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Barth, November 26, 1988 4:52:58 pm PST
DIRECTORY Basics, Combinatorial, Core, CoreFlat, CoreOps, FIFOQueue, Imager, ImagerBackdoor, IO, RefTab, Rope, SymTab, TerminalIO, ViewerClasses, ViewerOps;
SoftHdwPlacement: CEDAR PROGRAM
IMPORTS Basics, Combinatorial, CoreFlat, CoreOps, FIFOQueue, Imager, ImagerBackdoor, IO, RefTab, SymTab, TerminalIO, ViewerOps
EXPORTS
= BEGIN
Placement
PlaceArrayStats: TYPE = REF ArrayStatsRec;
PlaceArrayStatsRec: TYPE = RECORD [
combinatorials: NAT ← 0,
sequentials: NAT ← 0,
minors: NAT ← 0,
horizontals: NAT ← 0,
verticals: NAT ← 0,
netInputs: ARRAY InputCount OF NATALL[0]];
InputCount: TYPE = [0..20];
PlaceArray: TYPE = REF PlaceArrayRec;
PlaceArrayRec: TYPE = RECORD [
root: Core.CellType ← NIL,
grainsPerMinorSide: NAT ← 4,
minorsPerChipSide: NAT ← 16,
chipsPerBoardSide: NAT ← 8,
currentMinor: DABasics.Position ← [0, 0],
currentChip: DABasics.Position ← [0, 0],
minors: MinorArrays ← NIL,
lastMinor: MinorArrays ← NIL,
outputs: RefTab.Ref ← NIL];
MinorArrays: TYPE = LIST OF MinorArray;
MinorArray: TYPE = REF MinorArrayRec;
MinorArrayRec: TYPE = RECORD [
position: GridPosition,
combinatorials: ARRAY Orientation OF CombinatorialElements ← ALL[NIL],
sequentials: SequentialElements ← NIL,
firstFreeSequentialElement: NAT ← 0];
GridPosition: TYPE = RECORD [
chip: DABasics.Position,
minor: DABasics.Position];
CombinatorialElements: TYPE = REF CombinatorialElementsRec;
CombinatorialElementsRec: TYPE = RECORD [
elements: SEQUENCE size: CARDINAL OF CombinatorialElement]; -- MinorIndex
CombinatorialElement: TYPE = REF CombinatorialElementRec;
CombinatorialElementRec: TYPE = RECORD [
c: CoreFlat.FlatCellType,
o: Label ← NIL,
i: Label ← NIL,
ip: InputPositions ← NIL]; -- inputs required for o
InputPositions: TYPE = LIST OF MinorIndex;
SequentialElements: TYPE = REF SequentialElementsRec;
SequentialElementsRec: TYPE = RECORD [elements: SEQUENCE size: CARDINAL OF SequentialElement]; -- MinorIndex
SequentialElement: TYPE = REF SequentialElementRec;
SequentialElementRec: TYPE = RECORD [
c: CoreFlat.FlatCellType,
i: Label ← NIL,
o: Label ← NIL];
Orientation: TYPE = {vertical, horizontal};
GrainIndex: TYPE = NAT;
MinorIndex: TYPE = NAT;
ChipIndex: TYPE = NAT;
RopeList: TYPE = LIST OF Rope.ROPE;
Labels: TYPE = CoreFlat.FlatWires;
Label: TYPE = CoreFlat.FlatWire;
SoftHdwCoreA, SoftHdwCoreF, and SoftHdwCoreK are not handled by the following classification.
primitiveTypes: SymTab.Ref ← SymTab.Create[];
PrimitiveType: TYPE = {ignore, equate, simple, xor2, a22o2i, a21o2i, ff, ffEn, tstDriver};
LoadPrimitiveTypes: PROC = {
InsertList: PROC [ropes: RopeList, type: PrimitiveType] = {
FOR rl: RopeList ← ropes, rl.rest UNTIL rl=NIL DO
Insert[rl.first, type];
ENDLOOP;
};
Insert: PROC [rope: Rope.ROPE, type: PrimitiveType] = {
[] ← SymTab.Insert[primitiveTypes, rope, NEW[PrimitiveType ← type]];
};
InsertList[LIST["pd", "pdw", "puw"], ignore];
InsertList[LIST["inv", "invBuffer", "rec2V"], equate];
InsertList[LIST["and2", "and3", "and4", "nand2", "nand3", "nand4", "or2", "or3", "or4", "nor2", "nor3", "nor4"], simple];
InsertList[LIST["xor2", "xnor2"], xor2];
InsertList[LIST["a22o2i", "o22a2i"], a22o2i];
InsertList[LIST["a21o2i", "o21a2i"], a21o2i];
Insert["ff", ff];
Insert["ffEn", ffEn];
Insert["tstDriver", tstDriver];
};
PackArrayStats: PROC [array: PlaceArray] RETURNS [stats: ArrayStats] = {
CountInput: PROC [flatWire: CoreFlat.FlatWire] = {
IF flatWire#NIL THEN {
count: REF NATNARROW[RefTab.Fetch[flatInputCounts, flatWire].val];
IF count=NIL THEN {
count ← NEW[NAT ← 0];
IF NOT RefTab.Insert[flatInputCounts, flatWire, count] THEN ERROR;
};
count^ ← count^ + 1;
};
};
BinInput: RefTab.EachPairAction = {
count: REF NATNARROW[val];
index: InputCount ← IF count^>LAST[InputCount] THEN LAST[InputCount] ELSE count^;
stats.netInputs[index] ← stats.netInputs[index] + 1;
};
flatInputCounts: RefTab.Ref ← RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
stats ← NEW[ArrayStatsRec];
FOR ml: MinorArrays ← array.minors, ml.rest UNTIL ml=NIL DO
m: MinorArray ← ml.first;
stats.minors ← stats.minors + 1;
FOR aIndex: AIndex IN [0..array.a) DO
IF m.combinatorials[vertical].elements[aIndex].o#NIL THEN {
stats.combinatorials ← stats.combinatorials + 1;
stats.verticals ← stats.verticals + 1;
};
CountInput[m.combinatorials[vertical].elements[aIndex].i];
IF m.sequentials[aIndex]#NIL THEN CountInput[m.sequentials[aIndex].i];
ENDLOOP;
FOR bIndex: BIndex IN [0..array.b) DO
IF m.combinatorials[horizontal].elements[bIndex].o#NIL THEN {
stats.combinatorials ← stats.combinatorials + 1;
stats.horizontals ← stats.horizontals + 1;
};
CountInput[m.combinatorials[horizontal].elements[bIndex].i];
ENDLOOP;
stats.sequentials ← stats.sequentials + m.firstFreeSequentialElement;
ENDLOOP;
[] ← RefTab.Pairs[flatInputCounts, BinInput];
};
TriData: TYPE = REF TriDataRec;
TriDataRec: TYPE = RECORD [
count: NAT ← 0,
lastInput: CoreFlat.FlatWire ← NIL,
next: CoreFlat.FlatWire ← NIL];
PackArray: PROC [root: Core.CellType, minorSize, majorSize: NAT ← 4] RETURNS [array: PlaceArray] = {
Equate: CoreFlat.BoundFlatCellProc = {
EquateWire: PROC [from, to: Rope.ROPE] = {
fromWire: Core.Wire ← CoreOps.FindWire[cell.public, from];
flatFrom: CoreFlat.FlatWire ← CanonizeWire[bindings, flatCell, fromWire];
toWire: Core.Wire ← CoreOps.FindWire[cell.public, to];
flatTo: CoreFlat.FlatWire ← CanonizeWire[bindings, flatCell, toWire];
IF fromWire=NIL OR toWire=NIL THEN ERROR;
[] ← RefTab.Insert[equivalence, flatFrom, flatTo];
};
name: Rope.ROPE ← CoreOps.GetCellTypeName[cell];
primitiveType: REF PrimitiveType ← NARROW[SymTab.Fetch[primitiveTypes, name].val];
IF primitiveType=NIL THEN CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, Equate]
ELSE SELECT primitiveType^ FROM
ff => EquateWire["NQ", "Q"];
equate => EquateWire["X", "I"];
tstDriver => {
x: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "X"];
i: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "I"];
triData: TriData ← NARROW[RefTab.Fetch[triDataTable, x].val];
IF triData=NIL THEN {
triData ← NEW[TriDataRec];
IF NOT RefTab.Store[triDataTable, x, triData] THEN ERROR;
};
triData.lastInput ← i;
triData.count ← triData.count + 1;
};
ENDCASE;
};
EquateTristate: RefTab.EachPairAction = {
x: CoreFlat.FlatWire ← NARROW[key];
triData: TriData ← NARROW[val];
IF triData.count<2 THEN [] ← RefTab.Insert[equivalence, x, triData.lastInput]
ELSE triData.next ← x;
};
Flatten: CoreFlat.BoundFlatCellProc = {
name: Rope.ROPE ← CoreOps.GetCellTypeName[cell];
primitiveType: REF PrimitiveType ← NARROW[SymTab.Fetch[primitiveTypes, name].val];
IF primitiveType=NIL THEN CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, Flatten]
ELSE SELECT primitiveType^ FROM
ignore, equate => NULL;
simple => {
flatOutput: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "X"];
flatInputs: CoreFlat.FlatWires ← NIL;
Combinatorial.MakeCombinatorial[cell];
FOR wl: Core.Wires ← Combinatorial.GetTypedWires[cell, input], wl.rest UNTIL wl=NIL DO
flatInput: CoreFlat.FlatWire ← CanonizeWire[bindings, flatCell, wl.first];
flatInput ← GetEquivalent[flatInput];
flatInputs ← CONS[flatInput, flatInputs];
ENDLOOP;
PackCombinatorialElement[array, flatCell, flatOutput, flatInputs];
};
xor2 => {
a: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "I-A"];
b: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "I-B"];
x: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "X"];
i1: CoreFlat.FlatWire ← CreateWire[flatCell];
i2: CoreFlat.FlatWire ← CreateWire[flatCell];
PackCombinatorialElement[array, flatCell, i1, LIST[a, b]];
PackCombinatorialElement[array, flatCell, i2, LIST[a, b]];
PackCombinatorialElement[array, flatCell, x, LIST[i1, i2]];
};
a22o2i => {
a: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "A"];
b: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "B"];
c: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "C"];
d: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "D"];
x: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "X"];
i1: CoreFlat.FlatWire ← CreateWire[flatCell];
i2: CoreFlat.FlatWire ← CreateWire[flatCell];
PackCombinatorialElement[array, flatCell, i1, LIST[a, b]];
PackCombinatorialElement[array, flatCell, i2, LIST[c, d]];
PackCombinatorialElement[array, flatCell, x, LIST[i1, i2]];
};
a21o2i => {
a: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "A"];
b: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "B"];
c: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "C"];
x: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "X"];
i: CoreFlat.FlatWire ← CreateWire[flatCell];
PackCombinatorialElement[array, flatCell, i, LIST[a, b]];
PackCombinatorialElement[array, flatCell, x, LIST[i, c]];
};
ff => {
d: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "D"];
q: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "Q"];
PackSequentialElement[array, flatCell, q, d];
};
ffEn => {
en: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "en"];
d: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "D"];
q: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "Q"];
i1: CoreFlat.FlatWire ← CreateWire[flatCell];
i2: CoreFlat.FlatWire ← CreateWire[flatCell];
i3: CoreFlat.FlatWire ← CreateWire[flatCell];
PackCombinatorialElement[array, flatCell, i1, LIST[en, d]];
PackCombinatorialElement[array, flatCell, i2, LIST[en, q]];
PackCombinatorialElement[array, flatCell, i3, LIST[i1, i2]];
PackSequentialElement[array, flatCell, q, i3];
};
tstDriver => {
x: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "X"];
triData: TriData ← NARROW[RefTab.Fetch[triDataTable, x].val];
IF triData.count>1 THEN {
i: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "I"];
en: CoreFlat.FlatWire ← GetNamedWire[bindings, cell.public, flatCell, "EN"];
i1: CoreFlat.FlatWire ← CreateWire[flatCell];
i2: CoreFlat.FlatWire ← CreateWire[flatCell];
previous: CoreFlat.FlatWire ← IF triData.count=2 THEN GetEquivalent[triData.lastInput] ELSE CreateWire[flatCell];
PackCombinatorialElement[array, flatCell, i1, LIST[en, i]];
PackCombinatorialElement[array, flatCell, i2, LIST[en, previous]];
PackCombinatorialElement[array, flatCell, triData.next, LIST[i1, i2]];
triData.count ← triData.count - 1;
triData.next ← previous;
};
};
ENDCASE => ERROR;
};
CreateWire: PROC [flatCell: CoreFlat.FlatCellTypeRec] RETURNS [flatWire: CoreFlat.FlatWire] = {
flatWire ← NEW[CoreFlat.FlatWireRec];
flatWire.flatCell ← flatCell;
flatWire.wire ← CoreOps.CreateWire[];
};
GetNamedWire: PROC [bindings: CoreFlat.Bindings, public: Core.Wire, flatCell: CoreFlat.FlatCellTypeRec, name: Rope.ROPE] RETURNS [flatWire: CoreFlat.FlatWire] = {
wire: Core.Wire ← CoreOps.FindWire[public, name];
flatWire ← CanonizeWire[bindings, flatCell, wire];
flatWire ← GetEquivalent[flatWire];
};
GetEquivalent: PROC [from: CoreFlat.FlatWire] RETURNS [to: CoreFlat.FlatWire] = {
WHILE from#NIL DO
to ← from;
from ← NARROW[RefTab.Fetch[equivalence, from].val]
ENDLOOP;
};
CanonizeWire: PROC [bindings: CoreFlat.Bindings, flatCell: CoreFlat.FlatCellTypeRec, wire: Core.Wire] RETURNS [flatWire: CoreFlat.FlatWire] = {
flatWire ← NARROW[RefTab.Fetch[bindings, wire].val];
IF flatWire=NIL THEN {
flatWire ← NEW[CoreFlat.FlatWireRec];
flatWire.flatCell ← flatCell;
flatWire.wire ← wire;
};
};
equivalence: RefTab.Ref ← RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
triDataTable: RefTab.Ref ← RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
array ← NEW[PlaceArrayRec];
array.minorSize ← minorSize;
array.majorSize ← majorSize;
array.outputs ← RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
array.root ← root;
Equate[root];
[] ← RefTab.Pairs[triDataTable, EquateTristate];
Flatten[root];
array.root ← root;
};
PackCombinatorialElement: PROC [array: PlaceArray, c: CoreFlat.FlatCellTypeRec, o: Label, li: Labels] = {
minor: MinorArray;
t: Orientation;
minorIndex: ABIndex;
lip: InputPositions ← NIL;
IF CheckOutput[array, o] THEN RETURN;
FOR lm: MinorArrays ← array.minors, lm.rest UNTIL lm=NIL DO
minor ← lm.first;
FOR t IN Orientation DO
FOR minorIndex IN [0..IF t=vertical THEN array.a ELSE array.b) DO
IF minor.combinatorials[t].elements[minorIndex].o=NIL THEN {
KillInputAssignments: PROC = {
FOR kl: InputPositions ← klip, kl.rest UNTIL kl=NIL DO
inputScan[kl.first].i ← NIL;
ENDLOOP;
lip ← NIL;
};
inputScan: CombinatorialElements ← minor.combinatorials[IF t=vertical THEN horizontal ELSE vertical];
klip: InputPositions ← NIL;
FOR ll: Labels ← li, ll.rest UNTIL ll=NIL DO
FOR inputIndex: MinorIndex IN [0..IF t=vertical THEN array.b ELSE array.a) DO
IF inputScan[inputIndex].i=NIL OR CoreFlat.FlatWireEqual[inputScan[inputIndex].i, ll.first] THEN {
lip ← CONS[inputIndex, lip];
IF inputScan[inputIndex].i=NIL THEN klip ← CONS[inputIndex, klip];
inputScan[inputIndex].i ← ll.first;
EXIT;
};
REPEAT FINISHED => {
KillInputAssignments[];
EXIT;
};
ENDLOOP;
REPEAT FINISHED => {
FOR otherIndex: MinorIndex IN [0..IF t=vertical THEN array.b ELSE array.a) DO
IF inputScan[otherIndex].o#NIL THEN {
thisInOther: BOOL ← IndexInList[minorIndex, inputScan[otherIndex].ip];
otherInThis: BOOL ← IndexInList[otherIndex, lip];
IF (thisInOther AND NOT otherInThis) OR (NOT thisInOther AND otherInThis) THEN {
KillInputAssignments[];
EXIT;
}
};
REPEAT FINISHED => GOTO foundOne;
ENDLOOP;
};
ENDLOOP;
};
ENDLOOP;
ENDLOOP;
REPEAT
foundOne => NULL;
FINISHED => {
firstFreeInput: MinorIndex ← 0;
CreateMinorArray[array];
minor ← array.lastMinor.first;
t ← horizontal;
minorIndex ← 0;
FOR ll: Labels ← li, ll.rest UNTIL ll=NIL DO
lip ← CONS[firstFreeInput, lip];
firstFreeInput ← firstFreeInput + 1;
ENDLOOP;
IF firstFreeInput > array.a THEN ERROR;
};
ENDLOOP;
minor.combinatorials[t].elements[minorIndex].c ← NEW[CoreFlat.FlatCellTypeRec ← c];
minor.combinatorials[t].elements[minorIndex].o ← o;
minor.combinatorials[t].elements[minorIndex].ip ← lip;
};
IndexInList: PROC [index: ABIndex, list: InputPositions] RETURNS [BOOL] = {
FOR ipl: InputPositions ← list, ipl.rest UNTIL ipl=NIL DO
IF index=list.first THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
};
PackSequentialElement: PROC [array: PlaceArray, c: CoreFlat.FlatCellTypeRec, o: Label, i: Label] = {
IF CheckOutput[array, o] THEN RETURN;
FOR lm: MinorArrays ← array.minors, lm.rest UNTIL lm=NIL DO
minor: MinorArray ← lm.first;
IF minor.firstFreeSequentialElement<array.a THEN {
minor.sequentials[minor.firstFreeSequentialElement] ← NEW[SequentialElementRec ← [c: NEW[CoreFlat.FlatCellTypeRec ← c], i: i, o: o]];
minor.firstFreeSequentialElement ← minor.firstFreeSequentialElement + 1;
EXIT;
};
REPEAT FINISHED => {
minor: MinorArray;
CreateMinorArray[array];
minor ← array.lastMinor.first;
minor.sequentials[0] ← NEW[SequentialElementRec ← [c: NEW[CoreFlat.FlatCellTypeRec ← c], i: i, o: o]];
minor.firstFreeSequentialElement ← 1;
};
ENDLOOP;
};
CreateMinorArray: PROC [array: PlaceArray] = {
m: MinorArray ← NEW[MinorArrayRec];
m.position ← [array.c, array.d];
m.combinatorials[vertical] ← NEW[CombinatorialElementsRec[array.a]];
FOR aIndex: AIndex IN [0..array.a) DO
m.combinatorials[vertical].elements[aIndex] ← NEW[CombinatorialElementRec];
ENDLOOP;
m.combinatorials[horizontal] ← NEW[CombinatorialElementsRec[array.b]];
FOR bIndex: BIndex IN [0..array.b) DO
m.combinatorials[horizontal].elements[bIndex] ← NEW[CombinatorialElementRec];
ENDLOOP;
m.sequentials ← NEW[SequentialElementsRec[array.a]];
FOR ei: AIndex IN [0..array.a) DO
m.sequentials[ei] ← NIL;
ENDLOOP;
IF array.lastMinor=NIL THEN array.lastMinor ← array.minors ← LIST[m]
ELSE {
array.lastMinor.rest ← LIST[m];
array.lastMinor ← array.lastMinor.rest;
};
update array.c and array.d in spiral pattern
IF array.d>=0 AND array.c=array.d THEN {
array.d ← array.d + 1;
array.enumerationState ← left;
}
ELSE {
IF ABS[array.c]=ABS[array.d] THEN array.enumerationState ← SUCC[array.enumerationState];
SELECT array.enumerationState FROM
left => array.c ← array.c - 1;
down => array.d ← array.d - 1;
right => array.c ← array.c + 1;
up => array.d ← array.d + 1;
ENDCASE;
};
};
CheckOutput: PROC [array: PlaceArray, o: Label] RETURNS [found: BOOL] = {
found ← RefTab.Fetch[array.outputs, o].found;
IF found THEN TerminalIO.PutF["\nMultiply driven output: %g", IO.rope[CoreFlat.WirePathRope[array.root, o^]]]
ELSE IF NOT RefTab.Insert[array.outputs, o, $Driven] THEN ERROR;
};
Routing
Surface: TYPE = REF SurfaceRec;
SurfaceRec: TYPE = RECORD [
array: PlaceArray,
size: MajorGridPosition ← [0, 0],
channelSizes: ARRAY Orientation OF ChannelSizes,
flatWires: RefTab.Ref, -- maps CoreFlat.FlatWire to NetEnds
nodes: ?];
ChannelSizes: TYPE = REF ChannelSizesRec;
ChannelSizesRec: TYPE = RECORD [
elements: SEQUENCE size: CARDINAL OF NAT]; -- surface.size.? + 1
NetEnds: TYPE = REF NetEndsRec;
NetEndsRec: TYPE = RECORD [
output: NodePosition,
inputs: NodePositions ← NIL];
Nodes: TYPE = LIST OF Node;
Node: TYPE = REF NodeRec;
NodeRec: TYPE = RECORD [
flatCell: CoreFlat.FlatCellType ← NIL,
flatWire: CoreFlat.FlatWire ← NIL,
back: NodePosition ← NIL,
neighbors: SEQUENCE size: NodeIndex OF Node];
NodePositions: TYPE = LIST OF NodePosition;
NodePosition: TYPE = RECORD [
type: NodeType,
majorPosition: MajorGridPosition,
minorPosition: ABIndex ← 0];
NodeType: TYPE = {horizontalShort, verticalShort, horizontalLong, verticalLong, horizontalOutput, verticalOutput, sequentialIn, sequentialOut};
majorPosition is dependent on type. If type is horizontalLong then majorPosition.x is invalid. If type is verticalLong then majorPosition.y is invalid.
NodeIndex: TYPE = CARDINAL;
ChannelSizesFromList: PROC [sl: LIST OF NAT] RETURNS [cs: ChannelSizes] = {
index: CARDINAL ← 0;
FOR l: LIST OF NAT ← sl, l.rest UNTIL l=NIL DO
index ← index + 1;
ENDLOOP;
cs ← NEW[ChannelSizesRec[index]];
index ← 0;
FOR l: LIST OF NAT ← sl, l.rest UNTIL l=NIL DO
cs[index] ← l.first;
index ← index + 1;
ENDLOOP;
};
CreateChanneledSurface: PROC [array: PlaceArray, channelSize: NAT ← 1] RETURNS [surface: Surface] = {
minx, miny: INTLAST[INT];
maxx, maxy: INTFIRST[INT];
csv, csh: ChannelSizes;
FOR lm: MinorArrays ← array.minors, lm.rest UNTIL lm=NIL DO
m: MinorArray ← lm.first;
minx ← MIN[minx, m.position.x];
miny ← MIN[miny, m.position.y];
maxx ← MAX[maxx, m.position.x];
maxy ← MAX[maxy, m.position.y];
ENDLOOP;
csv ← NEW[ChannelSizesRec[maxx - minx + 2]];
csh ← NEW[ChannelSizesRec[maxy - miny + 2]];
FOR index: NAT IN [0..csv.size) DO
csv[index] ← channelSize;
ENDLOOP;
FOR index: NAT IN [0..csh.size) DO
csh[index] ← channelSize;
ENDLOOP;
surface ← CreateSurface[array, [csv, csh]];
};
CreateSurface: PROC [array: PlaceArray, channelSizes: ARRAY Orientation OF ChannelSizes] RETURNS [surface: Surface] = {
LookupNodePosition: PROC [position: NodePositionRec] RETURNS [node: Node] = {
nodePosition^ ← position;
node ← NARROW[RefTab.Fetch[surface.nodes, nodePosition].val];
IF node=NIL THEN ERROR;
};
FetchNetEnds: PROC [flatWire: CoreFlat.FlatWire] RETURNS [ne: NetEnds] = {
ne ← NARROW[RefTab.Fetch[surface.flatWires, flatWire].val];
IF ne=NIL THEN {
ne ← NEW[NetEndsRec];
IF NOT RefTab.Insert[surface.flatWires, flatWire, ne] THEN ERROR;
};
};
MajorToSurface: PROC [array: MajorGridPosition] RETURNS [surface: MajorGridPosition] = {
adjustedx: NAT ← array.x - minx;
adjustedy: NAT ← array.y - miny;
surface.x ← adjustedx;
surface.y ← adjustedy;
FOR i: NAT IN [0..adjustedx] DO
surface.x ← surface.x + channelSizes[vertical][i];
ENDLOOP;
FOR i: NAT IN [0..adjustedy] DO
surface.y ← surface.y + channelSizes[horizontal][i];
ENDLOOP;
};
minx, miny: INTLAST[INT];
maxx, maxy: INTFIRST[INT];
nodePosition: NodePosition ← NEW[NodePositionRec];
surface ← NEW[SurfaceRec];
surface.array ← array;
surface.channelSizes ← channelSizes;
surface.flatWires ← RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
surface.nodes ← RefTab.Create[hash: NodePositionHash, equal: NodePositionEqual];
surface.size.x ← ComputeSize[channelSizes[vertical]];
surface.size.y ← ComputeSize[channelSizes[horizontal]];
FOR lm: MinorArrays ← array.minors, lm.rest UNTIL lm=NIL DO
m: MinorArray ← lm.first;
minx ← MIN[minx, m.position.x];
miny ← MIN[miny, m.position.y];
maxx ← MAX[maxx, m.position.x];
maxy ← MAX[maxy, m.position.y];
ENDLOOP;
IF (maxx - minx + 2) # channelSizes[vertical].size THEN ERROR;
IF (maxy - miny + 2) # channelSizes[horizontal].size THEN ERROR;
AllocateNodesAndArcs[surface];
FOR lm: MinorArrays ← array.minors, lm.rest UNTIL lm=NIL DO
minor: MinorArray ← lm.first;
position: MajorGridPosition ← MajorToSurface[minor.position];
FOR ei: AIndex IN [0..minor.sequentials.size) DO
se: SequentialElement ← minor.sequentials[ei];
IF se#NIL THEN {
in: Node ← LookupNodePosition[[sequentialIn, position, ei]];
out: Node ← LookupNodePosition[[sequentialOut, position, ei]];
inNetEnds: NetEnds ← FetchNetEnds[se.i];
outNetEnds: NetEnds ← FetchNetEnds[se.o];
inNetEnds.inputs ← CONS[in, inNetEnds.inputs];
in.flatCell ← se.c;
in.flatWire ← se.i;
IF outNetEnds.output#NIL THEN ERROR;
outNetEnds.output ← out;
out.flatCell ← se.c;
out.flatWire ← se.o;
};
ENDLOOP;
FOR t: Orientation IN Orientation DO
elements: CombinatorialElements ← minor.combinatorials[t];
FOR ei: ABIndex IN [0..elements.size) DO
IF elements[ei].i#NIL THEN {
node: Node ← LookupNodePosition[[IF t=vertical THEN verticalShort ELSE horizontalShort, position, ei]];
ne: NetEnds ← FetchNetEnds[elements[ei].i];
ne.inputs ← CONS[node, ne.inputs];
node.flatWire ← elements[ei].i;
};
IF elements[ei].o#NIL THEN {
node: Node ← LookupNodePosition[[IF t=vertical THEN verticalOutput ELSE horizontalOutput, position, ei]];
ne: NetEnds ← FetchNetEnds[elements[ei].o];
IF ne.output#NIL THEN ERROR;
ne.output ← node;
node.flatCell ← elements[ei].c;
node.flatWire ← elements[ei].o;
};
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
AllocateNodesAndArcs: PROC [surface: Surface] = {
LookupNodePosition: PROC [position: NodePositionRec] RETURNS [node: Node] = {
nodePosition^ ← position;
node ← NARROW[RefTab.Fetch[surface.nodes, nodePosition].val];
IF node=NIL THEN ERROR;
};
nodePosition: NodePosition ← NEW[NodePositionRec];
array: PlaceArray ← surface.array;
FOR x: INT IN [0..surface.size.x) DO
FOR a: AIndex IN [0..array.a) DO
CreateNode[surface, verticalLong, [x, 0], a, 2*surface.size.y];
ENDLOOP;
ENDLOOP;
FOR y: INT IN [0..surface.size.y) DO
FOR b: BIndex IN [0..array.b) DO
CreateNode[surface, horizontalLong, [0, y], b, surface.size.x];
ENDLOOP;
ENDLOOP;
FOR x: INT IN [0..surface.size.x) DO
FOR y: INT IN [0..surface.size.y) DO
FOR a: AIndex IN [0..array.a) DO
shortNeighbors: NATIF y=0 OR y=surface.size.y-1 THEN 1 ELSE 2;
seqNeighbors: NATIF y=0 THEN 1 ELSE 2;
CreateNode[surface, verticalShort, [x, y], a, shortNeighbors+seqNeighbors+1+array.b];
CreateNode[surface, verticalOutput, [x, y], a, shortNeighbors+seqNeighbors+2];
CreateNode[surface, sequentialIn, [x, y], a, 0];
CreateNode[surface, sequentialOut, [x, y], a, (IF y=surface.size.y-1 THEN 1 ELSE 2)+1];
ENDLOOP;
FOR b: BIndex IN [0..array.b) DO
shortNeighbors: NATIF x=0 OR x=surface.size.x-1 THEN 1 ELSE 2;
CreateNode[surface, horizontalShort, [x, y], b, shortNeighbors+1+array.a];
CreateNode[surface, horizontalOutput, [x, y], b, shortNeighbors+2];
ENDLOOP;
ENDLOOP;
ENDLOOP;
FOR x: INT IN [0..surface.size.x) DO
FOR a: AIndex IN [0..array.a) DO
long: Node ← LookupNodePosition[[verticalLong, [x, 0], a]];
FOR y: INT IN [0..surface.size.y) DO
short: Node ← LookupNodePosition[[verticalShort, [x, y], a]];
out: Node ← LookupNodePosition[[verticalOutput, [x, y], a]];
sIn: Node ← LookupNodePosition[[sequentialIn, [x, y], a]];
sOut: Node ← LookupNodePosition[[sequentialOut, [x, y], a]];
CreateArc[surface, short, long];
CreateArc[surface, long, short];
CreateArc[surface, out, short];
CreateArc[surface, out, long];
CreateArc[surface, long, sIn];
CreateArc[surface, short, sIn];
CreateArc[surface, out, sIn];
CreateArc[surface, sOut, long];
CreateArc[surface, sOut, short];
IF y>0 THEN {
neighbor: Node ← LookupNodePosition[[verticalShort, [x, y-1], a]];
CreateArc[surface, neighbor, short];
neighbor ← LookupNodePosition[[verticalOutput, [x, y-1], a]];
CreateArc[surface, neighbor, short];
};
IF y<surface.size.y-1 THEN {
neighbor: Node ← LookupNodePosition[[verticalShort, [x, y+1], a]];
CreateArc[surface, neighbor, short];
CreateArc[surface, neighbor, sIn];
CreateArc[surface, sOut, neighbor];
neighbor ← LookupNodePosition[[verticalOutput, [x, y+1], a]];
CreateArc[surface, neighbor, short];
CreateArc[surface, neighbor, sIn];
};
ENDLOOP;
ENDLOOP;
ENDLOOP;
FOR y: INT IN [0..surface.size.y) DO
FOR b: BIndex IN [0..array.b) DO
long: Node ← LookupNodePosition[[horizontalLong, [0, y], b]];
FOR x: INT IN [0..surface.size.x) DO
short: Node ← LookupNodePosition[[horizontalShort, [x, y], b]];
out: Node ← LookupNodePosition[[horizontalOutput, [x, y], b]];
CreateArc[surface, short, long];
CreateArc[surface, long, short];
CreateArc[surface, out, short];
CreateArc[surface, out, long];
IF x>0 THEN {
neighbor: Node ← LookupNodePosition[[horizontalShort, [x-1, y], b]];
CreateArc[surface, neighbor, short];
neighbor ← LookupNodePosition[[horizontalOutput, [x-1, y], b]];
CreateArc[surface, neighbor, short];
};
IF x<surface.size.x-1 THEN {
neighbor: Node ← LookupNodePosition[[horizontalShort, [x+1, y], b]];
CreateArc[surface, neighbor, short];
neighbor ← LookupNodePosition[[horizontalOutput, [x+1, y], b]];
CreateArc[surface, neighbor, short];
};
ENDLOOP;
ENDLOOP;
ENDLOOP;
FOR x: INT IN [0..surface.size.x) DO
FOR y: INT IN [0..surface.size.y) DO
FOR a: AIndex IN [0..array.a) DO
verticalShort: Node ← LookupNodePosition[[verticalShort, [x, y], a]];
verticalOutput: Node ← LookupNodePosition[[verticalOutput, [x, y], a]];
FOR b: BIndex IN [0..array.b) DO
horizontalShort: Node ← LookupNodePosition[[horizontalShort, [x, y], b]];
horizontalOutput: Node ← LookupNodePosition[[horizontalOutput, [x, y], b]];
CreateArc[surface, verticalShort, horizontalOutput];
CreateArc[surface, horizontalShort, verticalOutput];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
CreateNode: PROC [surface: Surface, type: NodeType, majorPosition: MajorGridPosition, minorPosition: ABIndex, arcCount: NAT] = {
node: Node ← NEW[NodeRec[arcCount]];
node.position ← NEW[NodePositionRec ← [type, majorPosition, minorPosition]];
FOR arcIndex: NAT IN [0..arcCount) DO
node[arcIndex] ← NIL;
ENDLOOP;
IF NOT RefTab.Insert[surface.nodes, node.position, node] THEN ERROR;
};
CreateArc: PROC [surface: Surface, source, destination: Node] = {
FOR nodeIndex: NAT IN [0..source.size) DO
IF source[nodeIndex]=NIL THEN {
source[nodeIndex] ← destination;
RETURN;
};
ENDLOOP;
ERROR;
};
NodePositionHash: RefTab.HashProc = {
nodePosition: NodePosition ← NARROW[key];
hash: CARDINAL ← Basics.LowHalf[nodePosition.minorPosition];
bigHash: CARD32LOOPHOLE[Basics.DoubleXor[LOOPHOLE[nodePosition.majorPosition.x], LOOPHOLE[nodePosition.majorPosition.y]]];
hash ← Basics.BITXOR[hash, Basics.LowHalf[bigHash]];
hash ← Basics.BITXOR[hash, Basics.HighHalf[bigHash]];
RETURN[hash];
};
NodePositionEqual: RefTab.EqualProc = {
np1: NodePosition ← NARROW[key1];
np2: NodePosition ← NARROW[key2];
RETURN[np1^=np2^];
};
ComputeSize: PROC [channelSizes: ChannelSizes] RETURNS [size: INT ← -1] = {
FOR ci: CARDINAL IN [0..channelSizes.size) DO
size ← size + channelSizes[ci] + 1;
ENDLOOP;
};
maxNodeCount: NAT ← 0;
RouteSurface: PROC [surface: Surface] RETURNS [incomplete: CoreFlat.FlatWires] = {
RouteWire: RefTab.EachPairAction = {
wire: CoreFlat.FlatWire ← NARROW[key];
ne: NetEnds ← NARROW[RefTab.Fetch[surface.flatWires, wire].val];
inputs: Nodes ← ne.inputs;
IF inputs#NIL THEN {
seed: Node;
IF ne.output=NIL THEN {
seed ← inputs.first;
inputs ← inputs.rest;
}
ELSE seed ← ne.output;
IF inputs#NIL THEN {
FIFOQueue.Include[fifo, seed];
UNTIL FIFOQueue.IsEmpty[fifo] DO
FOR il: Nodes ← inputs, il.rest UNTIL il=NIL DO
IF il.first.back=NIL THEN EXIT;
REPEAT FINISHED => {
FOR il: Nodes ← inputs, il.rest UNTIL il=NIL DO
nodeCount: NAT ← 0;
assign: Node ← il.first;
UNTIL assign=NIL DO
assign.flatWire ← wire;
assign ← assign.back;
nodeCount ← nodeCount + 1;
ENDLOOP;
maxNodeCount ← MAX[maxNodeCount, nodeCount];
ENDLOOP;
EXIT;
};
ENDLOOP;
{
current: Node ← NARROW[FIFOQueue.Remove[fifo]];
FOR ni: NodeIndex IN [0..current.size) DO
neighbor: Node ← current[ni];
IF (neighbor.flatWire=NIL OR (neighbor#seed AND CoreFlat.FlatWireEqual[neighbor.flatWire, wire])) AND neighbor.back=NIL THEN {
neighbor.back ← current;
FIFOQueue.Include[fifo, neighbor];
};
ENDLOOP;
};
REPEAT FINISHED => incomplete ← CONS[wire, incomplete];
ENDLOOP;
CleanUpBackPointers[fifo, seed];
};
};
};
fifo: FIFOQueue.Queue ← FIFOQueue.Create[];
[] ← RefTab.Pairs[surface.flatWires, RouteWire];
};
CleanUpBackPointers: PROC [fifo: FIFOQueue.Queue, seed: Node] = {
FIFOQueue.Flush[fifo];
FIFOQueue.Include[fifo, seed];
UNTIL FIFOQueue.IsEmpty[fifo] DO
current: Node ← NARROW[FIFOQueue.Remove[fifo]];
FOR ni: NodeIndex IN [0..current.size) DO
neighbor: Node ← current[ni];
IF neighbor.back#NIL THEN {
neighbor.back ← NIL;
FIFOQueue.Include[fifo, neighbor];
};
ENDLOOP;
ENDLOOP;
};
Display
SurfaceViewer: TYPE = REF SurfaceViewerRec;
SurfaceViewerRec: TYPE = RECORD [
surface: Surface ← NIL,
completed: BOOLTRUE, -- nodes assigned to wires
allocated: BOOLFALSE, -- all allocated nodes
flatWires: CoreFlat.FlatWires ← NIL]; -- net endpoints
surfaceViewerAtom: ATOM = $SurfaceViewer;
surfaceViewerClass: ViewerClasses.ViewerClass ← NEW [ViewerClasses.ViewerClassRec ← [paint: PaintSurfaceViewer]];
AllWires: PROC [surface: Surface] RETURNS [wires: CoreFlat.FlatWires ← NIL] = {
AddWire: RefTab.EachPairAction = {
wire: CoreFlat.FlatWire ← NARROW[key];
wires ← CONS[wire, wires];
};
[] ← RefTab.Pairs[surface.flatWires, AddWire];
};
DisplayWires: PROC [surface: Surface, endpoints: CoreFlat.FlatWires ← NIL, completed: BOOLTRUE, allocated: BOOLFALSE] = {
viewer: ViewerClasses.Viewer;
surfaceViewer: SurfaceViewer ← NEW[SurfaceViewerRec];
surfaceViewer.surface ← surface;
surfaceViewer.allocated ← allocated;
surfaceViewer.completed ← completed;
surfaceViewer.flatWires ← endpoints;
viewer ← ViewerOps.CreateViewer[
flavor: surfaceViewerAtom,
info: [
name: CoreOps.GetCellTypeName[surface.array.root],
iconic: FALSE,
column: color,
border: TRUE,
data: surfaceViewer
]
];
};
PaintSurfaceViewer: ViewerClasses.PaintProc = {
ToVec: PROC [pos: NodePosition] RETURNS [vec: Imager.VEC] = {
p1, p2: Imager.VEC;
[p1, p2] ← ToVecPair[pos];
vec.x ← (p1.x + p2.x) / 2.0;
vec.y ← (p1.y + p2.y) / 2.0;
};
ToVecPair: PROC [pos: NodePosition] RETURNS [p1, p2: Imager.VEC] = {
minorAdjust: REAL ← (1+4*pos.minorPosition)*minorGrid;
p1 ← [bounds.x + pos.majorPosition.x*grid, bounds.y + pos.majorPosition.y*grid];
SELECT pos.type FROM
verticalLong => {
p1.x ← p1.x + minorAdjust;
p1.y ← bounds.y;
p2.x ← p1.x;
p2.y ← p1.y + size.y*grid;
};
sequentialIn, verticalShort => {
p1.x ← p1.x + minorAdjust + minorGrid;
p2.x ← p1.x;
p2.y ← p1.y + grid;
};
sequentialOut, verticalOutput => {
p1.x ← p1.x + minorAdjust + 2.0*minorGrid;
p2.x ← p1.x;
p2.y ← p1.y + grid;
};
horizontalLong => {
p1.y ← p1.y + minorAdjust;
p1.x ← bounds.x;
p2.y ← p1.y;
p2.x ← p1.x + size.x*grid;
};
horizontalShort => {
p1.y ← p1.y + minorAdjust + minorGrid;
p2.y ← p1.y;
p2.x ← p1.x + grid;
};
horizontalOutput => {
p1.y ← p1.y + minorAdjust + 2.0*minorGrid;
p2.y ← p1.y;
p2.x ← p1.x + grid;
};
ENDCASE => ERROR;
};
PaintNode: RefTab.EachPairAction = {
node: Node ← NARROW[val];
IF node.flatWire#NIL THEN {
p1, p2: Imager.VEC;
[p1, p2] ← ToVecPair[node.position];
Imager.MaskVector[context, p1, p2];
};
};
surfaceViewer: SurfaceViewer ← NARROW[self.data];
size: MajorGridPosition ← surfaceViewer.surface.size;
xChannels: ChannelSizes ← surfaceViewer.surface.channelSizes[vertical];
yChannels: ChannelSizes ← surfaceViewer.surface.channelSizes[horizontal];
bounds: Imager.Rectangle ← ImagerBackdoor.GetBounds[context];
grid: REALMIN[bounds.w, bounds.h]/MAX[size.x, size.y];
minorGrid: REAL ← (grid/surfaceViewer.surface.array.a)/4.0;
xpos: REAL ← bounds.x;
IF clear THEN {
Imager.SetColor[context, Imager.white];
Imager.MaskRectangle[context, bounds];
};
Imager.SetColor[context, Imager.black];
Imager.SetStrokeWidth[context, grid/10.0];
FOR x: INT IN [0..xChannels.size-1) DO
ypos: REAL ← bounds.y;
xpos ← xpos + grid*xChannels[x];
FOR y: INT IN [0..yChannels.size-1) DO
xr, yu: REAL;
ypos ← ypos + grid*yChannels[y];
xr ← xpos + grid;
yu ← ypos + grid;
Imager.MaskVector[context, [xpos, ypos], [xr, ypos]];
Imager.MaskVector[context, [xpos, ypos], [xpos, yu]];
Imager.MaskVector[context, [xr, yu], [xr, ypos]];
Imager.MaskVector[context, [xr, yu], [xpos, yu]];
ypos ← ypos + grid;
ENDLOOP;
xpos ← xpos + grid;
ENDLOOP;
Imager.SetStrokeWidth[context, grid/40.0];
Imager.SetColor[context, Imager.black];
FOR wl: CoreFlat.FlatWires ← surfaceViewer.flatWires, wl.rest UNTIL wl=NIL DO
ne: NetEnds ← NARROW[RefTab.Fetch[surfaceViewer.surface.flatWires, wl.first].val];
inputs: Nodes ← ne.inputs;
IF inputs#NIL THEN {
firstPos: Imager.VEC;
IF ne.output=NIL THEN {
firstPos ← ToVec[inputs.first.position];
inputs ← inputs.rest;
}
ELSE firstPos ← ToVec[ne.output.position];
FOR il: Nodes ← inputs, il.rest UNTIL il=NIL DO
inputPos: Imager.VEC ← ToVec[il.first.position];
Imager.MaskVector[context, firstPos, inputPos];
ENDLOOP;
};
ENDLOOP;
Imager.SetGray[context, 0.5];
IF surfaceViewer.completed THEN [] ← RefTab.Pairs[surfaceViewer.surface.nodes, PaintNode];
IF surfaceViewer.allocated THEN {
fifo: FIFOQueue.Queue ← FIFOQueue.Create[];
seedPosition: NodePosition ← NEW[NodePositionRec ← [horizontalShort, [0, 0], 0]];
seed: Node ← NARROW[RefTab.Fetch[surfaceViewer.surface.nodes, seedPosition].val];
FIFOQueue.Include[fifo, seed];
UNTIL FIFOQueue.IsEmpty[fifo] DO
current: Node ← NARROW[FIFOQueue.Remove[fifo]];
FOR ni: NodeIndex IN [0..current.size) DO
neighbor: Node ← current[ni];
IF neighbor.back=NIL THEN {
p1, p2: Imager.VEC;
[p1, p2] ← ToVecPair[neighbor.position];
Imager.MaskVector[context, p1, p2];
neighbor.back ← current;
FIFOQueue.Include[fifo, neighbor];
};
ENDLOOP;
ENDLOOP;
CleanUpBackPointers[fifo, seed];
};
}; 
Initialization
LoadPrimitiveTypes[];
ViewerOps.RegisterViewerClass[surfaceViewerAtom, surfaceViewerClass];
END.