DIRECTORY Ascii, CD, CDBasics, CDCurves, CDInstances, CDOps, CDProperties, CDRects, Combinatorial, Core, CoreFlat, CoreOps, DABasics, GList, IO, PrincOps, PW, Real, RefTab, Rope, Rsh, SymTab, TerminalIO, UnixRemoteFile, UserCredentials, VM;

SoftHdwFlat: CEDAR PROGRAM
IMPORTS Ascii, CD, CDBasics, CDCurves, CDInstances, CDOps, CDProperties, CDRects, Combinatorial, CoreFlat, CoreOps, GList, IO, PW, Real, RefTab, Rope, Rsh, SymTab, TerminalIO, UnixRemoteFile, UserCredentials, VM
EXPORTS 
= BEGIN
FlatCell: TYPE = REF FlatCellRec;
FlatCellRec: TYPE = RECORD [
root: Core.CellType,
wires: RefTab.Ref];  -- maps CoreFlat.FlatWire to Primitive

Primitives: TYPE = LIST OF Primitive;
Primitive: TYPE = REF PrimitiveRec;
PrimitiveRec: TYPE = RECORD [
flatClock: CoreFlat.FlatWire,   -- not NIL => sequential element
flatCell: CoreFlat.FlatCellTypeRec,
flatOutput: CoreFlat.FlatWire,
negateOutput: BOOL,
sinks: Primitives _ NIL,  -- NIL => primary output or unused
inputs: SEQUENCE size: CARDINAL OF PolarizedInputRec];

PolarizedInputs: TYPE = LIST OF PolarizedInputRec;
PolarizedInputRec: TYPE = RECORD [
flatInput: CoreFlat.FlatWire,
negate: BOOL,
source: Primitive _ NIL];  -- NIL => primary input

Placement: TYPE = REF PlacementRec;
PlacementRec: TYPE = RECORD [
flatCell: FlatCell,
sizes: ArrayPosition,
maxChip: DABasics.Position,
positions: RefTab.Ref];  -- maps Primitive to PrimitiveAssignment

PrimitiveAssignment: TYPE = REF PrimitiveAssignmentRec;
PrimitiveAssignmentRec: TYPE = RECORD [
position: ArrayPosition,
inputIndicies: SEQUENCE size: CARDINAL OF CARDINAL];

ArrayPositions: TYPE = LIST OF ArrayPositionRec;
ArrayPosition: TYPE = REF ArrayPositionRec;
ArrayPositionRec: TYPE = RECORD [
chip: DABasics.Position,
minor: DABasics.Position,
grain: DABasics.Number,
orientation: Orientation,
type: NodeType];
Orientation: TYPE = {vertical, horizontal};

Surface: TYPE = REF SurfaceRec;
SurfaceRec: TYPE = RECORD [
sizes: ArrayPosition,
nodes: ARRAY NodeType OF NodeArrays];

NodeArrays: TYPE = RECORD [
base: NodeArray,
maxNeighbors: DABasics.Number,
nodeSize: DABasics.Number,
grainSize: DABasics.Number,
orientSize: DABasics.Number,
chipXSize: DABasics.Number,
chipYSize: DABasics.Number,
minorXSize: DABasics.Number];

NodeType: TYPE = {interchipVertical, interchipHorizontal, longVertical, longHorizontal, short, output};
NodeArray: TYPE = RECORD [
pages: INT,
base: LONG POINTER];
NodeLabel: TYPE = LONG POINTER;  -- really CoreFlat.FlatWire
Nodes: TYPE = LIST OF Node;
Node: TYPE = LONG POINTER TO NodeRec;
NodeRec: TYPE = RECORD [
fifoNext: Node,
position: ArrayPositionRec,
label: NodeLabel,
back: Node,
size: CARDINAL,
neighbors: SEQUENCE COMPUTED CARDINAL OF Node];

Path: TYPE = REF PathRec;
PathRec: TYPE = RECORD [
subPaths: SubPaths _ NIL,
path: SEQUENCE size: CARDINAL OF ArrayPositionRec];

SubPaths: TYPE = REF SubPathsRec;
SubPathsRec: TYPE = RECORD [
paths: SEQUENCE size: CARDINAL OF Path];

NetEndList: TYPE = LIST OF NetEnds;
NetEnds: TYPE = REF NetEndsRec;
NetEndsRec: TYPE = RECORD [
source: Node _ NIL,
destinations: Nodes _ NIL];

primitiveTypes: SymTab.Ref _ SymTab.Create[];
PrimitiveType: TYPE = {ignore, equate, and, nand, or, nor, xor2, xnor2, a22o2i, o22a2i, a21o2i, o21a2i, ff, ffEn, tstDriver};
PrimitiveSimpleType: TYPE = PrimitiveType[and..nor];
invertInputs: ARRAY PrimitiveSimpleType OF BOOL _ [FALSE, FALSE, TRUE, TRUE];
invertOutput: ARRAY PrimitiveSimpleType OF BOOL _ [TRUE, FALSE, FALSE, TRUE];
RopeList: TYPE = LIST OF Rope.ROPE;
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"], and];
InsertList[LIST["nand2", "nand3", "nand4"], nand];
InsertList[LIST["or2", "or3", "or4"], or];
InsertList[LIST["nor2", "nor3", "nor4"], nor];
Insert["xor2", xor2];
Insert["xnor2", xnor2];
Insert["a22o2i", a22o2i];
Insert["o22a2i", o22a2i];
Insert["a21o2i", a21o2i];
Insert["o21a2i", o21a2i];
Insert["ff", ff];
Insert["ffEn", ffEn];
Insert["tstDriver", tstDriver];
};

TriData: TYPE = REF TriDataRec;
TriDataRec: TYPE = RECORD [
count: NAT _ 0,
lastInput: CoreFlat.FlatWire _ NIL,
next: CoreFlat.FlatWire _ NIL];

Flatten: PROC [root: Core.CellType] RETURNS [flat: FlatCell] = {
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 = {
AddPrimitive: PROC [output: CoreFlat.FlatWire, negateOutput: BOOL, inputs: PolarizedInputs, clock: CoreFlat.FlatWire _ NIL] = {
p: Primitive;
index: CARDINAL _ 0;
size: CARDINAL _ 0;
FOR il: PolarizedInputs _ inputs, il.rest UNTIL il=NIL DO
size _ size + 1;
ENDLOOP;
p _ NEW[PrimitiveRec[size]];
p.flatClock _ IF clock=NIL THEN NIL ELSE FetchUnique[clock];
p.flatCell _ flatCell;
p.flatOutput _ FetchUnique[output];
p.negateOutput _ negateOutput;
FOR fws: PolarizedInputs _ inputs, fws.rest UNTIL fws=NIL DO
equivalent: CoreFlat.FlatWire;
polarity: BOOL;
[equivalent, polarity] _ GetEquivalent[fws.first.flatInput, fws.first.negate];
p.inputs[index].flatInput _ FetchUnique[equivalent];
p.inputs[index].negate _ polarity;
p.inputs[index].source _ NIL;
index _ index + 1;
ENDLOOP;
IF NOT RefTab.Insert[flat.wires, output, p] THEN {
ep: Primitive _ NARROW[RefTab.Fetch[flat.wires, output].val];
IF p.flatClock#ep.flatClock THEN ERROR;
IF p.flatOutput#ep.flatOutput THEN ERROR;
IF p.negateOutput#ep.negateOutput THEN ERROR;
IF p.size#ep.size THEN ERROR;
FOR index: CARDINAL IN [0..size) DO
IF p.inputs[index].flatInput#ep.inputs[index].flatInput THEN ERROR;
IF p.inputs[index].negate#ep.inputs[index].negate THEN ERROR;
ENDLOOP;
};
};
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;
and, nand, or, nor => {
flatOutput: CoreFlat.FlatWire _ GetNamedWire[bindings, cell.public, flatCell, "X"];
flatInputs: PolarizedInputs _ 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];
flatInputs _ CONS[[flatInput, invertInputs[primitiveType^]], flatInputs];
ENDLOOP;
AddPrimitive[flatOutput, invertOutput[primitiveType^], flatInputs];
};
xor2, xnor2 => {
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];
AddPrimitive[i1, FALSE, LIST[[a, TRUE], [b, FALSE]]];
AddPrimitive[i2, FALSE, LIST[[a, FALSE], [b, TRUE]]];
AddPrimitive[x, primitiveType^=xnor2, LIST[[i1, FALSE], [i2, FALSE]]];
};
a22o2i, o22a2i => {
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];
invertInputs: BOOL _ primitiveType^=o22a2i;
AddPrimitive[i1, FALSE, LIST[[a, invertInputs], [b, invertInputs]]];
AddPrimitive[i2, FALSE, LIST[[c, invertInputs], [d, invertInputs]]];
AddPrimitive[x, NOT invertInputs, LIST[[i1, FALSE], [i2, FALSE]]];
};
a21o2i, o21a2i => {
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];
invert: BOOL _ primitiveType^=o21a2i;
AddPrimitive[i, FALSE, LIST[[a, invert], [b, invert]]];
AddPrimitive[x, NOT invert, LIST[[i, FALSE], [c, NOT invert]]];
};
ff => {
d: CoreFlat.FlatWire _ GetNamedWire[bindings, cell.public, flatCell, "D"];
q: CoreFlat.FlatWire _ GetNamedWire[bindings, cell.public, flatCell, "Q"];
ck: CoreFlat.FlatWire _ GetNamedWire[bindings, cell.public, flatCell, "CK"];
AddPrimitive[q, FALSE, LIST[[d, FALSE]], ck];
};
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"];
ck: CoreFlat.FlatWire _ GetNamedWire[bindings, cell.public, flatCell, "CK"];
i1: CoreFlat.FlatWire _ CreateWire[flatCell];
i2: CoreFlat.FlatWire _ CreateWire[flatCell];
i3: CoreFlat.FlatWire _ CreateWire[flatCell];
AddPrimitive[i1, FALSE, LIST[[en, FALSE], [d, FALSE]]];
AddPrimitive[i2, FALSE, LIST[[en, TRUE], [q, FALSE]]];
AddPrimitive[i3, FALSE, LIST[[i1, FALSE], [i2, FALSE]]];
AddPrimitive[q, FALSE, LIST[[i3, FALSE]], ck];
};
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 triData.lastInput ELSE CreateWire[flatCell];
AddPrimitive[i1, FALSE, LIST[[en, FALSE], [i, FALSE]]];
AddPrimitive[i2, FALSE, LIST[[en, TRUE], [previous, FALSE]]];
AddPrimitive[triData.next, FALSE, LIST[[i1, FALSE], [i2, FALSE]]];
triData.count _ triData.count - 1;
triData.next _ previous;
};
};
ENDCASE => ERROR;
};
FillSourcesAndSinks: RefTab.EachPairAction = {
p: Primitive _ NARROW[val];
FOR index: CARDINAL IN [0..p.size) DO
p[index].source _ NARROW[RefTab.Fetch[flat.wires, p[index].flatInput].val];
IF p[index].source#NIL THEN p[index].source.sinks _ CONS[p, p[index].source.sinks];
ENDLOOP;
};
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];
};
GetEquivalent: PROC [from: CoreFlat.FlatWire, initialPolarity: BOOL _ FALSE] RETURNS [to: CoreFlat.FlatWire, polarity: BOOL] = {
polarity _ initialPolarity;
WHILE from#NIL DO
to _ from;
polarity _ NOT polarity;
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;
};
};
FetchUnique: PROC [from: CoreFlat.FlatWire] RETURNS [to: CoreFlat.FlatWire] = {
to _ NARROW[RefTab.Fetch[unique, from].val];
IF to=NIL THEN {
IF NOT RefTab.Insert[unique, from, from] THEN ERROR;
to _ from;
};
};
unique: RefTab.Ref _ RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
equivalence: RefTab.Ref _ RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
triDataTable: RefTab.Ref _ RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
flat _ NEW[FlatCellRec];
flat.root _ root;
flat.wires _ RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
Equate[root];
[] _ RefTab.Pairs[triDataTable, EquateTristate];
Flatten[root];
[] _ RefTab.Pairs[flat.wires, FillSourcesAndSinks];
flat.root _ root;
};

fileHost: Rope.ROPE _ "palain-NFS";
cpuHost: Rope.ROPE _ "palain";
serverDir: Rope.ROPE _ "/timberwolf/";
remoteServer: Rope.ROPE _ "/palain/";
twCmd: Rope.ROPE _ "/usr/datools/TimberWolfSCrsh ";
fileMode: UnixRemoteFile.Mode _ 0666B;
lastMsg: Rope.ROPE _ NIL;

RopeSequence: TYPE = REF RopeSequenceRec;
RopeSequenceRec: TYPE = RECORD [ropes: SEQUENCE size: CARDINAL OF Rope.ROPE];

GrainPositions: TYPE = REF GrainPositionsRec;
GrainPositionsRec: TYPE = RECORD [rows: SEQUENCE size: CARDINAL OF GrainRow];
GrainRow: TYPE = REF GrainRowRec;
GrainRowRec: TYPE = RECORD [columns: SEQUENCE size: CARDINAL OF Primitive];

MinorArrays: TYPE = LIST OF MinorArray;
MinorArray: TYPE = REF MinorArrayRec;
MinorArrayRec: TYPE = RECORD [
rowIndex: CARDINAL _ 0,
primitives: ARRAY Orientation OF GrainSequence _ ALL[NIL]];

GrainSequence: TYPE = REF GrainSequenceRec;
GrainSequenceRec: TYPE = RECORD [
elements: SEQUENCE size: CARDINAL OF GrainRec];
GrainRec: TYPE = RECORD [
input: Primitive,
inputIndex: CARDINAL,
output: Primitive];

InputPositions: TYPE = LIST OF CARDINAL;

Place: PROC [flatCell: FlatCell, sizes: ArrayPosition, attPerCell: INT _ 50] RETURNS [placement: Placement] = {
grainPositions: GrainPositions _ TimberWolf[flatCell, sizes, attPerCell];
placement _ HayBaler[flatCell, sizes, grainPositions];
};

HayBaler: PROC [flatCell: FlatCell, sizes: ArrayPosition, grainPositions: GrainPositions] RETURNS [placement: Placement] = {
placement _ NEW[PlacementRec];
placement.maxChip _ [0, 0];
placement.positions _ RefTab.Create[];
FOR rowIndex: CARDINAL _ 0, rowIndex+sizes.grain UNTIL rowIndex>=grainPositions.size DO
rowMinors: MinorArrays _ NIL;
lastRowMinor: MinorArrays _ NIL;
columnCount: CARDINAL _ 0;
maxRowSize: CARDINAL _ 0;
FOR subRowIndex: DABasics.Number IN [0..sizes.grain) DO
y: CARDINAL _ rowIndex+subRowIndex;
IF y>=grainPositions.size THEN EXIT;
maxRowSize _ MAX[maxRowSize, grainPositions[y].size];
ENDLOOP;
FOR columnIndex: CARDINAL IN [0..maxRowSize) DO
FOR subRowIndex: DABasics.Number IN [0..sizes.grain) DO
y: CARDINAL _ rowIndex+subRowIndex;
pa: PrimitiveAssignment;
t: Orientation;
grain: DABasics.Number;
minor: MinorArray;
p: Primitive;
IF y>=grainPositions.size THEN EXIT;
IF columnIndex>=grainPositions[y].size THEN LOOP;
p _ grainPositions[y][columnIndex];
pa _ NEW[PrimitiveAssignmentRec[p.size]];
[t, grain, minor] _ GrainFirstFit[sizes.grain, p, rowMinors, pa];
IF minor=NIL THEN {
nt: Orientation;
minor _ NEW[MinorArrayRec];
minor.rowIndex _ columnCount;
columnCount _ columnCount + 1;
FOR o: Orientation IN Orientation DO
minor.primitives[o] _ NEW[GrainSequenceRec[sizes.grain]];
FOR index: DABasics.Number IN [0..sizes.grain) DO
minor.primitives[o][index].output _ NIL;
minor.primitives[o][index].input _ NIL;
minor.primitives[o][index].inputIndex _ 0;
ENDLOOP;
ENDLOOP;
t _ horizontal;
grain _ 0;
IF rowMinors=NIL THEN {
rowMinors _ LIST[minor];
lastRowMinor _ rowMinors;
}
ELSE {
lastRowMinor.rest _ LIST[minor];
lastRowMinor _ lastRowMinor.rest;
};
minor.primitives[t][grain].output _ p;
nt _ IF t=vertical THEN horizontal ELSE vertical;
FOR index: CARDINAL IN [0..p.size) DO
minor.primitives[nt][index].input _ p;
minor.primitives[nt][index].inputIndex _ index;
pa[index] _ index;
ENDLOOP;
};
{
chipX: INT _ minor.rowIndex/sizes.minor.x;
chipY: INT _ (rowIndex/sizes.grain)/sizes.minor.y;
pa.position _ NEW[ArrayPositionRec _ [
chip: [chipX, chipY],
minor: [minor.rowIndex MOD sizes.minor.x, (rowIndex/sizes.grain) MOD sizes.minor.y],
grain: grain,
orientation: t,
type: output]];
IF NOT RefTab.Insert[placement.positions, p, pa] THEN ERROR;
IF chipX>=sizes.chip.x OR chipY>=sizes.chip.y THEN ERROR;
placement.maxChip.x _ MAX[chipX, placement.maxChip.x];
placement.maxChip.y _ MAX[chipY, placement.maxChip.y];
};
ENDLOOP;
ENDLOOP;
ENDLOOP;
placement.flatCell _ flatCell;
placement.sizes _ sizes;
};

GrainFirstFit: PROC [grainSize: DABasics.Number, p: Primitive, minors: MinorArrays, pa: PrimitiveAssignment] RETURNS [t: Orientation, grain: DABasics.Number, minor: MinorArray] = {
FOR lm: MinorArrays _ minors, lm.rest UNTIL lm=NIL DO
minor _ lm.first;
FOR t IN Orientation DO
nt: Orientation _ IF t=vertical THEN horizontal ELSE vertical;
FOR grain IN [0..grainSize) DO
IF minor.primitives[t][grain].output=NIL THEN {
klip: InputPositions _ NIL;
FOR inputIndex: CARDINAL IN [0..p.size) DO
FOR searchIndex: DABasics.Number IN [0..grainSize) DO
searchGrain: GrainRec _ minor.primitives[nt][searchIndex];
IF searchGrain.input=NIL OR (searchGrain.input[searchGrain.inputIndex].flatInput = p[inputIndex].flatInput AND searchGrain.input[searchGrain.inputIndex].negate = p[inputIndex].negate) THEN {
IF searchGrain.input=NIL THEN klip _ CONS[searchIndex, klip];
minor.primitives[nt][searchIndex].input _ p;
minor.primitives[nt][searchIndex].inputIndex _ inputIndex;
pa[inputIndex] _ searchIndex;
EXIT;
};
REPEAT FINISHED => {
FOR lip: InputPositions _ klip, lip.rest UNTIL lip=NIL DO
minor.primitives[nt][lip.first].input _ NIL;
ENDLOOP;
GOTO IncompatibleInputs;
};
ENDLOOP;
REPEAT FINISHED => {
minor.primitives[t][grain].output _ p;
RETURN;
};
ENDLOOP;
};
REPEAT IncompatibleInputs => NULL;
ENDLOOP;
ENDLOOP;
ENDLOOP;
minor _ NIL;
};

TimberWolf: PROC [flatCell: FlatCell, sizes: ArrayPosition, attPerCell: INT _ 50] RETURNS [grainPositions: GrainPositions] = {
rootName, filePathName: Rope.ROPE;
cellNames: SymTab.Ref;
[rootName, filePathName, cellNames] _ WriteTimberWolf[flatCell, sizes, attPerCell];
lastMsg _ Rsh.RSH[
remoteMachine: cpuHost,
command: Rope.Cat[twCmd, rootName],
in: IO.noInputStream, out: TerminalIO.TOS[]];
grainPositions _ ReadTimberWolf[filePathName, cellNames];
};

WriteTimberWolf: PROC [flatCell: FlatCell, sizes: ArrayPosition, attPerCell: INT] RETURNS [rootName, filePathName: Rope.ROPE, cellNames: SymTab.Ref] = {
rowCount: INT _ (sizes.grain*Real.Round[Real.SqRt[RefTab.GetSize[flatCell.wires]]])/2;
blockRadius: INT _ sizes.grain+2;
server: UnixRemoteFile.UnixServerHandle _ UnixRemoteFile.CreateHandle[fileHost];
rootName _ CoreOps.GetCellTypeName[flatCell.root];
filePathName _ Rope.Cat[Rope.Cat[remoteServer, GuessUnixName[], serverDir], rootName];
{  -- first the net file
netStream: IO.STREAM _ UnixRemoteFile.OpenWriteStream[server, [Rope.Cat[filePathName, ".net"]], fileMode];
IO.Put[netStream, IO.rope["allnets HVweights 1.0 1.0\l"]];
IO.Flush[netStream]; 
IO.Close[netStream];
};
{  --  next the parameter file
parStream: IO.STREAM _ UnixRemoteFile.OpenWriteStream[server, [Rope.Cat[filePathName, ".par"]], fileMode];
IO.Put[parStream, IO.rope["att.per.cell "], IO.int[attPerCell], IO.rope["\l"]];
IO.Put[parStream, IO.rope["rowSep 0.0\l"]];
IO.Put[parStream, IO.rope["indent 1.0\l"]];
IO.Flush[parStream]; 
IO.Close[parStream];
};
{  --  next the row definitions
blkStream: IO.STREAM _ UnixRemoteFile.OpenWriteStream[server, [Rope.Cat[filePathName, ".blk"]], fileMode];
FOR row: INT IN [1 .. rowCount] DO
IO.Put[blkStream, IO.rope["block height "], IO.int[2*blockRadius], IO.rope[" class 1 nofeeds\l"]];
ENDLOOP;
IO.Flush[blkStream]; 
IO.Close[blkStream];
};
{  --  finally the connectivity
EmitPrimitive: RefTab.EachPairAction = {
WritePin: PROC [pinName: Rope.ROPE, signal: CoreFlat.FlatWire, position: INT] = {
micronPosition: INT _ 2*position-blockRadius+1;
signalName: Rope.ROPE _ NARROW[RefTab.Fetch[wireToName, signal].val];
IF signalName=NIL THEN {
signalName _ IO.PutFR["w%g", IO.int[wireCount]];
IF NOT RefTab.Insert[wireToName, signal, signalName] THEN ERROR;
wireCount _ wireCount + 1;
};
IO.PutF[celStream, "  pin name %g signal %g %g %g\l", IO.rope[pinName], IO.rope[signalName], IO.int[micronPosition], IO.int[blockRadius]];
IO.PutF[celStream, "  equiv name %g %g %g\l", IO.rope[pinName], IO.int[micronPosition], IO.int[-blockRadius]];
};
p: Primitive _ NARROW[val];
cellName: Rope.ROPE _ IO.PutFR["c%g", IO.int[cellCount]];
IF NOT SymTab.Insert[cellNames, cellName, p] THEN ERROR;
IO.PutF[celStream, "cell %g %g\l", IO.int[cellCount], IO.rope[cellName]];
IO.PutRope[celStream, "  nomirror\l"];
IO.PutF[celStream, "  left -%g right %g bottom -%g top %g\l", IO.int[blockRadius], IO.int[blockRadius], IO.int[blockRadius], IO.int[blockRadius]];
WritePin["out", p.flatOutput, blockRadius-1];
IF p.flatClock#NIL THEN WritePin["clock", p.flatClock, blockRadius-2];
FOR index: CARDINAL IN [0..p.size) DO
WritePin[inputNames[index], p.inputs[index].flatInput, index];
ENDLOOP;
cellCount _ cellCount + 1;
};
celStream: IO.STREAM _ UnixRemoteFile.OpenWriteStream[server, [Rope.Cat[filePathName, ".cel"]], fileMode];
cellCount: INT _ 0;
wireCount: INT _ 0;
wireToName: RefTab.Ref _ RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
inputNames: RopeSequence _ NEW[RopeSequenceRec[sizes.grain]];
FOR index: INT IN [0..sizes.grain) DO
inputNames[index] _ IO.PutFR["in%g", IO.int[index]];
ENDLOOP;
cellNames _ SymTab.Create[];
[] _ RefTab.Pairs[flatCell.wires, EmitPrimitive];
IO.Flush[celStream]; 
IO.Close[celStream];
UnixRemoteFile.DestroyHandle[server];
};
};

ReadTimberWolf: PROC [filePathName: Rope.ROPE, cellNames: SymTab.Ref] RETURNS [grainPositions: GrainPositions] = {
ConsColumnPrimitives: PROC = {
IF columnPrimitives#NIL THEN {
rowPrimitives _ CONS[columnPrimitives, rowPrimitives];
columnPrimitives _ NIL;
rowCount _ rowCount + 1;
};
};
server: UnixRemoteFile.UnixServerHandle _ UnixRemoteFile.CreateHandle[fileHost];
placeStream: IO.STREAM _ UnixRemoteFile.OpenReadStream[server, [Rope.Cat[filePathName, ".pl1"]]];
rowCount, lastRow: INT _ 0;
rowPrimitives: LIST OF Primitives _ NIL;
columnPrimitives: Primitives _ NIL;
[] _ IO.SkipWhitespace[placeStream];
WHILE ~IO.EndOf[placeStream] DO
name: Rope.ROPE _ IO.GetTokenRope[placeStream, IO.IDProc].token;
p: Primitive _ NARROW[SymTab.Fetch[cellNames, name].val];
left: INT _ IO.GetInt[placeStream];
lower: INT _ IO.GetInt[placeStream];
right: INT _ IO.GetInt[placeStream];
upper: INT _ IO.GetInt[placeStream];
orient: INT _ IO.GetInt[placeStream];
row: INT _ IO.GetInt[placeStream];
[] _ IO.SkipWhitespace[placeStream];
IF row#lastRow THEN ConsColumnPrimitives[];
columnPrimitives _ CONS[p, columnPrimitives];
lastRow _ row;
ENDLOOP;
ConsColumnPrimitives[];
IO.Close[placeStream];
UnixRemoteFile.DestroyHandle[server];
grainPositions _ NEW[GrainPositionsRec[rowCount]];
FOR rowIndex: INT DECREASING IN [0..rowCount) DO
columnPrimitives: Primitives _ rowPrimitives.first;
columnCount: CARDINAL _ GList.Length[columnPrimitives];
grainPositions[rowIndex] _ NEW[GrainRowRec[columnCount]];
FOR columnIndex: CARDINAL DECREASING IN [0..columnCount) DO
grainPositions[rowIndex][columnIndex] _ columnPrimitives.first;
columnPrimitives _ columnPrimitives.rest;
ENDLOOP;
IF columnPrimitives#NIL THEN ERROR;
rowPrimitives _ rowPrimitives.rest;
ENDLOOP;
IF rowPrimitives#NIL THEN ERROR;
};

GuessUnixName: PROC RETURNS [unixName: Rope.ROPE] ~ {
unixName _ UserCredentials.Get[].name;
unixName _ Rope.Substr[unixName, 0, MIN[8, Rope.Index[unixName, 0, "."]]];
unixName _ Rope.Translate[base: unixName, translator: MyLower];
};

MyLower: Rope.TranslatorType ~ {RETURN[Ascii.Lower[old]]};

AddChannels: PROC [old: Placement, channelSize: NAT _ 1] RETURNS [new: Placement] = {
Adjust: RefTab.EachPairAction = {
p: Primitive _ NARROW[key];
oldPA: PrimitiveAssignment _ NARROW[val];
newPA: PrimitiveAssignment _ NEW[PrimitiveAssignmentRec[oldPA.size]];
oldPos: ArrayPosition _ oldPA.position;
newPos: ArrayPosition _ NEW[ArrayPositionRec];
newX: INT _ channelSize + (1+channelSize)*(oldPos.minor.x + oldPos.chip.x*old.sizes.minor.x);
newY: INT _ channelSize + (1+channelSize)*(oldPos.minor.y + oldPos.chip.y*old.sizes.minor.y);
newPos^ _ oldPos^;
newPos.minor.x _ newX MOD old.sizes.minor.x;
newPos.chip.x _ newX / old.sizes.minor.x;
newPos.minor.y _ newY MOD old.sizes.minor.y;
newPos.chip.y _ newY / old.sizes.minor.y;
IF newPos.chip.x>=old.sizes.chip.x OR newPos.chip.y>=old.sizes.chip.y THEN ERROR;
new.maxChip.x _ MAX[newPos.chip.x, new.maxChip.x];
new.maxChip.y _ MAX[newPos.chip.y, new.maxChip.y];
newPA.position _ newPos;
FOR index: CARDINAL IN [0..oldPA.size) DO
newPA[index] _ oldPA[index];
ENDLOOP;
IF NOT RefTab.Insert[new.positions, p, newPA] THEN ERROR;
};
new _ NEW[PlacementRec];
new^ _ old^;
new.positions _ RefTab.Create[];
[] _ RefTab.Pairs[old.positions, Adjust];
};

CreateSurfaceAndRoute: PROC [placement: Placement] RETURNS [route: RefTab.Ref, incompleteNetEnds: NetEndList, incomplete: INT _ 0] = {
sizes: ArrayPosition _ NEW[ArrayPositionRec];
surface: Surface;
sizes^ _ placement.sizes^;
sizes.chip.x _ placement.maxChip.x + 1;
sizes.chip.y _ placement.maxChip.y + 1;
surface _ CreateSurface[sizes];
[route, incompleteNetEnds] _ RouteSurface[placement, surface];
FOR nel: NetEndList _ incompleteNetEnds, nel.rest UNTIL nel=NIL DO
incomplete _ incomplete + 1;
ENDLOOP;
};

FreeSurface: PROC [surface: Surface] = {
FOR nt: NodeType IN NodeType DO
FreeNodeArray[surface.nodes[nt].base];
ENDLOOP;
};

CreateSurface: PROC [sizes: ArrayPosition] RETURNS [surface: Surface] = {
position: ArrayPosition _ NEW[ArrayPositionRec];
surface _ NEW[SurfaceRec];
FOR nt: NodeType IN NodeType DO
surface.nodes[nt].maxNeighbors _ SELECT nt FROM
longVertical => sizes.minor.y+2,
longHorizontal => sizes.minor.x+2,
short => 3+sizes.grain,
output, interchipVertical, interchipHorizontal => 4,
ENDCASE => ERROR;
surface.nodes[nt].nodeSize _ SIZE[NodeRec]+(surface.nodes[nt].maxNeighbors*SIZE[Node]);
surface.nodes[nt].grainSize _ surface.nodes[nt].nodeSize*sizes.grain;
surface.nodes[nt].chipXSize _ surface.nodes[nt].grainSize*sizes.chip.x;
surface.nodes[nt].chipYSize _ surface.nodes[nt].chipXSize*sizes.chip.y;
surface.nodes[nt].orientSize _ surface.nodes[nt].chipYSize*2;
surface.nodes[nt].minorXSize _ surface.nodes[nt].orientSize*sizes.minor.x;
surface.nodes[nt].base _ AllocateNodeArray[SELECT nt FROM
interchipVertical, longVertical => surface.nodes[nt].chipYSize*sizes.minor.x,
interchipHorizontal, longHorizontal => surface.nodes[nt].chipYSize*sizes.minor.y,
short, output => surface.nodes[nt].minorXSize*sizes.minor.y,
ENDCASE => ERROR];
ENDLOOP;
surface.sizes _ sizes;
EnumerateNodes[surface, position, InitializeNode];
position.orientation _ vertical;
FOR chipX: INT IN [0..sizes.chip.x) DO
position.chip.x _ chipX;
FOR chipY: INT IN [0..sizes.chip.y) DO
position.chip.y _ chipY;
FOR minorX: INT IN [0..sizes.minor.x) DO
position.minor.x _ minorX;
FOR grain: INT IN [0..sizes.grain) DO
long: Node;
position.grain _ grain;
position.type _ longVertical;
long _ PositionToNode[surface, position];
IF chipY<sizes.chip.y-1 THEN {
interchip, other: Node;
position.type _ interchipVertical;
interchip _ PositionToNode[surface, position];
CreateArc[surface, interchip, long];
CreateArc[surface, long, interchip];
position.minor.y _ sizes.minor.y-1;
position.type _ short;
other _ PositionToNode[surface, position];
CreateArc[surface, interchip, other];
CreateArc[surface, other, interchip];
position.type _ output;
other _ PositionToNode[surface, position];
CreateArc[surface, other, interchip];
position.chip.y _ chipY+1;
position.type _ longVertical;
other _ PositionToNode[surface, position];
CreateArc[surface, interchip, other];
CreateArc[surface, other, interchip];
position.minor.y _ 0;
position.type _ short;
other _ PositionToNode[surface, position];
CreateArc[surface, interchip, other];
CreateArc[surface, other, interchip];
position.type _ output;
other _ PositionToNode[surface, position];
CreateArc[surface, other, interchip];
position.chip.y _ chipY;
};
FOR minorY: INT IN [0..sizes.minor.y) DO
short, output: Node;
position.minor.y _ minorY;
position.type _ short;
short _ PositionToNode[surface, position];
position.type _ output;
output _ PositionToNode[surface, position];
CreateArc[surface, short, long];
CreateArc[surface, long, short];
CreateArc[surface, output, short];
CreateArc[surface, output, long];
IF minorY>0 THEN {
neighbor: Node;
position.minor.y _ minorY - 1;
position.type _ short;
neighbor _ PositionToNode[surface, position];
CreateArc[surface, neighbor, short];
position.type _ output;
neighbor _ PositionToNode[surface, position];
CreateArc[surface, neighbor, short];
};
IF minorY<sizes.minor.y-1 THEN {
neighbor: Node;
position.minor.y _ minorY + 1;
position.type _ short;
neighbor _ PositionToNode[surface, position];
CreateArc[surface, neighbor, short];
position.type _ output;
neighbor _ PositionToNode[surface, position];
CreateArc[surface, neighbor, short];
};
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
position.orientation _ horizontal;
FOR chipX: INT IN [0..sizes.chip.x) DO
position.chip.x _ chipX;
FOR chipY: INT IN [0..sizes.chip.y) DO
position.chip.y _ chipY;
FOR minorY: INT IN [0..sizes.minor.y) DO
position.minor.y _ minorY;
FOR grain: INT IN [0..sizes.grain) DO
long: Node;
position.grain _ grain;
position.type _ longHorizontal;
long _ PositionToNode[surface, position];
IF chipX<sizes.chip.x-1 THEN {
interchip, other: Node;
position.type _ interchipHorizontal;
interchip _ PositionToNode[surface, position];
CreateArc[surface, interchip, long];
CreateArc[surface, long, interchip];
position.minor.x _ sizes.minor.x-1;
position.type _ short;
other _ PositionToNode[surface, position];
CreateArc[surface, interchip, other];
CreateArc[surface, other, interchip];
position.type _ output;
other _ PositionToNode[surface, position];
CreateArc[surface, other, interchip];
position.chip.x _ chipX+1;
position.type _ longHorizontal;
other _ PositionToNode[surface, position];
CreateArc[surface, interchip, other];
CreateArc[surface, other, interchip];
position.minor.x _ 0;
position.type _ short;
other _ PositionToNode[surface, position];
CreateArc[surface, interchip, other];
CreateArc[surface, other, interchip];
position.type _ output;
other _ PositionToNode[surface, position];
CreateArc[surface, other, interchip];
position.chip.x _ chipX;
};
FOR minorX: INT IN [0..sizes.minor.x) DO
short, output: Node;
position.minor.x _ minorX;
position.type _ short;
short _ PositionToNode[surface, position];
position.type _ output;
output _ PositionToNode[surface, position];
CreateArc[surface, short, long];
CreateArc[surface, long, short];
CreateArc[surface, output, short];
CreateArc[surface, output, long];
IF minorX>0 THEN {
neighbor: Node;
position.minor.x _ minorX - 1;
position.type _ short;
neighbor _ PositionToNode[surface, position];
CreateArc[surface, neighbor, short];
position.type _ output;
neighbor _ PositionToNode[surface, position];
CreateArc[surface, neighbor, short];
};
IF minorX<sizes.minor.x-1 THEN {
neighbor: Node;
position.minor.x _ minorX + 1;
position.type _ short;
neighbor _ PositionToNode[surface, position];
CreateArc[surface, neighbor, short];
position.type _ output;
neighbor _ PositionToNode[surface, position];
CreateArc[surface, neighbor, short];
};
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
FOR chipX: INT IN [0..sizes.chip.x) DO
position.chip.x _ chipX;
FOR chipY: INT IN [0..sizes.chip.y) DO
position.chip.y _ chipY;
FOR minorX: INT IN [0..sizes.minor.x) DO
position.minor.x _ minorX;
FOR minorY: INT IN [0..sizes.minor.y) DO
position.minor.y _ minorY;
FOR grainX: INT IN [0..sizes.grain) DO
verticalShort, verticalOutput: Node;
position.orientation _ vertical;
position.grain _ grainX;
position.type _ short;
verticalShort _ PositionToNode[surface, position];
position.type _ output;
verticalOutput _ PositionToNode[surface, position];
FOR grainY: INT IN [0..sizes.grain) DO
horizontalShort, horizontalOutput: Node;
position.orientation _ horizontal;
position.grain _ grainY;
position.type _ short;
horizontalShort _ PositionToNode[surface, position];
position.type _ output;
horizontalOutput _ PositionToNode[surface, position];
CreateArc[surface, verticalShort, horizontalOutput];
CreateArc[surface, horizontalShort, verticalOutput];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
};

AllocateNodeArray: PROC [words: INT] RETURNS [array: NodeArray] = {
pageCount: INT _ VM.PagesForWords[words];
interval: VM.Interval _ VM.SimpleAllocate[pageCount];
IF interval.count#pageCount THEN ERROR;
array.pages _ pageCount;
array.base _ VM.AddressForPageNumber[interval.page];
};

FreeNodeArray: PROC [array: NodeArray] = TRUSTED {
VM.Free[[LOOPHOLE[array.base, INT]/PrincOps.wordsPerPage, array.pages]];
};

InitializeNode: EachNodeProc = TRUSTED {
node: Node _ PositionToNode[surface, position];
node.position _ position^;
node.label _ NIL;
node.back _ NIL;
node.size _ surface.nodes[position.type].maxNeighbors;
FOR index: INT IN [0..node.size) DO
node.neighbors[index] _ NIL;
ENDLOOP;
};

CreateArc: PROC [surface: Surface, source: Node, destination: Node] = TRUSTED {
FOR nodeIndex: INT IN [0..source.size) DO
IF source[nodeIndex]=NIL THEN {
source[nodeIndex] _ destination;
RETURN;
};
ENDLOOP;
ERROR;
};

PositionToNode: PROC [surface: Surface, position: ArrayPosition] RETURNS [node: Node] = {
type: NodeType _ position.type;
nodeAddress: LONG CARDINAL _ LOOPHOLE[surface.nodes[type].base.base];
nodeAddress _ nodeAddress +
surface.nodes[type].nodeSize*position.grain +
surface.nodes[type].grainSize*position.chip.x +
surface.nodes[type].chipXSize*position.chip.y;
nodeAddress _ nodeAddress + (SELECT type FROM
short, output => surface.nodes[type].chipYSize*(IF position.orientation=vertical THEN 1 ELSE 0) + surface.nodes[type].orientSize*position.minor.x + surface.nodes[type].minorXSize* position.minor.y,
interchipVertical, longVertical => surface.nodes[type].chipYSize*position.minor.x,
interchipHorizontal, longHorizontal => surface.nodes[type].chipYSize*position.minor.y,
ENDCASE => ERROR);
node _ LOOPHOLE[nodeAddress];
};

maxNodeCount: NAT _ 0;

RouteSurface: PROC [placement: Placement, surface: Surface] RETURNS [route: RefTab.Ref, incomplete: NetEndList] = {
EachPrimitivePosition: RefTab.EachPairAction = TRUSTED {
p: Primitive _ NARROW[key];
pa: PrimitiveAssignment _ NARROW[val];
node: Node _ PositionToNode[surface, pa.position];
ne: NetEnds _ FetchNetEnds[p.flatOutput];
node.label _ LOOPHOLE[p.flatOutput];
IF ne.source#NIL THEN ERROR;
ne.source _ node;
position^ _ pa.position^;
position.orientation _ IF position.orientation=vertical THEN horizontal ELSE vertical;
position.type _ short;
FOR index: CARDINAL IN [0..p.size) DO
label: NodeLabel _ LOOPHOLE[p[index].flatInput];
ne: NetEnds _ FetchNetEnds[p[index].flatInput];
position.grain _ pa[index];
node _ PositionToNode[surface, position];
IF node.label#NIL AND node.label#label THEN ERROR;
node.label _ label;
ne.destinations _ CONS[node, ne.destinations];
ENDLOOP;
};
RouteWire: RefTab.EachPairAction = TRUSTED {
wire: CoreFlat.FlatWire _ NARROW[key];
ne: NetEnds _ NARROW[val];
sourceDestinations: Nodes _ ne.destinations;
IF sourceDestinations#NIL THEN {
seed: Node;
destinations: Nodes _ NIL;
IF ne.source=NIL THEN seed _ sourceDestinations.first
ELSE seed _ ne.source;
FOR il: Nodes _ sourceDestinations, il.rest UNTIL il=NIL DO
IF il.first#seed THEN destinations _ CONS[il.first, destinations];
ENDLOOP;
IF destinations#NIL THEN {
somePath: BOOL _ FALSE;
label: NodeLabel _ seed.label;
fifoFirst: Node _ seed;
fifoLast: Node _ fifoFirst;
fifoLast.fifoNext _ NIL;
UNTIL fifoFirst=NIL DO
trail: Nodes _ NIL;
FOR il: Nodes _ destinations, il.rest UNTIL il=NIL DO
IF il.first.back=NIL THEN trail _ il
ELSE {
nodeCount: NAT _ 0;
assign: Node _ il.first;
UNTIL assign=NIL DO
assign.label _ label;
assign _ assign.back;
nodeCount _ nodeCount + 1;
ENDLOOP;
maxNodeCount _ MAX[maxNodeCount, nodeCount];
IF trail=NIL THEN destinations _ il.rest
ELSE trail.rest _ il.rest;
somePath _ TRUE;
};
ENDLOOP;
IF destinations=NIL THEN EXIT;
{
current: Node _ fifoFirst;
fifoFirst _ fifoFirst.fifoNext;
IF fifoFirst=NIL THEN fifoLast _ NIL;
FOR ni: CARDINAL IN [0..current.size) DO
neighbor: Node _ current[ni];
IF neighbor=NIL THEN EXIT;
IF (neighbor.label=NIL OR (neighbor#seed AND neighbor.label=label)) AND neighbor.back=NIL THEN {
neighbor.back _ current;
IF fifoLast=NIL THEN {
fifoFirst _ neighbor;
fifoLast _ fifoFirst;
}
ELSE {
fifoLast.fifoNext _ neighbor;
fifoLast _ fifoLast.fifoNext;
};
fifoLast.fifoNext _ NIL;
};
ENDLOOP;
};
REPEAT FINISHED => incomplete _ CONS[NEW[NetEndsRec _ [source: seed, destinations: destinations]], incomplete];
ENDLOOP;
IF somePath THEN IF NOT RefTab.Insert[route, wire, MakePath[seed]] THEN ERROR;
CleanUpBackPointers[seed];
};
};
};
FetchNetEnds: PROC [flatWire: CoreFlat.FlatWire] RETURNS [ne: NetEnds] = {
ne _ NARROW[RefTab.Fetch[netEnds, flatWire].val];
IF ne=NIL THEN {
ne _ NEW[NetEndsRec];
IF NOT RefTab.Insert[netEnds, flatWire, ne] THEN ERROR;
};
};
netEnds: RefTab.Ref _ RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
position: ArrayPosition _ NEW[ArrayPositionRec];
EnumerateNodes[surface, position, ScrubNode];
[] _ RefTab.Pairs[placement.positions, EachPrimitivePosition];
route _ RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
[] _ RefTab.Pairs[netEnds, RouteWire];
};

ScrubNode: EachNodeProc = TRUSTED {
node: Node _ PositionToNode[surface, position];
node.label _ NIL;
node.back _ NIL;
};

CleanUpBackPointers: PROC [seed: Node] = TRUSTED {
fifoFirst: Node _ seed;
fifoLast: Node _ fifoFirst;
fifoLast.fifoNext _ NIL;
UNTIL fifoFirst=NIL DO
current: Node _ fifoFirst;
fifoFirst _ fifoFirst.fifoNext;
IF fifoFirst=NIL THEN fifoLast _ NIL;
FOR ni: CARDINAL IN [0..current.size) DO
neighbor: Node _ current[ni];
IF neighbor=NIL THEN EXIT;
IF neighbor.back#NIL THEN {
neighbor.back _ NIL;
IF fifoLast=NIL THEN {
fifoFirst _ neighbor;
fifoLast _ fifoFirst;
}
ELSE {
fifoLast.fifoNext _ neighbor;
fifoLast _ fifoLast.fifoNext;
};
fifoLast.fifoNext _ NIL;
};
ENDLOOP;
ENDLOOP;
};

MakePath: PROC [current: Node] RETURNS [path: Path] = TRUSTED {
ListToSequence: PROC RETURNS [path: Path] = TRUSTED {
size: CARDINAL _ 0;
FOR pl: ArrayPositions _ positions, pl.rest UNTIL pl=NIL DO
size _ size + 1;
ENDLOOP;
path _ NEW[PathRec[size]];
FOR index: CARDINAL DECREASING IN [0..size) DO
path[index] _ positions.first;
positions _ positions.rest;
ENDLOOP;
IF positions#NIL THEN ERROR;
};
positions: ArrayPositions _ LIST[current.position];
DO
neighbors: Nodes _ NIL;
neighborCount: CARDINAL _ 0;
FOR ni: CARDINAL IN [0..current.size) DO
neighbor: Node _ current[ni];
IF neighbor=NIL THEN EXIT;
IF neighbor.back=current AND neighbor.label=current.label THEN {
neighbors _ CONS[neighbor, neighbors];
neighborCount _ neighborCount + 1;
};
ENDLOOP;
SELECT TRUE FROM
neighborCount=0 => {  -- tree leaf
path _ ListToSequence[];
EXIT;
};
neighborCount=1 => {  -- branch continues
current _ neighbors.first;
positions _ CONS[current.position, positions];
};
ENDCASE => {  -- tree branches
subPaths: SubPaths _ NEW[SubPathsRec[neighborCount]];
path _ ListToSequence[];
path.subPaths _ subPaths;
FOR index: CARDINAL DECREASING IN [0..neighborCount) DO
subPaths[index] _ MakePath[neighbors.first];
neighbors _ neighbors.rest;
ENDLOOP;
EXIT;
};
ENDLOOP;
};

EachNodeProc: TYPE = PROC [surface: Surface, position: ArrayPosition];
EnumerateNodes: PROC [surface: Surface, position: ArrayPosition, eachNode: EachNodeProc] = {
FOR chipX: INT IN [0..surface.sizes.chip.x) DO
position.chip.x _ chipX;
FOR chipY: INT IN [0..surface.sizes.chip.y) DO
position.chip.y _ chipY;
FOR minorX: INT IN [0..surface.sizes.minor.x) DO
position.minor.x _ minorX;
FOR minorY: INT IN [0..surface.sizes.minor.y) DO
position.minor.y _ minorY;
FOR o: Orientation IN Orientation DO
position.orientation _ o;
FOR grain: INT IN [0..surface.sizes.grain) DO
position.grain _ grain;
position.type _ short;
eachNode[surface, position];
position.type _ output;
eachNode[surface, position];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
FOR chipX: INT IN [0..surface.sizes.chip.x) DO
position.chip.x _ chipX;
FOR chipY: INT IN [0..surface.sizes.chip.y) DO
position.chip.y _ chipY;
FOR minorX: INT IN [0..surface.sizes.minor.x) DO
position.minor.x _ minorX;
FOR grain: INT IN [0..surface.sizes.grain) DO
position.grain _ grain;
position.type _ longVertical;
eachNode[surface, position];
position.type _ interchipVertical;
eachNode[surface, position];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
FOR chipX: INT IN [0..surface.sizes.chip.x) DO
position.chip.x _ chipX;
FOR chipY: INT IN [0..surface.sizes.chip.y) DO
position.chip.y _ chipY;
FOR minorY: INT IN [0..surface.sizes.minor.y) DO
position.minor.y _ minorY;
FOR grain: INT IN [0..surface.sizes.grain) DO
position.grain _ grain;
position.type _ longHorizontal;
eachNode[surface, position];
position.type _ interchipHorizontal;
eachNode[surface, position];
ENDLOOP;
ENDLOOP;
ENDLOOP;
ENDLOOP;
};

CheckRoute: PROC [route: RefTab.Ref] = {
EachRoutedWire: RefTab.EachPairAction = {
path: Path _ NARROW[val];
CheckPath[path];
};
CheckPath: PROC [path: Path] = {
FOR index: CARDINAL IN [0..path.size) DO
position: ArrayPosition _ NEW[ArrayPositionRec];
position^ _ path[index];
IF NOT RefTab.Insert[nodeTable, position, $Used] THEN ERROR;
ENDLOOP;
IF path.subPaths#NIL THEN FOR index: CARDINAL IN [0..path.subPaths.size) DO
CheckPath[path.subPaths[index]];
ENDLOOP;
};
nodeTable: RefTab.Ref _ RefTab.Create[hash: ArrayPositionHash, equal: ArrayPositionEqual];
[] _ RefTab.Pairs[route, EachRoutedWire];
};

ArrayPositionHash: RefTab.HashProc = {
Fold: PROC [current: CARD32, next: DABasics.Number] RETURNS [new: CARD32] = {
new _ LOOPHOLE[Basics.DoubleXor[LOOPHOLE[current], LOOPHOLE[next]]];
};
position: ArrayPosition _ NARROW[key];
long: CARD32 _ position.chip.x;
long _ Fold[long, position.chip.y];
long _ Fold[long, position.minor.x];
long _ Fold[long, position.minor.y];
long _ Fold[long, position.grain];
RETURN[Basics.LowHalf[long]];
};

ArrayPositionEqual: RefTab.EqualProc = {
position1: ArrayPosition _ NARROW[key1];
position2: ArrayPosition _ NARROW[key2];
IF position1.type#position2.type THEN RETURN[FALSE];
SELECT position1.type FROM
interchipVertical, longVertical => RETURN[position1.chip=position2.chip AND position1.minor.x=position2.minor.x AND position1.grain=position2.grain];
interchipHorizontal, longHorizontal => RETURN[position1.chip=position2.chip AND position1.minor.y=position2.minor.y AND position1.grain=position2.grain];
short, output => RETURN[position1^=position2^];
ENDCASE => ERROR;
};
AssemblyPrimitive: TYPE = {SToI, LToI, OToI, IToS, IToL, SToS, ComplexOToS, SimpleOToS, ProgramVertical, ProgramHorizontal, OToL, OToS, SToL, LToS};
assemblyPrimitives: ARRAY AssemblyPrimitive OF CD.Object _ ALL[NIL];
assemblyPrimitiveNames: ARRAY AssemblyPrimitive OF Rope.ROPE _ ["SToI", "LToI", "OToI", "IToS", "IToL", "SToS", "ComplexOToS", "SimpleOToS", "ProgramVertical", "ProgramHorizontal", "OToL", "OToS", "SToL", "LToS"];

RectangleColor: TYPE = {black, red, green, blue, yellow};
rectangleAtoms: ARRAY RectangleColor OF ATOM _ [$comment, $red, $green, $blue, $yellow];
rectangleLayers: ARRAY RectangleColor OF CD.Layer;

minorSize: DABasics.Number _ 72*8;
interChipSize: DABasics.Number _ 8*8;
interChipOffset: DABasics.Number _ 4*8;
longIndent: DABasics.Number _ 8*8;
grainSpacing: DABasics.Number _ 16*8;
shortOutputOffset: DABasics.Number _ 12*8;
shortOutputIndent: DABasics.Number _ 4*8;
outputOffset: DABasics.Number _ 4*8;

LoadAssemblyPrimitives: PROC  = {
design: CD.Design _ PW.OpenDesign["SoftHdwFlat.dale"];
CDOps.SetMutability[design, readonly];
FOR ap: AssemblyPrimitive IN AssemblyPrimitive DO
assemblyPrimitives[ap] _ PW.Get[design, assemblyPrimitiveNames[ap]];
ENDLOOP;
FOR rc: RectangleColor IN RectangleColor DO
rectangleLayers[rc] _ CD.FetchLayer[NIL, rectangleAtoms[rc]];
ENDLOOP;
};

PrintPlaceAndRoute: PROC [placement: Placement, route: RefTab.Ref, incompleteNetEnds: NetEndList] RETURNS [design: CD.Design] = {
PrintPlacement: RefTab.EachPairAction = {
pa: PrimitiveAssignment _ NARROW[val];
CreateRectangle[pa.position, green];
position^ _ pa.position^;
position.orientation _ IF position.orientation=vertical THEN horizontal ELSE vertical;
position.type _ short;
FOR index: CARDINAL IN [0..pa.size) DO
position.grain _ pa[index];
CreateRectangle[position, red];
CreateArc[position, pa.position];
ENDLOOP;
};
PrintRoute: RefTab.EachPairAction = {
path: Path _ NARROW[val];
PrintPath[path]
};
PrintPath: PROC [path: Path] = {
FOR index: CARDINAL IN [0..path.size) DO
position^ _ path[index];
CreateRectangle[position, blue];
IF index<path.size-1 THEN {
nextPosition^ _ path[index+1];
CreateArc[position, nextPosition];
};
ENDLOOP;
IF path.subPaths#NIL THEN FOR index: CARDINAL IN [0..path.subPaths.size) DO
PrintPath[path.subPaths[index]];
position^ _ path[path.size-1];
nextPosition^ _ path.subPaths[index][0];
CreateArc[position, nextPosition];
ENDLOOP;
};
CreateRectangle: PROC [position: ArrayPosition, color: RectangleColor] = {
size: DABasics.Position _ [0, 4];
orient: DABasics.Orientation _ original;  -- or rotate90X
off: DABasics.Position _ PositionCoordinates[position^];
size.x _ SELECT position.type FROM
longVertical => minorSize*placement.sizes.minor.y,
longHorizontal => minorSize*placement.sizes.minor.x,
interchipVertical, interchipHorizontal => interChipSize,
short, output => minorSize-2*shortOutputIndent,
ENDCASE => ERROR;
orient _ SELECT position.type FROM
interchipVertical, longVertical => rotate90X,
interchipHorizontal, longHorizontal => original,
short, output => (IF position.orientation=vertical THEN rotate90X ELSE original),
ENDCASE => ERROR;
il _ CONS[CDInstances.NewInst[CDRects.CreateRect[size, rectangleLayers[color]], [off, orient]], il];
CDProperties.PutInstanceProp[il.first, $SoftHdwArrayPosition, NEW[ArrayPositionRec _ position^]];
};
CreateArc: PROC [from, to: ArrayPosition] = {
Direction: TYPE = {left, right, up, down, sideways};
direction: Direction _ SELECT TRUE FROM
to.chip.x=from.chip.x AND to.minor.x=from.minor.x AND to.chip.y=from.chip.y AND to.minor.y=from.minor.y => sideways,
to.chip.x>from.chip.x OR to.minor.x>from.minor.x => right,
to.chip.y>from.chip.y OR to.minor.y>from.minor.y => up,
to.chip.x<from.chip.x OR to.minor.x<from.minor.x => left,
to.chip.y<from.chip.y OR to.minor.y<from.minor.y => down,
ENDCASE => ERROR;
arcType: AssemblyPrimitive _ SELECT from.type FROM
interchipVertical, interchipHorizontal => SELECT to.type FROM
longVertical, longHorizontal => IToL,
short => IToS,
ENDCASE => ERROR,
longVertical, longHorizontal => SELECT to.type FROM
interchipVertical, interchipHorizontal => LToI,
short => LToS,
ENDCASE => ERROR,
short => SELECT to.type FROM
interchipVertical, interchipHorizontal => SToI,
longVertical, longHorizontal => SToL,
short => SToS,
output => IF to.orientation=vertical THEN ProgramVertical ELSE ProgramHorizontal,
ENDCASE => ERROR,
output => SELECT to.type FROM
interchipVertical, interchipHorizontal => OToI,
longVertical, longHorizontal => OToL,
short => SELECT direction FROM
sideways => OToS,
up, right => SimpleOToS,
down, left => ComplexOToS,
ENDCASE => ERROR,
ENDCASE => ERROR,
ENDCASE => ERROR;
orient: DABasics.Orientation;
off: DABasics.Position_ [0, 0];
off.x _ from.chip.x*(placement.sizes.minor.x*minorSize+2*interChipSize);
off.y _ from.chip.y*(placement.sizes.minor.y*minorSize + 2*interChipSize);
SELECT arcType FROM
SToI, LToI, OToI => {
direction _ SELECT to.type FROM
interchipHorizontal => (IF from.chip.x=to.chip.x THEN right ELSE left),
interchipVertical => (IF from.chip.y=to.chip.y THEN up ELSE down),
ENDCASE => ERROR;
SELECT direction FROM
right => {
orient _ original;
off.x _ off.x + placement.sizes.minor.x*minorSize - shortOutputIndent;
off.y _ off.y + to.minor.y*minorSize + to.grain*grainSpacing + shortOutputIndent;
};
up => {
orient _ rotate90X;
off.x _ off.x + to.minor.x*minorSize + to.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + placement.sizes.minor.y*minorSize - shortOutputIndent;
};
down => {
orient _ rotate270;
off.x _ off.x + to.minor.x*minorSize + to.grain*grainSpacing + shortOutputIndent;
off.y _ off.y - interChipOffset;
};
left => {
orient _ mirrorX;
off.x _ off.x - interChipOffset;
off.y _ off.y + to.minor.y*minorSize + to.grain*grainSpacing + shortOutputIndent;
};
ENDCASE => ERROR;
};
IToS, IToL => {
direction _ SELECT from.type FROM
interchipHorizontal => (IF from.chip.x=to.chip.x THEN left ELSE right),
interchipVertical => (IF from.chip.y=to.chip.y THEN down ELSE up),
ENDCASE => ERROR;
SELECT direction FROM
left => {
orient _ mirrorX;
off.x _ off.x + placement.sizes.minor.x*minorSize - shortOutputIndent;
off.y _ off.y + to.minor.y*minorSize + to.grain*grainSpacing + shortOutputIndent;
};
down => {
orient _ rotate270;
off.x _ off.x + to.minor.x*minorSize + to.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + placement.sizes.minor.y*minorSize - shortOutputIndent;
};
up => {
orient _ rotate90X;
off.x _ off.x + to.minor.x*minorSize + to.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + placement.sizes.minor.y*minorSize + interChipOffset + interChipSize;
};
right => {
orient _ original;
off.x _ off.x + placement.sizes.minor.x*minorSize + interChipOffset + interChipSize;
off.y _ off.y + to.minor.y*minorSize + to.grain*grainSpacing + shortOutputIndent;
};
ENDCASE => ERROR;
};
SToS, ComplexOToS, SimpleOToS => SELECT direction FROM
right => {
orient _ original;
off.x _ off.x + to.minor.x*minorSize - shortOutputIndent;
off.y _ off.y + to.minor.y*minorSize + to.grain*grainSpacing + shortOutputIndent;
};
up => {
orient _ rotate90X;
off.x _ off.x + to.minor.x*minorSize + to.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + to.minor.y*minorSize - shortOutputIndent;
};
down => {
orient _ rotate270;
off.x _ off.x + from.minor.x*minorSize + from.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + from.minor.y*minorSize - shortOutputIndent;
};
left => {
orient _ mirrorX;
off.x _ off.x + from.minor.x*minorSize - shortOutputIndent;
off.y _ off.y + from.minor.y*minorSize + from.grain*grainSpacing + shortOutputIndent;
};
ENDCASE => ERROR;
OToL, OToS, SToL => {
IF from.orientation=vertical THEN {
orient _ original;
off.x _ off.x + from.minor.x*minorSize + from.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + from.minor.y*minorSize;
}
ELSE {
orient _ rotate90X;
off.x _ off.x + from.minor.x*minorSize;
off.y _ off.y + from.minor.y*minorSize + from.grain*grainSpacing + shortOutputIndent;
};
};
LToS => {
IF to.orientation=vertical THEN {
orient _ original;
off.x _ off.x + to.minor.x*minorSize + to.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + to.minor.y*minorSize;
}
ELSE {
orient _ rotate90X;
off.x _ off.x + to.minor.x*minorSize;
off.y _ off.y + to.minor.y*minorSize + to.grain*grainSpacing + shortOutputIndent;
};
};
ProgramVertical => {
orient _ original;
off.x _ off.x + to.minor.x*minorSize + to.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + from.minor.y*minorSize + from.grain*grainSpacing + shortOutputIndent;
};
ProgramHorizontal => {
orient _ original;
off.x _ off.x + from.minor.x*minorSize + from.grain*grainSpacing + shortOutputIndent;
off.y _ off.y + to.minor.y*minorSize + to.grain*grainSpacing + shortOutputIndent;
};
ENDCASE => ERROR;
{
base: DABasics.Position _ CD.InterestBase[assemblyPrimitives[arcType]];
tbase: DABasics.Position _ CDBasics.MapPoint[base, [[0, 0], orient]];
toff: DABasics.Position _ CDBasics.SubPoints[off, tbase];
size: DABasics.Position _ CD.InterestSize[assemblyPrimitives[arcType]];
SELECT orient FROM
rotate270 => toff.y _ toff.y + size.x;
mirrorX => toff.x _ toff.x + size.x;
ENDCASE;
il _ CONS[CDInstances.NewInst[assemblyPrimitives[arcType], [toff, orient]], il];
CDProperties.PutInstanceProp[il.first, $SoftHdwFromArrayPosition, NEW[ArrayPositionRec _ from^]];
CDProperties.PutInstanceProp[il.first, $SoftHdwToArrayPosition, NEW[ArrayPositionRec _ to^]];
};
};
PositionCoordinates: PROC [position: ArrayPositionRec] RETURNS [coordinates: CD.Position] = {
coordinates.x _ position.chip.x*(placement.sizes.minor.x*minorSize+2*interChipSize);
coordinates.y _ position.chip.y*(placement.sizes.minor.y*minorSize + 2*interChipSize);
SELECT position.type FROM
short, output => {
grainOffset: DABasics.Number _ shortOutputOffset + position.grain*grainSpacing + (IF position.type=output THEN outputOffset ELSE 0);
coordinates.x _ coordinates.x + position.minor.x*minorSize;
coordinates.y _ coordinates.y + position.minor.y*minorSize;
IF position.orientation=vertical THEN {
coordinates.x _ coordinates.x + grainOffset;
coordinates.y _ coordinates.y + shortOutputIndent;
}
ELSE {
coordinates.x _ coordinates.x + shortOutputIndent;
coordinates.y _ coordinates.y + grainOffset;
};
};
longVertical => coordinates.x _ coordinates.x + position.minor.x*minorSize + longIndent + position.grain*grainSpacing;
longHorizontal => coordinates.y _ coordinates.y + position.minor.y*minorSize + longIndent + position.grain*grainSpacing;
interchipVertical => {
coordinates.x _ coordinates.x + position.minor.x*minorSize + shortOutputOffset + position.grain*grainSpacing;
coordinates.y _ coordinates.y + placement.sizes.minor.y*minorSize + interChipOffset;
};
interchipHorizontal => {
coordinates.y _ coordinates.y + position.minor.y*minorSize + shortOutputOffset + position.grain*grainSpacing;
coordinates.x _ coordinates.x + placement.sizes.minor.x*minorSize + interChipOffset;
};
ENDCASE => ERROR;
};
il: CD.InstanceList _ NIL;
position: ArrayPosition _ NEW[ArrayPositionRec];
nextPosition: ArrayPosition _ NEW[ArrayPositionRec];
[] _ RefTab.Pairs[placement.positions, PrintPlacement];
[] _ RefTab.Pairs[route, PrintRoute];
{
NodeCoordinates: PROC [node: Node] RETURNS [position: CD.Position] = TRUSTED {
position _ PositionCoordinates[node.position];
SELECT node.position.type FROM
interchipVertical, interchipHorizontal, longVertical, longHorizontal => ERROR;  -- no net end should be on these nodes
short, output => SELECT node.position.orientation FROM
vertical => {
position.x _ position.x + 2;
position.y _ position.y + minorSize/2 - shortOutputIndent/2;
};
horizontal => {
position.x _ position.x + minorSize/2 - shortOutputIndent/2;
position.y _ position.y + 2;
};
ENDCASE => ERROR;
ENDCASE => ERROR;
};
FOR nel: NetEndList _ incompleteNetEnds, nel.rest UNTIL nel=NIL DO
ne: NetEnds _ nel.first;
from: CD.Position _ NodeCoordinates[ne.source];
FOR nl: Nodes _ ne.destinations, nl.rest UNTIL nl=NIL DO
to: CD.Position _ NodeCoordinates[nl.first];
line: CD.Object;
offset: CD.Position;
w: DABasics.Number _ 8;
w2: INT _ MAX[1, (w+1)/2];
min: CD.Position _ CDBasics.MinPoint[from, to];
max: CD.Position _ CDBasics.MaxPoint[from, to];
r: CD.Rect;
min _ [min.x-w2, min.y-w2];
max _ [max.x+w2, max.y+w2];
r _ CDBasics.ToRect[min, max];
IF (r.x2-r.x1)>LAST[NAT] OR (r.y2-r.y1)>LAST[NAT] THEN {
TerminalIO.PutRope["\nSome disconnect line is too long"];
}
ELSE {
[line, offset] _ CDCurves.CreateLine[LIST[from, to], w, rectangleLayers[yellow]];
il _ CONS[CDInstances.NewInst[line, [offset, original]], il];
CDProperties.PutInstanceProp[il.first, $SoftHdwFromArrayPosition, NEW[CD.Position _ from]];
CDProperties.PutInstanceProp[il.first, $SoftHdwToArrayPosition, NEW[CD.Position _ to]];
};
ENDLOOP;
ENDLOOP;
};
design _ PW.Draw[PW.CreateCell[il]]
};

InsertPrimitive: PROC [placement: Placement, minorx, minory: DABasics.Number, orientation: Orientation, grain: DABasics.Number, inputs: LIST OF DABasics.Number] = {
position: ArrayPosition _ NEW[ArrayPositionRec _ [
chip: [0, 0],
minor: [minorx, minory],
grain: grain,
orientation: orientation,
type: output]];
p: Primitive _ NEW[PrimitiveRec];
pa: PrimitiveAssignment;
size: INT _ 0;
FOR il: LIST OF DABasics.Number _ inputs, il.rest UNTIL il=NIL DO
size _ size + 1;
ENDLOOP;
pa _ NEW[PrimitiveAssignmentRec[size]];
pa.position _ position;
FOR index: INT IN [0..pa.size) DO
pa[index] _ inputs.first;
inputs _ inputs.rest;
ENDLOOP;
[] _ RefTab.Insert[placement.positions, p, pa];
};

PathElements: TYPE = LIST OF PathElement;
PathElement: TYPE = RECORD [
nodeType: NodeType,
minorx, minory: DABasics.Number,
orientation: Orientation,
grain: DABasics.Number,
chipx, chipy:DABasics.Number _ 0];

MakeSimplePath: PROC [route: RefTab.Ref, elements: PathElements] = {
flatWire: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec _ [wire: NEW[Core.WireRec[0]]]];
path: Path;
size: INT _ 0;
FOR el: PathElements _ elements, el.rest UNTIL el=NIL DO
size _ size + 1;
ENDLOOP;
path _ NEW[PathRec[size]];
FOR index: INT IN [0..path.size) DO
el: PathElement _ elements.first;
path[index] _ [
chip: [el.chipx, el.chipy],
minor: [el.minorx, el.minory],
grain: el.grain,
orientation: el.orientation,
type: el.nodeType];
elements _ elements.rest;
ENDLOOP;
[] _ RefTab.Insert[route, flatWire, path];
};

MakePlaceAndRoute: PROC RETURNS[placement: Placement, route: RefTab.Ref] = {
placement _ NEW[PlacementRec];
placement.flatCell _ NIL;
placement.sizes _ NEW[ArrayPositionRec _ [[4,4],[16,16],4,horizontal,output]];
placement.maxChip _ [1, 1];
placement.positions _ RefTab.Create[];
route _ RefTab.Create[hash: CoreFlat.FlatWireHash, equal: CoreFlat.FlatWireEqual];
};

LoadPrimitiveTypes[];
LoadAssemblyPrimitives[];
[] _ CDProperties.Register[$SoftHdwArrayPosition, [makeCopy: CDProperties.CopyVal], $SoftHdw];
[] _ CDProperties.Register[$SoftHdwFromArrayPosition, [makeCopy: CDProperties.CopyVal], $SoftHdw];
[] _ CDProperties.Register[$SoftHdwToArrayPosition, [makeCopy: CDProperties.CopyVal], $SoftHdw];

END.
��P��SoftHdwFlat.mesa
Copyright Ó 1988 by Xerox Corporation.  All rights reserved.
Barth, January 1, 1989 2:21:09 pm PST

Types

{short, output} => ARRAY [grain, chip.x, chip.y, orientation, minor.x, minor.y] OF NodeRec
{longVertical} => ARRAY [grain, chip.x, chip.y, minor.x] OF NodeRec
{longHorizontal} => ARRAY [grain, chip.x, chip.y, minor.y] OF NodeRec
{interchipVertical} => ARRAY [grain, chip.x, chip.y, minor.x] OF NodeRec
{interchipHorizontal} => ARRAY [grain, chip.x, chip.y, minor.y] OF NodeRec
A Path is a tree representation of a route.
Primitives
SoftHdwCoreA, SoftHdwCoreF, and SoftHdwCoreK are not handled by the following classification.
Flatten
Place
IF columnCount>4 THEN rowMinors _ rowMinors.rest;
get rid of the ".pa" & truncate to 8 char, put in lower case.
Route
route maps CoreFlat.FlatWire to Path
Output
Initialization

Ê@��˜�codešœ™K™<Kšœ%™%—K™�š
Ïk	œœzœœPœ˜ðK˜�—šÏnœœ˜Kš	œœjœœP˜ÓKšœ˜Kšœ˜—head™Kšœ
œœ
˜!šœ
œœ˜Kšœ˜KšœÏc&˜;K˜�—Kšœœœœ˜%Kšœœœ˜#šœœœ˜Kšœ Ÿ ˜@K˜#Kšœ˜Kšœœ˜KšœœŸ"˜<Kšœœœœ˜6K˜�—Kšœœœœ˜2šœœœ˜"Kšœ˜Kšœœ˜
KšœœŸ˜2K˜�—Kšœœœ˜#šœœœ˜Kšœ˜Kšœ˜Kšœ˜KšœŸ(˜AK˜�—Kšœœœ˜7šœœœ˜'Kšœ˜Kš	œœœœœ˜4K˜�—Kšœœœœ˜0Kšœœœ˜+šœœœ˜!Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K™�—šœ
œ˜+K˜�—Kšœ	œœ˜šœœœ˜Kšœ˜Kšœœ
œ
˜%K˜�—šœœœ˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜�—Kšœ
œY˜gšœœœ˜Kšœœ˜Kšœœœ˜Kšœœ8œ™ZKšœœ"œ™CKšœœ"œ™EKšœœ"œ™HKšœœ"œ™J—KšœœœœŸ˜<Kšœœœœ˜Kš	œœœœœ	˜%šœ	œœ˜K˜Kšœ˜Kšœ˜Kšœ˜Kšœœ˜Kš	œœœœœ˜/K˜�—K™+Kšœœœ	˜šœ	œœ˜Kšœœ˜Kšœœœœ˜3K˜�—Kšœ
œœ
˜!šœ
œœ˜Kšœœœœ˜(K˜�—Kšœœœœ	˜#Kšœ	œœ˜šœœœ˜Kšœœ˜Kšœœ˜K˜�——™
K™]Kšœ-˜-Kšœœj˜}Kšœœ˜4Kšœœœœœœœœ˜MKšœœœœœœœœ˜MKš	œ
œœœœ˜#šžœœ˜šž
œœ+˜;šœœœ˜1Kšœ˜Kšœ˜—K˜—šžœœ
œ˜7Kšœ)œ˜DK˜—Kšœœ˜-Kšœœ'˜6Kšœœ˜.Kšœœ#˜2Kšœœ˜*Kšœœ˜.Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜K˜�——™Kšœ	œœ˜šœœœ˜Kšœœ˜Kšœœ˜#Kšœœ˜K˜�—šžœœœ˜@šžœ ˜&šž
œœœ˜*Kšœ:˜:KšœI˜IKšœ6˜6KšœE˜EKšœ
œœœœœ˜)Kšœ3˜3K˜—Kšœœ!˜0Kšœœœ)˜RKšœœœp˜‰šœœ˜Kšœ˜Kšœ˜šœ˜KšœJ˜JKšœJ˜JKšœœ$˜=šœ	œœ˜Kšœ
œ
˜Kšœœ(œœ˜9K˜—Kšœ˜Kšœ"˜"Kšœ˜—Kšœ˜—K˜—šžœ˜)Kšœœ˜#Kšœœ˜Kšœœ6˜MKšœ˜K˜—šžœ ˜'šžœœ+œ6œ˜Kšœ
˜
Kšœœ˜Kšœœ˜šœ'œœ˜9Kšœ˜Kšœ˜—Kšœœ˜Kšœœœœœœ˜<Kšœ˜Kšœ#˜#Kšœ˜šœ)œœ˜<Kšœ˜Kšœ
œ˜KšœN˜NKšœ4˜4Kšœ"˜"Kšœœ˜K˜Kšœ˜—šœœ&œ˜2Kšœœ'˜=Kšœœœ˜'Kšœœœ˜)Kšœ œœ˜-Kšœœœ˜šœœœ˜#Kšœ6œœ˜CKšœ0œœ˜=Kšœ˜—K˜—K˜—Kšœœ!˜0Kšœœœ)˜RKšœœœq˜Ššœœ˜Kšœœ˜šœ˜KšœS˜SKšœœ˜"Kšœ&˜&šœDœœ˜VKšœJ˜JKšœ
œ8˜IKšœ˜—KšœC˜CK˜—šœ˜KšœL˜LKšœL˜LKšœJ˜JKšœ-˜-Kšœ-˜-Kš	œœœœœ˜5Kš	œœœœœ˜5Kšœ&œœœ˜FK˜—šœ˜KšœJ˜JKšœJ˜JKšœJ˜JKšœJ˜JKšœJ˜JKšœ-˜-Kšœ-˜-Kšœœ˜+Kšœœœ(˜DKšœœœ(˜DKš	œœœœœ˜BK˜—šœ˜KšœJ˜JKšœJ˜JKšœJ˜JKšœJ˜JKšœ,˜,Kšœœ˜%Kšœœœ˜7Kš	œœ	œœœ˜?K˜—šœ˜KšœJ˜JKšœJ˜JKšœL˜LKšœœœœ˜-K˜—šœ	˜	KšœL˜LKšœJ˜JKšœJ˜JKšœL˜LKšœ-˜-Kšœ-˜-Kšœ-˜-Kš	œœœœœ˜7Kš	œœœœœ˜6Kš	œœœœœ˜8Kšœœœœ˜.K˜—šœ˜KšœJ˜JKšœœ$˜=šœœ˜KšœJ˜JKšœL˜LKšœ-˜-Kšœ-˜-Kšœœœœ˜bKš	œœœœœ˜7Kš	œœœœœ˜=Kš	œœœœœ˜BKšœ"˜"Kšœ˜Kšœ˜—Kšœ˜—Kšœœ˜—K˜—šžœ˜.Kšœœ˜šœœœ
˜%Kšœœ3˜KKšœœœœ˜SKšœ˜—K˜—šž
œœ&œ"˜_Kšœœ˜%Kšœ˜Kšœ%˜%K˜—šžœœaœœ"˜¢Kšœ1˜1Kšœ2˜2K˜—šž
œœ,œœœ#œ˜€Kšœ˜šœœ˜Kšœ
˜
Kšœœ
˜Kšœœ%˜2Kšœ˜—K˜—šžœœTœ"˜Kšœœ#˜4šœ
œœ˜Kšœœ˜%Kšœ˜Kšœ˜K˜—K˜—šžœœœ˜OKšœœ!˜,šœœœ˜Kšœœ#œœ˜4K˜
K˜—K˜—K˜_K˜dKšœe˜eKšœœ˜Kšœ˜KšœW˜WK˜
Kšœ0˜0K˜Kšœ3˜3Kšœ˜K˜K˜�——™Kšœœ˜#Kšœœ˜Kšœœ˜&Kšœœ˜%Kšœœ#˜3Kšœ&˜&šœœœ˜K˜�—Kšœœœ˜)š
œœœ	œœœœ˜MK˜�—Kšœœœ˜-Kšœœœœœœ˜MKšœ
œœ
˜!šœ
œœœœœ˜KK˜�—Kšœ
œœœ˜'Kšœœœ˜%šœœœ˜Kšœ
œ˜Kš	œœ
œœœ˜;K˜�—Kšœœœ˜+šœœœ˜!Kšœ
œœœ˜/—šœ
œœ˜Kšœ˜Kšœœ˜Kšœ˜K˜�—š	œœœœœ˜(K˜�—šžœœ8œœ˜oKšœI˜IKšœ6˜6K˜K˜�—šžœœLœ˜|Kšœœ˜Kšœ˜Kšœ&˜&šœœœ˜WKšœœ˜Kšœœ˜ Kšœ
œ˜Kšœœ˜šœœ˜7Kšœœ˜#Kšœœœ˜$Kšœ
œ%˜5Kšœ˜—šœœœ˜/šœœ˜7Kšœœ˜#Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜
Kšœœœ˜$Kšœ%œœ˜1Kšœ#˜#Kšœœ!˜)KšœA˜Ašœœœ˜Kšœ˜Kšœœ˜Kšœ˜Kšœ˜šœœ
˜$Kšœœ ˜9šœœ˜1Kšœ$œ˜(Kšœ#œ˜'Kšœ*˜*Kšœ˜—Kšœ˜—Kšœ˜Kšœ
˜
šœœœ˜Kšœœ˜Kšœ˜K˜—šœ˜Kšœœ˜ Kšœ!˜!Kšœœ™1K˜—Kšœ&˜&Kšœœœœ
˜1šœœœ
˜%Kšœ&˜&Kšœ/˜/Kšœ˜Kšœ˜—K˜—šœ˜Kšœœ ˜*Kšœœ(˜2šœœ˜&Kšœ˜Kšœœ'œ˜TKšœ
˜
Kšœ˜Kšœ˜—Kšœœ+œœ˜<Kšœœœœ˜9Kšœœ˜6Kšœœ˜6K˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜Kšœ˜K˜K˜�—šž
œœZœ@˜´šœ#œœ˜5Kšœ˜šœœ
˜Kšœœœœ
˜>šœœ˜šœ#œœ˜/Kšœœ˜šœ
œœ
˜*šœœ˜5Kšœ:˜:š
œœœPœJœ˜¾Kšœœœœ˜=Kšœ,˜,Kšœ:˜:Kšœ˜Kšœ˜K˜—šœœ˜šœ&œœ˜9Kšœ(œ˜,Kšœ˜—Kšœ˜K˜—Kšœ˜—šœœ˜Kšœ&˜&Kšœ˜K˜—Kšœ˜—K˜—Kšœœ˜"Kšœ˜—Kšœ˜—Kšœ˜—Kšœœ˜Kšœ˜K˜�—šž
œœ8œœ%˜~Kšœœ˜"Kšœ˜KšœS˜Sšœœ˜Kšœ˜Kšœ#˜#Kšœœ œ˜-—Kšœ9˜9K˜K˜�—š
žœœ8œœœ˜˜Kšœ
œI˜VKšœ
œ˜!KšœP˜PKšœ2˜2KšœV˜VšœŸ˜KšœœœV˜jKšœœ&˜:Kšœ˜Kšœ˜K˜—šœŸ˜KšœœœV˜jKšœœœœ
˜OKšœœ˜+Kšœœ˜+Kšœ˜Kšœ˜K˜—šœŸ˜KšœœœV˜jšœœœ˜"Kšœœœœ˜bKšœ˜—Kšœ˜Kšœ˜K˜—šœŸ˜šž
œ˜(šžœœœ'œ˜QKšœœ˜/Kšœœœ'˜Ešœœœ˜Kšœ
œœ˜0Kšœœ/œœ˜@Kšœ˜K˜—Kš
œ4œœœœ˜ŠKšœ,œœœ˜nK˜—Kšœœ˜Kšœœœœ˜9Kšœœ'œœ˜8Kšœ!œœ˜IKšœ$˜&Kš
œ<œœœœ˜’Kšœ-˜-Kšœ
œœ/˜Fšœœœ
˜%Kšœ>˜>Kšœ˜—Kšœ˜K˜—KšœœœV˜jKšœœ˜Kšœœ˜Kšœc˜cKšœœ˜=šœœœ˜%Kšœœœ
˜4Kšœ˜—K˜Kšœ1˜1Kšœ˜Kšœ˜Kšœ%˜%K˜—K˜K˜�—šžœœœœ%˜ršžœœ˜šœœœ˜Kšœœ"˜6Kšœœ˜Kšœ˜K˜—K˜—KšœP˜PKšœ
œœK˜aKšœœ˜Kšœœœœ˜(Kšœœ˜#Kšœœ˜$šœœ˜Kšœœœœ˜@Kšœœ$˜9Kšœœœ˜#Kšœœœ˜$Kšœœœ˜$Kšœœœ˜$Kšœœœ˜%Kšœœœ˜"Kšœœ˜$Kšœ
œ˜+Kšœœ˜-Kšœ˜Kšœ˜—Kšœ˜Kšœ˜Kšœ%˜%Kšœœ˜2š	œœ
œœ˜0Kšœ3˜3Kšœ
œ"˜7Kšœœ˜9š	œœ
œœ˜;Kšœ?˜?Kšœ)˜)Kšœ˜—Kšœœœœ˜#Kšœ#˜#Kšœ˜—Kšœœœœ˜ Kšœ˜K˜�—šž
œœœœ˜5Kšœ=™=Kšœ&˜&Kšœ$œ#˜JKšœ?˜?K˜K˜�—šžœœ˜:K˜�—šžœœœœ˜Ušžœ˜!Kšœœ˜Kšœœ˜)Kšœœ%˜EKšœ'˜'Kšœœ˜.KšœœT˜]KšœœT˜]Kšœ˜Kšœœ˜,Kšœ)˜)Kšœœ˜,Kšœ)˜)Kšœ!œ!œœ˜QKšœœ˜2Kšœœ˜2Kšœ˜šœœœ˜)Kšœ˜Kšœ˜—Kšœœ(œœ˜9K˜—Kšœœ˜K˜Kšœ ˜ Kšœ)˜)K˜K˜�——™šžœœœ@œ	˜†Kšœœ˜-Kšœ˜Kšœ˜Kšœ'˜'Kšœ'˜'Kšœ˜Kšœ>˜>šœ/œœ˜BKšœ˜Kšœ˜—K˜K˜�—šžœœ˜(šœœ
˜Kšœ&˜&Kšœ˜—K˜K˜�—šž
œœœ˜IKšœœ˜0Kšœ
œ
˜šœœ
˜šœ!œ˜/Kšœ ˜ Kšœ"˜"Kšœ˜Kšœ4˜4Kšœœ˜—Kšœœ*œ˜WKšœE˜EKšœG˜GKšœG˜GKšœ=˜=KšœJ˜Jšœ+œ˜9KšœM˜MKšœQ˜QKšœ<˜<Kšœœ˜—Kšœ˜—K˜Kšœ2˜2Kšœ ˜ šœœœ˜&Kšœ˜šœœœ˜&Kšœ˜šœ	œœ˜(Kšœ˜šœœœ˜%Kšœ˜Kšœ˜Kšœ˜Kšœ)˜)šœœ˜Kšœ˜Kšœ"˜"Kšœ.˜.Kšœ$˜$Kšœ$˜$Kšœ#˜#Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ%˜%Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ˜Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ%˜%Kšœ˜Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ%˜%Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ˜K˜—šœ	œœ˜(Kšœ˜Kšœ˜Kšœ˜Kšœ*˜*Kšœ˜Kšœ+˜+Kšœ ˜ Kšœ ˜ Kšœ"˜"Kšœ!˜!šœ
œ˜Kšœ˜Kšœ˜Kšœ˜Kšœ-˜-Kšœ$˜$Kšœ˜Kšœ-˜-Kšœ$˜$Kšœ˜—šœœ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ-˜-Kšœ$˜$Kšœ˜Kšœ-˜-Kšœ$˜$Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ"˜"šœœœ˜&Kšœ˜šœœœ˜&Kšœ˜šœ	œœ˜(Kšœ˜šœœœ˜%Kšœ˜Kšœ˜Kšœ˜Kšœ)˜)šœœ˜Kšœ˜Kšœ$˜$Kšœ.˜.Kšœ$˜$Kšœ$˜$Kšœ#˜#Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ%˜%Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ˜Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ%˜%Kšœ˜Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ%˜%Kšœ˜Kšœ*˜*Kšœ%˜%Kšœ˜K˜—šœ	œœ˜(Kšœ˜Kšœ˜Kšœ˜Kšœ*˜*Kšœ˜Kšœ+˜+Kšœ ˜ Kšœ ˜ Kšœ"˜"Kšœ!˜!šœ
œ˜Kšœ˜Kšœ˜Kšœ˜Kšœ-˜-Kšœ$˜$Kšœ˜Kšœ-˜-Kšœ$˜$Kšœ˜—šœœ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ-˜-Kšœ$˜$Kšœ˜Kšœ-˜-Kšœ$˜$Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—šœœœ˜&Kšœ˜šœœœ˜&Kšœ˜šœ	œœ˜(Kšœ˜šœ	œœ˜(Kšœ˜šœ	œœ˜&Kšœ$˜$Kšœ ˜ Kšœ˜Kšœ˜Kšœ2˜2Kšœ˜Kšœ3˜3šœ	œœ˜&Kšœ(˜(Kšœ"˜"Kšœ˜Kšœ˜Kšœ4˜4Kšœ˜Kšœ5˜5Kšœ4˜4Kšœ4˜4Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—K˜K˜�—šžœœ	œœ˜CKšœœœ˜)Kšœ
œœ˜5Kšœœœ˜'Kšœ˜Kšœ
œ%˜4K˜K˜�—šž
œœœ˜2Kšœœ
œ'˜HK˜K˜�—šžœœ˜(Kšœ/˜/Kšœ˜Kšœ
œ˜Kšœœ˜Kšœ6˜6šœœœ˜#Kšœœ˜Kšœ˜—K˜K˜�—šž	œœ7œ˜Ošœœœ˜)šœœœ˜Kšœ ˜ Kšœ˜K˜—Kšœ˜—Kšœ˜K˜K˜�—šžœœ-œ˜YKšœ˜Kšœ
œœœ ˜Ešœ˜Kšœ-˜-Kšœ/˜/Kšœ.˜.—šœœœ˜-Kšœ0œœœi˜ÅKšœR˜RKšœV˜VKšœœ˜—Kšœœ˜K˜K˜�—šœœ˜K˜�—Kšœ$™$šžœœ*œ0˜sšžœœ˜8Kšœœ˜Kšœœ˜&Kšœ2˜2Kšœ)˜)Kšœ
œ˜$Kšœœœœ˜Kšœ˜Kšœ˜Kšœœœœ
˜VKšœ˜šœœœ
˜%Kšœœ˜0Kšœ/˜/Kšœ˜Kšœ)˜)Kš
œœœœœ˜2Kšœ˜Kšœœ˜.Kšœ˜—K˜—šž	œœ˜,Kšœœ˜&Kšœœ˜Kšœ,˜,šœœœ˜ Kšœ˜Kšœœ˜Kšœœœ ˜5Kšœ˜šœ)œœ˜;Kšœœœ˜BKšœ˜—šœœœ˜Kšœ
œœ˜Kšœ˜Kšœ˜Kšœ˜Kšœœ˜šœœ˜Kšœœ˜šœ#œœ˜5Kšœœœ˜$šœ˜Kšœœ˜K˜šœœ˜Kšœ˜K˜Kšœ˜Kšœ˜—Kšœœ˜,Kšœœœ˜(Kšœ˜Kšœœ˜Kšœ˜—Kšœ˜—Kšœœœœ˜šœ˜Kšœ˜Kšœ˜Kšœœœœ˜%šœœœ˜(K˜Kšœ
œœœ˜šœœœœœœœ˜`Kšœ˜šœ
œœ˜Kšœ˜Kšœ˜K˜—šœ˜Kšœ˜Kšœ˜K˜—Kšœœ˜K˜—Kšœ˜—K˜—KšœœœœG˜oKšœ˜—Kšœ
œœœ,œœ˜NKšœ˜K˜—K˜—K˜—šžœœœ˜JKšœœ&˜1šœœœ˜Kšœœ
˜Kšœœ&œœ˜7K˜—K˜—Kšœ`˜`Kšœœ˜0Kšœ-˜-Kšœ>˜>KšœR˜RKšœ&˜&K˜K˜�—šž	œœ˜#Kšœ/˜/Kšœ
œ˜Kšœœ˜K˜K˜�—šžœœœ˜2Kšœ˜Kšœ˜Kšœœ˜šœœ˜Kšœ˜Kšœ˜Kšœœœœ˜%šœœœ˜(K˜Kšœ
œœœ˜šœœœ˜Kšœœ˜šœ
œœ˜Kšœ˜Kšœ˜K˜—šœ˜Kšœ˜Kšœ˜K˜—Kšœœ˜K˜—Kšœ˜—Kšœ˜—K˜K˜�—šžœœœœ˜?šžœœœœ˜5Kšœœ˜šœ)œœ˜;K˜Kšœ˜—Kšœœ˜š	œœ
œœ˜.K˜K˜Kšœ˜—Kšœœœœ˜K˜—Kšœœ˜3š˜Kšœœ˜Kšœœ˜šœœœ˜(K˜Kšœ
œœœ˜šœœœ˜@Kšœœ˜&Kšœ"˜"K˜—Kšœ˜—šœœ˜šœŸ˜"Kšœ˜Kšœ˜K˜—šœŸ˜)Kšœ˜Kšœœ˜.K˜—šœŸ˜Kšœœ˜5K˜Kšœ˜š	œœ
œœ˜7Kšœ,˜,Kšœ˜Kšœ˜—Kšœ˜K˜——Kšœ˜—Kšœ˜K˜�—Kšœœœ-˜FšžœœH˜\šœœœ˜.Kšœ˜šœœœ˜.Kšœ˜šœ	œœ˜0Kšœ˜šœ	œœ˜0Kšœ˜šœœ
˜$Kšœ˜šœœœ˜-Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—šœœœ˜.Kšœ˜šœœœ˜.Kšœ˜šœ	œœ˜0Kšœ˜šœœœ˜-Kšœ˜Kšœ˜Kšœ˜Kšœ"˜"Kšœ˜Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—šœœœ˜.Kšœ˜šœœœ˜.Kšœ˜šœ	œœ˜0Kšœ˜šœœœ˜-Kšœ˜Kšœ˜Kšœ˜Kšœ$˜$Kšœ˜Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜—K˜K˜�—šž
œœ˜(šžœ˜)Kšœ
œ˜K˜K˜—šž	œœ˜ šœœœ˜(Kšœœ˜0Kšœ˜Kšœœ+œœ˜<Kšœ˜—š
œœœœœœ˜KKšœ ˜ Kšœ˜—K˜—K˜ZKšœ)˜)K˜K˜�—šžœ˜&š
žœœœœœ˜MKšœœœœ	˜DK˜—Kšœœ˜&Kšœœ˜Kšœ#˜#Kšœ$˜$Kšœ$˜$Kšœ"˜"Kšœ˜K˜K˜�—šžœ˜(Kšœœ˜(Kšœœ˜(Kšœœœœ˜4šœ˜Kšœ#œœ%œ"˜•Kšœ'œœ%œ"˜™Kšœœ˜/Kšœœ˜—K˜——™Kšœœ}˜”Kšœœœœ
œœ˜Dšœœœœ™˜ÕK˜�—Kšœœ%˜9Kšœœœ1˜Xšœœœœ˜2K˜�—Kšœ"˜"Kšœ%˜%Kšœ'˜'Kšœ"˜"Kšœ%˜%Kšœ*˜*Kšœ)˜)šœ$˜$K˜�—šžœœ˜!Kšœœ
œ ˜6Kšœ&˜&šœœ˜1Kšœœ)˜DKšœ˜—šœœ˜+Kšœœœ˜=Kšœ˜—K˜K˜�—šžœœJœ
œ˜šžœ˜)Kšœœ˜&Kšœ$˜$Kšœ˜Kšœœœœ
˜VKšœ˜šœœœ˜&Kšœ˜Kšœ˜Kšœ!˜!Kšœ˜—K˜—šž
œ˜%Kšœ
œ˜Kšœ˜K˜—šž	œœ˜ šœœœ˜(Kšœ˜Kšœ ˜ šœœ˜Kšœ˜Kšœ"˜"K˜—Kšœ˜—š
œœœœœœ˜KKšœ ˜ Kšœ˜Kšœ(˜(Kšœ"˜"Kšœ˜—K˜—šžœœ5˜JKšœ!˜!Kšœ*Ÿ˜9Kšœ8˜8šœ	œ˜"Kšœ2˜2Kšœ4˜4Kšœ8˜8Kšœ/˜/Kšœœ˜—šœ	œ˜"Kšœ-˜-Kšœ0˜0Kšœœœœ˜QKšœœ˜—Kšœœ[˜dKšœ>œ ˜aK˜—šž	œœ˜-Kšœœ%˜4šœœœ˜'Kšœœœœ%˜tKšœœ"˜:Kšœœ˜7Kšœœ!˜9Kšœœ!˜9Kšœœ˜—šœœ˜2šœ*œ	˜=Kšœ%˜%Kšœ˜Kšœœ˜—šœ œ	˜3Kšœ/˜/Kšœ˜Kšœœ˜—šœ	œ	˜Kšœ/˜/Kšœ%˜%Kšœ˜Kšœ
œœœ˜QKšœœ˜—šœ
œ	˜Kšœ/˜/Kšœ%˜%šœ	œ˜Kšœ˜Kšœ˜Kšœ˜Kšœœ˜—Kšœœ˜—Kšœœ˜—Kšœ˜Kšœ˜KšœH˜HKšœJ˜Jšœ	˜šœ˜šœœ	˜Kšœœœœ˜GKšœœœœ˜BKšœœ˜—šœ˜šœ
˜
Kšœ˜KšœF˜FKšœQ˜QK˜—šœ˜Kšœ˜KšœQ˜QKšœF˜FK˜—šœ	˜	Kšœ˜KšœQ˜QKšœ ˜ K˜—šœ	˜	Kšœ˜Kšœ ˜ KšœQ˜QK˜—Kšœœ˜—K˜—šœ˜šœœ˜!Kšœœœœ˜GKšœœœœ˜BKšœœ˜—šœ˜šœ	˜	Kšœ˜KšœF˜FKšœQ˜QK˜—šœ	˜	Kšœ˜KšœQ˜QKšœF˜FK˜—šœ˜Kšœ˜KšœQ˜QKšœT˜TK˜—šœ
˜
Kšœ˜KšœT˜TKšœQ˜QK˜—Kšœœ˜K˜——šœ!œ˜6šœ
˜
Kšœ˜Kšœ9˜9KšœQ˜QK˜—šœ˜Kšœ˜KšœQ˜QKšœ9˜9K˜—šœ	˜	Kšœ˜KšœU˜UKšœ;˜;K˜—šœ	˜	Kšœ˜Kšœ;˜;KšœU˜UK˜—Kšœœ˜—šœ˜šœœ˜#Kšœ˜KšœU˜UKšœ'˜'Kšœ˜—šœ˜Kšœ˜Kšœ'˜'KšœU˜UK˜—K˜—šœ	˜	šœœ˜!Kšœ˜KšœQ˜QKšœ%˜%Kšœ˜—šœ˜Kšœ˜Kšœ%˜%KšœQ˜QK˜—K˜—šœ˜Kšœ˜KšœQ˜QKšœU˜UKšœ˜—šœ˜Kšœ˜KšœU˜UKšœQ˜QKšœ˜—Kšœœ˜—šœ˜Kšœœ+˜GKšœE˜EKšœ9˜9Kšœœ+˜Gšœ˜Kšœ&˜&Kšœ$˜$Kšœ˜—KšœœG˜PKšœBœ˜aKšœ@œ˜]K˜—Kšœ˜—šžœœœœ˜]KšœT˜TKšœV˜Všœ˜šœ˜KšœRœœœ˜„Kšœ;˜;Kšœ;˜;šœœ˜'Kšœ,˜,Kšœ2˜2Kšœ˜—šœ˜Kšœ2˜2Kšœ,˜,K˜—K˜—Kšœv˜vKšœx˜xšœ˜Kšœm˜mKšœT˜TK˜—šœ˜Kšœm˜mKšœT˜TK˜—Kšœœ˜—K˜—Kšœœœ˜Kšœœ˜0Kšœœ˜4Kšœ7˜7Kšœ%˜%šœ˜š
žœœœœ
œ˜NKšœ.˜.šœ˜KšœHœŸ&˜všœœ˜6šœ
˜
Kšœ˜Kšœ<˜<K˜—šœ˜Kšœ<˜<Kšœ˜K˜—Kšœœ˜—Kšœœ˜—K˜—šœ/œœ˜BKšœ˜Kšœœ'˜/šœ&œœ˜8Kšœœ&˜,Kšœœ˜Kšœœ
˜K˜Kšœœœ
˜Kšœœ(˜/Kšœœ(˜/Kšœœ˜Kšœ˜Kšœ˜Kšœ˜šœ
œœœ
œœœ˜8Kšœ9˜9K˜—šœ˜Kšœ%œ(˜QKšœœ4˜=KšœBœœ˜[Kšœ@œœ˜WK˜—Kšœ˜—Kšœ˜—K˜—Kšœ	œœ˜#K˜K˜�—šžœœsœœ˜¤šœœ˜2Kšœ
˜
Kšœ˜Kšœ
˜
Kšœ˜Kšœ˜—Kšœœ˜!Kšœ˜Kšœœ˜šœœœ#œœ˜AK˜Kšœ˜—Kšœœ˜'Kšœ˜šœœœ˜!Kšœ˜K˜Kšœ˜—Kšœ/˜/K˜K˜�—Kšœœœœ
˜)šœ
œœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ"˜"K˜�—šžœœ0˜DKšœœœ˜WKšœ˜Kšœœ˜šœ&œœ˜8K˜Kšœ˜—Kšœœ˜šœœœ˜#Kšœ!˜!šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜Kšœ˜—Kšœ*˜*K˜K˜�—šžœœœ-˜LKšœœ˜Kšœœ˜Kšœœ9˜NKšœ˜Kšœ&˜&KšœR˜RK˜K˜�——™K˜Kšœ˜Kšœ^˜^Kšœb˜bšœ`˜`K˜�——Kšœ˜K™�—�…—����åB��(ž�