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 chipY0 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 minorY0 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 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 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 left, to.chip.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. PSoftHdwFlat.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šœœ˜šœ œœ ˜*šœœ˜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šœ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šœœ+œœ˜œ ˜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šœ<˜