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��(ž�