DIRECTORY Build, Core, CoreClasses, CoreFlat, CoreOps, CoreProperties, Flow, Globals, HashTable, IO, Model, Real, Rope, WriteCapa; BuildImpl: CEDAR PROGRAM IMPORTS CoreClasses, CoreFlat, CoreOps, CoreProperties, Flow, Globals, HashTable, IO, Model, Real, Rope, WriteCapa EXPORTS Build = BEGIN OPEN Build; CoreAttributes: TYPE = LIST OF CoreAttributeRec; CoreAttributeRec: TYPE = RECORD [ port: CoreClasses.TransistorPort, attribute: Rope.ROPE]; FlatCellProc: TYPE = PROC [cell: Core.CellType, target: CoreFlat.FlatCellTypeRec _ CoreFlat.allFlatCells, flatCell: CoreFlat.FlatCellTypeRec _ [], instance: CoreClasses.CellInstance _ NIL, parent: Core.CellType _ NIL, flatParent: CoreFlat.FlatCellTypeRec _ [], data: REF ANY _ NIL, wireName: HashTable.Table]; Units: PUBLIC REAL _ 2.0; totalNodes: INT _ 0; totalFets: ARRAY[0..Model.maxFetTypes) OF INT _ ALL[0]; debug: PUBLIC BOOL _ FALSE; EOF: ERROR = CODE; Terminal: TYPE = {gate, source, drain}; BuildNode: PUBLIC PROC[flatWire: CoreFlat.FlatWire, globalVars: Globals.GlobalVars] RETURNS [Globals.Node] = { new: Globals.Node; val: HashTable.Value; found: BOOLEAN; [found: found, value: val] _ HashTable.Fetch[globalVars.nodeTable, flatWire]; IF found THEN RETURN[NARROW[val]]; new _ NEW[Globals.NodeRec]; new.flatWire _ flatWire; new.cap _ WriteCapa.GetRootCap[flatWire.wire]; new.res _ 0; new.hiTime _ -1.0; new.loTime _ -1.0; new.firstPointer _ NIL; new.always0 _ FALSE; new.always1 _ FALSE; new.input _ FALSE; new.precharged _ FALSE; new.dynamic _ FALSE; new.ratioError _ FALSE; new.watched _ FALSE; [] _ HashTable.Store[table: globalVars.nodeTable, key: flatWire, value: new]; totalNodes _ totalNodes + 1; RETURN [new]; }; BuildPointer: PROC[node: Globals.Node, fet: Globals.Fet] = { p: Globals.Pointer _ NEW[Globals.PointerRec _ [fet, node.firstPointer]]; node.firstPointer _ p; }; BuildFet: PROC[gate, source, drain: CoreFlat.FlatWire, fetData: REF ANY, l, w: REAL, globalVars: Globals.GlobalVars] RETURNS [fet: Globals.Fet] = { f2: Globals.Fet; ptr: Globals.Pointer; type: REF INTEGER _ NARROW[fetData]; fet _ NEW[Globals.FetRec]; fet.type _ type^; fet.gate _ BuildNode[gate, globalVars]; fet.source _ BuildNode[source, globalVars]; fet.drain _ BuildNode[drain, globalVars]; fet.area _ l*w; fet.aspect _ l/w; IF fet.type = Model.fetNDep THEN { IF fet.source = globalVars.VddNode THEN { IF fet.drain = fet.gate THEN fet.type _ Model.fetNLoad ELSE fet.type _ Model.fetNSuper; } ELSE IF fet.drain = globalVars.VddNode THEN { IF fet.source = fet.gate THEN fet.type _ Model.fetNLoad ELSE fet.type _ Model.fetNSuper; }; }; IF (fet.source # globalVars.VddNode) AND (fet.source # globalVars.GroundNode) THEN ptr _ fet.source.firstPointer ELSE IF (fet.drain # globalVars.VddNode) AND (fet.drain # globalVars.GroundNode) THEN ptr _ fet.drain.firstPointer ELSE IF (fet.gate # globalVars.VddNode) AND (fet.gate # globalVars.GroundNode) THEN ptr _ fet.gate.firstPointer ELSE ptr _ NIL; WHILE ptr # NIL DO f2 _ ptr.fet; IF (f2.gate = fet.gate) AND (f2.drain = fet.drain) AND (f2.source = fet.source) AND (f2.type = fet.type) THEN { f2.area _ f2.area + fet.area; f2.aspect _ 1.0/(1.0/f2.aspect + 1.0/fet.aspect); fet _ f2; EXIT; }; ptr _ ptr.next; ENDLOOP; IF ptr = NIL THEN { BuildPointer[fet.gate, fet]; IF fet.drain # fet.gate THEN BuildPointer[fet.drain, fet]; IF (fet.source # fet.gate) AND (fet.source # fet.drain) THEN BuildPointer[fet.source, fet]; fet.on0 _ Model.TypeTable[fet.type].on0; fet.on1 _ Model.TypeTable[fet.type].on1; fet.onAlways _ Model.TypeTable[fet.type].onAlways; }; totalFets[fet.type] _ totalFets[fet.type] + 1; RETURN; }; BuildAtt: PROC[fet: Globals.Fet, terminal: Terminal, string: Rope.ROPE] RETURNS [Rope.ROPE] = { pos, index: INT; pos _ Rope.Run[string, 0, "Crystal:", 0, FALSE]; IF pos < 7 THEN { pos _ Rope.Run[string, 0, "Cr:", 0, FALSE]; IF pos < 2 THEN RETURN[NIL]; }; string _ Rope.Replace[base: string, start: 0, len: pos, with: NIL]; IF terminal = gate THEN { index _ Model.NameToIndex[string]; IF index < 0 THEN RETURN [IO.PutFR["unknown transistor type %s", IO.rope[string]]]; fet.type _ index; RETURN [NIL]; }; IF Rope.Equal[string, "In", FALSE] OR Rope.Equal[string, "IN", FALSE] THEN { IF terminal = source THEN fet.noDrainInfo _ TRUE ELSE fet.noSourceInfo _ TRUE; } ELSE IF Rope.Equal[string, "Out", FALSE] OR Rope.Equal[string, "OUT", FALSE] THEN { IF terminal = source THEN fet.noSourceInfo _ TRUE ELSE fet.noDrainInfo _ TRUE; } ELSE Flow.Build[fet: fet, name: string, source: terminal=source]; RETURN [NIL]; }; Stats: PUBLIC PROC[] = { total: INT _ 0; IO.PutF[Globals.StdOut, "Total number of nodes: %d.\n", IO.int[totalNodes]]; FOR i:INT IN [0..Model.maxFetTypes) DO IF totalFets[i] = 0 THEN LOOP; IO.PutF[Globals.StdOut, "Number of %s transistors: %d.\n", IO.rope[Model.TypeTable[i].name], IO.int[totalFets[i]]]; total _ total + totalFets[i]; ENDLOOP; IO.PutF[Globals.StdOut, "Total number of transistors: %d.\n", IO.int[total]]; }; NodeFromRope: PUBLIC PROC [id: Rope.ROPE, globalVars: Globals.GlobalVars] RETURNS [node: Globals.Node] ~ { flatWire: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec _ CoreFlat.ParseWirePath[globalVars.rootCell, id]]; node _ NARROW[HashTable.Fetch[globalVars.nodeTable, flatWire].value]; }; RopeFromNode: PUBLIC PROC [node: Globals.Node, globalVars: Globals.GlobalVars] RETURNS [id: Rope.ROPE] ~ { id _ CoreFlat.WirePathRope[globalVars.rootCell, node.flatWire^]; }; NetFromCore: PUBLIC PROC[ct: Core.CellType] RETURNS [globalVars: Globals.GlobalVars] = { InsertPublic: PROC[wire: Core.Wire] = { InsertWire[wire, CoreFlat.rootCellType, globalVars, wireName, public]; }; wireName: HashTable.Table _ HashTable.Create[]; IO.PutF[Globals.StdOut, "\nConverting cell %g . . .", IO.rope[CoreOps.GetCellTypeName[ct]]]; globalVars _ NEW[Globals.GlobalVarsRec]; globalVars.rootCell _ ct; globalVars.nodeTable _ HashTable.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash]; CoreOps.VisitRootAtomics[root: ct.public, eachWire: InsertPublic]; Flatten[cell: ct, data: globalVars, wireName: wireName]; globalVars.GroundNode _ NodeFromRope[GndName, globalVars]; globalVars.GroundNode.input _ TRUE; globalVars.GroundNode.always0 _ TRUE; globalVars.VddNode _ NodeFromRope[VddName, globalVars]; globalVars.VddNode.input _ TRUE; globalVars.VddNode.always1 _ TRUE; IO.PutRope[Globals.StdOut, " \nFinished\n"]; }; InsertWire: PROC [wire: Core.Wire, flatCell: CoreFlat.FlatCellTypeRec, globalVars: Globals.GlobalVars, wireName: HashTable.Table, wireRoot: CoreFlat.WireRoot _ internal] = { node: Globals.Node; flatWire: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; flatWire.flatCell _ flatCell; flatWire.wireRoot _ wireRoot; flatWire.wire _ wire; node _ BuildNode[flatWire, globalVars]; [] _ HashTable.Store[table: wireName, key: wire, value: flatWire]; }; Flatten: FlatCellProc = { globalVars: Globals.GlobalVars _ NARROW[data]; SELECT cell.class FROM CoreClasses.transistorCellClass => { gateWire: CoreFlat.FlatWire _ NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.gate]]].value]; ch1Wire: CoreFlat.FlatWire _ NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.ch1]]].value]; ch2Wire: CoreFlat.FlatWire _ NARROW[HashTable.Fetch[table: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.ch2]]].value]; tran: CoreClasses.Transistor _ NARROW[cell.data]; fet: Globals.Fet _ BuildFet[gateWire, ch1Wire, ch2Wire, tranTab[tran.type], Real.Float[tran.length], Real.Float[tran.width], globalVars]; atts: CoreAttributes _ NARROW[CoreProperties.GetCellTypeProp[from: cell, prop: crystalAttProp]]; FOR att: CoreAttributes _ atts, att.rest UNTIL att=NIL DO error: Rope.ROPE _ BuildAtt[fet, (SELECT att.first.port FROM gate => gate, ch1 => source, ch2 => drain, ENDCASE => ERROR), Rope.Cat["Cry: ", att.first.attribute]]; IF error#NIL THEN IO.PutF[Globals.StdOut, "Attribute error: %s.\n", IO.rope[error]]; ENDLOOP; }; CoreClasses.recordCellClass => { MarkAtomicPublic: PROC[wire: Core.Wire] = { [] _ HashTable.Store[table: publics, key: wire, value: $Public]; }; InsertInternal: PROC[wire: Core.Wire] = { IF NOT HashTable.Fetch[table: publics, key: wire].found THEN { InsertWire[wire, flatCell, globalVars, wireName]; }; }; rct: CoreClasses.RecordCellType; publics: HashTable.Table _ HashTable.Create[cell.public.size+1]; rct _ NARROW[cell.data]; CoreOps.VisitRootAtomics[root: cell.public, eachWire: MarkAtomicPublic]; CoreOps.VisitRootAtomics[root: rct.internal, eachWire: InsertInternal]; NextCellType[cell, target, flatCell, instance, parent, flatParent, data, wireName, Flatten] }; ENDCASE => { NextCellType[cell, target, flatCell, instance, parent, flatParent, data, wireName, Flatten] }; }; NextCellType: PROC [cell: Core.CellType, target: CoreFlat.FlatCellTypeRec, flatCell: CoreFlat.FlatCellTypeRec, instance: CoreClasses.CellInstance, parent: Core.CellType, flatParent: CoreFlat.FlatCellTypeRec, data: REF ANY, wireName: HashTable.Table, proc: FlatCellProc] = { BindCellType: CoreFlat.UnboundFlatCellProc = { BindPublicToActual: CoreOps.EachWirePairProc = { IF publicWire.size=0 THEN { flatWire: CoreFlat.FlatWire _ NARROW[HashTable.Fetch[table: wireName, key: actualWire].value]; [] _ HashTable.Store[table: wireName, key: publicWire, value: flatWire]; }; }; IF CoreOps.VisitBinding[actual: IF instance=NIL OR instance.type#cell THEN previous.public ELSE instance.actual, public: cell.public, eachWirePair: BindPublicToActual] THEN ERROR; proc[cell, target, flatCell, instance, parent, flatParent, data, wireName]; }; previous: Core.CellType _ cell; CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, parent, flatParent, data, BindCellType]; }; SetAtt: PUBLIC PROC [transistor: Core.CellType, port: CoreClasses.TransistorPort, attribute: Core.ROPE] RETURNS [sameTransistor: Core.CellType] = { currentAtts: CoreAttributes _ NARROW[CoreProperties.GetCellTypeProp[from: transistor, prop: crystalAttProp]]; IF transistor.class#CoreClasses.transistorCellClass THEN ERROR; FOR att: CoreAttributes _ currentAtts, att.rest UNTIL att=NIL DO IF att.first.port=port THEN { att.first.attribute _ attribute; EXIT; }; REPEAT FINISHED => { currentAtts _ CONS[[port, attribute], currentAtts]; CoreProperties.PutCellTypeProp[on: transistor, prop: crystalAttProp, value: currentAtts]; }; ENDLOOP; sameTransistor _ transistor; }; GndName: Rope.ROPE _ "public.Gnd"; VddName: Rope.ROPE _ "public.Vdd"; crystalAttProp: ATOM = CoreProperties.RegisterProperty[prop: $CrystalAtt]; tranTab: ARRAY CoreClasses.TransistorType OF REF INTEGER; FOR i: INTEGER IN [0..Model.maxFetTypes) DO ttype: Model.TType _ Model.TypeTable[i]; IF ttype = NIL THEN EXIT; SELECT TRUE FROM Rope.Equal[ttype.name, "NETran"] => tranTab[nE] _ NEW[INTEGER _ i]; Rope.Equal[ttype.name, "PETran"] => tranTab[pE] _ NEW[INTEGER _ i]; Rope.Equal[ttype.name, "NDTran"] => tranTab[nD] _ NEW[INTEGER _ i]; ENDCASE; ENDLOOP; END. "ξBuildImpl.mesa Ousterhout, February 7, 1984 1:22 pm Barth, February 17, 1986 5:23:45 pm PST Christian LeCocq December 29, 1986 5:55:35 pm PST Bertrand Serlet October 18, 1986 9:00:17 pm PDT This file contains the implementation of the package that builds up a circuit network. Statistics gathered while reading in files. The following type is used to distinguish between terminals of a transistor. This procedure sees if a given node exists, and makes a new one if necessary. A pointer is returned to the new or existing node. Find the hash entry for the node, and then see if it contains a node pointer. If not, it is a new entry, so we have to create the node. entry _ Hash.Find[globalVars.nodeTable, name]; IF entry.clientData # NIL THEN RETURN[NARROW[entry.clientData]]; new.name _ name; entry.clientData _ new; This procedure links a transistor into the list of those that connect to a node. This procedure builds a transistor data structure and links it into the network under construction. The fetData parameter must NARROW into the type of the transistor. A pointer to the new transistor is saved in lastFet. cap: REAL; fet.x _ x; fet.y _ y; Detect loads and super buffers. If the gate doesn't connect to either source or drain, then add its gate-channel capacitance onto the gate. Also add in source and drain overlap capacitance. IF (fet.gate # fet.source) AND (fet.gate # fet.drain) THEN fet.gate.cap _ fet.gate.cap + (fet.area * Model.TypeTable[fet.type].cPerArea); cap _ w * Model.TypeTable[fet.type].cPerWidth; IF (fet.gate # fet.drain) THEN { fet.drain.cap _ fet.drain.cap + cap; fet.gate.cap _ fet.gate.cap + cap; }; IF fet.gate # fet.source THEN { fet.source.cap _ fet.source.cap + cap; fet.gate.cap _ fet.gate.cap + cap; }; See if there is already a transistor of the same type connecting between the same three nodes. If so, just lump the two transistors into a single bigger transistor (this handles pads with multiple driving transistors in parallel). If not, then create pointers to the transistor from each of the nodes it connects to. This procedure does all of the work of making a new attribute. It's called by separate procedures to handle Thyme and Sim formats. The string must be of the form "Cr:goo" or "Crystal:goo"; otherwise, this attribute is ignored (to make this work with Thyme, the colons are optional). The attribute may be used to set the transistor's type, modify its flags, or allocate flow control records. If all goes well, NIL is returned. Otherwise the return value is an error string. If the attribute is attached to the transistor gate, it is the name of the transistor's type. Look up the name and set the type. If the attribute is "In" or "Out", then just set a flag in the transistor. Otherwise, create special flow control information. InOutGuess: PUBLIC PROC [ct: Core.CellType, r1, r2, r3, r4, r5: Rope.ROPE, globalVars: Globals.GlobalVars] ~ { GuessNode: PROC[wire: Core.Wire] = { node: Globals.Node; IF wire.size=0 THEN { name: Rope.ROPE _ CoreOps.GetFullWireNames[rc.public, wire].first; IF Rope.Equal[name, r1] THEN RETURN; IF Rope.Equal[name, r2] THEN RETURN; IF Rope.Equal[name, r3] THEN RETURN; IF Rope.Equal[name, r4] THEN RETURN; IF Rope.Equal[name, r5] THEN RETURN; node _ BuildNode[name, globalVars]; IF node=globalVars.VddNode OR node=globalVars.GroundNode THEN RETURN; node.input _ TRUE; FOR iFet: Globals.Pointer _ node.firstPointer, iFet.next UNTIL iFet=NIL DO IF iFet.fet.source= node OR iFet.fet.drain=node THEN { node.input _ FALSE; EXIT; }; ENDLOOP; IF node.input THEN IO.PutF[Globals.StdOut, "\ninput: %g", IO.rope[name]] ELSE { node.output _ TRUE; IO.PutF[Globals.StdOut, "\noutput: %g", IO.rope[name]]; }; }; }; rc: Core.CellType; FOR rc _ ct, CoreOps.Recast[rc] UNTIL rc.class.recast = NIL DO ENDLOOP; CoreOps.VisitRootAtomics[root: rc.public, eachWire: GuessNode]; }; NetFromCore: PUBLIC PROC[ct: Core.CellType] RETURNS [globalVars: Globals.GlobalVars]= { Flatten: PROC [name: Rope.ROPE, ct: Core.CellType] = { IF Globals.Stop^ THEN RETURN; IF ct.class=CoreClasses.transistorCellClass THEN { gateName: Rope.ROPE _ NARROW[HashTable.Fetch[table: wireName, key: ct.public[ORD[CoreClasses.TransistorPort.gate]]].value]; ch1Name: Rope.ROPE _ NARROW[HashTable.Fetch[table: wireName, key: ct.public[ORD[CoreClasses.TransistorPort.ch1]]].value]; ch2Name: Rope.ROPE _ NARROW[HashTable.Fetch[table: wireName, key: ct.public[ORD[CoreClasses.TransistorPort.ch2]]].value]; tran: CoreClasses.Transistor _ NARROW[ct.data]; fet: Globals.Fet _ NARROW[BuildFet[gateName, ch1Name, ch2Name, tranTab[tran.type], Real.Float[tran.length], Real.Float[tran.width], globalVars]]; atts: CoreAttributes _ NARROW[CoreProperties.GetCellTypeProp[from: ct, prop: crystalAttProp]]; FOR att: CoreAttributes _ atts, att.rest UNTIL att=NIL DO error: Rope.ROPE _ BuildAtt[fet, (SELECT att.first.port FROM gate => gate, ch1 => source, ch2 => drain, ENDCASE => ERROR), Rope.Cat["Cry: ", att.first.attribute]]; IF error#NIL THEN IO.PutF[Globals.StdOut, "Attribute error: %s.\n", IO.rope[error]]; ENDLOOP; IF debug THEN IO.PutF[Globals.StdOut, "\nFet: %g, %g, %g", IO.rope[gateName], IO.rope[ch1Name], IO.rope[ch2Name]]; } ELSE { MarkAtomicPublic: PROC[wire: Core.Wire] = { [] _ HashTable.Store[table: publics, key: wire, value: $Public]; }; InsertInternal: PROC[wire: Core.Wire] = { IF NOT HashTable.Fetch[table: publics, key: wire].found THEN { thisWireName: Rope.ROPE _ Rope.Cat[name, "/", CoreOps.GetFullWireNames[rct.internal, wire].first]; InsertWire[wire, thisWireName]; }; }; BindPublicToActual: CoreOps.EachWirePairProc = { PROC [actualWire, publicWire: Wire] IF publicWire.size=0 THEN { name: Rope.ROPE _ NARROW[HashTable.Fetch[table: wireName, key: actualWire].value]; [] _ HashTable.Store[table: wireName, key: publicWire, value: name]; }; }; rc: Core.CellType; rct: CoreClasses.RecordCellType; publics: HashTable.Table _ HashTable.Create[]; FOR rc _ ct, CoreOps.Recast[rc] UNTIL rc.class.recast = NIL DO ENDLOOP; rct _ NARROW[rc.data]; CoreOps.VisitRootAtomics[root: rc.public, eachWire: MarkAtomicPublic]; CoreOps.VisitRootAtomics[root: rct.internal, eachWire: InsertInternal]; FOR in: NAT IN [0..rct.size) DO instanceName: Rope.ROPE _ CoreClasses.GetCellInstanceName[rct[in]]; IF instanceName=NIL THEN instanceName _ IO.PutFR["%g[%g]", IO.rope[CoreOps.GetCellTypeName[rct[in].type]], IO.int[in]]; IF CoreOps.VisitBinding[actual: rct[in].actual, public: rct[in].type.public, eachWirePair: BindPublicToActual] THEN ERROR; Flatten[name: Rope.Cat[name, ".", instanceName], ct: rct[in].type]; ENDLOOP; }; }; InsertPublic: CoreOps.EachWireProc = { IF wire.size=0 THEN { name: Rope.ROPE _ CoreOps.GetFullWireNames[rc.public, wire].first; IO.PutF[Globals.StdOut, "\nExternal: %g", IO.rope[name]]; InsertWire[wire, name]; }; }; InsertWire: PROC [wire: Core.Wire, name: Rope.ROPE] = { node: Globals.Node _ BuildNode[name, globalVars]; IF debug THEN IO.PutF[Globals.StdOut, "\nNode: %g", IO.rope[name]]; [] _ HashTable.Store[table: wireName, key: wire, value: name]; node.cap _ WriteCapa.GetRootCap[wire]; IF node.cap#0 THEN capNodes _ capNodes + 1; }; entry: Hash.Entry; tranTab: ARRAY CoreClasses.TransistorType OF REF INTEGER; wireName: HashTable.Table _ HashTable.Create[]; rc: Core.CellType; IO.PutF[Globals.StdOut, "\nConverting Core data structure for cell type %g . . .", IO.rope[CoreOps.GetCellTypeName[ct]]]; FOR rc _ ct, CoreOps.Recast[rc] UNTIL rc.class.recast = NIL DO ENDLOOP; globalVars _ NEW[Globals.GlobalVarsRec]; globalVars.nodeTable _ Hash.NewTable[]; globalVars.GroundNode _ BuildNode["GND", globalVars]; globalVars.GroundNode.input _ TRUE; globalVars.GroundNode.always0 _ TRUE; entry _ Hash.Find[globalVars.nodeTable, "Gnd"]; entry.clientData _ globalVars.GroundNode; globalVars.VddNode _ BuildNode["VDD", globalVars]; globalVars.VddNode.input _ TRUE; globalVars.VddNode.always1 _ TRUE; entry _ Hash.Find[globalVars.nodeTable, "Vdd"]; entry.clientData _ globalVars.VddNode; FOR i: INTEGER IN [0..Model.maxFetTypes) DO ttype: Model.TType _ Model.TypeTable[i]; IF ttype = NIL THEN EXIT; SELECT TRUE FROM Rope.Equal[ttype.name, "NETran"] => tranTab[nE] _ NEW[INTEGER _ i]; Rope.Equal[ttype.name, "PETran"] => tranTab[pE] _ NEW[INTEGER _ i]; Rope.Equal[ttype.name, "NDTran"] => tranTab[nD] _ NEW[INTEGER _ i]; ENDCASE; ENDLOOP; IF CoreOps.VisitWire[wire: rc.public, eachWire: InsertPublic] THEN ERROR; Flatten[name: NIL, ct: ct]; IO.PutRope[Globals.StdOut, " \nFinished\n: "]; }; GetCap: PUBLIC PROC [wire: Core.Wire] RETURNS [cap: pfs] = { capRef: REF pfs _ NARROW[CoreProperties.GetWireProp[from: wire, prop: wireCapProp]]; IF capRef#NIL THEN { capNodes _ capNodes + 1; cap _ capRef^; } ELSE cap _ 0.0; }; SetCap: PUBLIC PROC [wire: Core.Wire, cap: pfs] RETURNS [sameWire: Core.Wire] = { CoreProperties.PutWireProp[on: wire, prop: wireCapProp, value: NEW[pfs _ cap]]; sameWire _ wire; }; PROC [actualWire, publicWire: Wire] Κ€˜šœ™Jšœ$™$Icode™'K™1K™/J˜JšœV™VJ˜—J™šΟk ˜ Jšœ˜Jšœ˜Jšœ ˜ J˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ —J˜šΟn œœ˜š˜JšœHœ˜j—š˜Jšœ˜—Jšœœ˜Kšœœœœ˜0šœœœ˜!Kšœ!˜!Kšœœ˜—KšœœœŸœœ3œœœ˜΅Jšœœœ˜J˜Jšœ,™,Jšœ œ˜Jš œ œœœœ˜7Jšœœœœ˜Jšœœœ˜J™MJšœ œ˜'J˜š ž œœœœ œ˜nJšœ‡™‡Jšœ˜J˜Jšœœ˜Jšœˆ™ˆJ˜J™.Jšœœœœ™@JšœM˜MJšœœœœ˜"J˜Jšœœ˜J™Jšœ˜Jšœ.˜.J˜ J˜J˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœ œ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜J™JšœM˜MJ˜J˜Jšœ˜ J˜—J˜šž œœ*˜œ ˜LJšœŠ™Ššœœ˜J˜"šœ ˜Jšœœ%œ˜A—J˜Jšœœ˜ J˜—J˜Jšœ™J˜š œœœœœ˜LJš œœœœœ˜NJšœ˜—š œœœœœœ˜SJš œœœœœ˜NJšœ˜—Jšœ=˜AJ˜Jšœœ˜ J˜J˜—J˜šžœœœ˜Jšœœ˜J˜Jšœ6œ˜Lšœœœ˜&Jšœœœ˜Jšœ9œ œ˜sJ˜Jšœ˜—Jšœ<œ ˜MJ˜—J˜šž œœœ.œ#™nK™šž œœ™$Kšœ™šœ ™Kšœ œ3™BKšœœœ™$Kšœœœ™$Kšœœœ™$Kšœœœ™$Kšœœœ™$Kšœ#™#Kšœœœœ™EKšœ œ™šœ6œœ™Jšœœœœœœœœœ™6Kšœ œ™Kšœ™K™—Kšœ™—šœ œ%œ ™HKšœ™Kšœœ™Kšœ&œ ™7K™—K™—Kšœ™K™—Kšœ™Kš œœœœœ™GKšœ?™?K™K™—J˜šž œœœœ$™WJ™šžœœ œ™6Jšœ  ™šœ*œ™2Jšœœœ1œ+™{Jšœœœ1œ*™yJšœœœ1œ*™yJšœœ ™/Kšœœx™‘KšœœA™^šœ&œœ™9Kš œ œœœ,œœ+™£Kš œœœœ0œ™TKšœ™—Kš œœœ+œœœ™rJ™—šœ™K™šžœœ™+Kšœ@™@Kšœ™K™—šžœœ™)šœœ2œ™>KšœœK™bKšœ™K™—Kšœ™K™—šžœ™0Kšœ™#šœœ™Kšœ œœ:™RKšœD™DK™—Kšœ™—K™Kšœ™Kšœ ™ J™.Kš œœœœœ™GKšœœ ™KšœF™FKšœG™Gšœœœ™Kšœœ,™CKš œœœœœ.œ ™wKšœmœœ™zKšœC™C—Kšœ™J™—J™—J™šž œ™&šœ ™Kšœ œ3™BKšœ(œ ™9Kšœ™K™—Kšœ™K™—šž œœœ™7Kšœ1™1Kšœœœ$œ ™CKšœ>™>Kšœ&™&Kšœ œ™+Kšœ™K™—J™Jš œ œœœœ™9J™/Kšœ™KšœQœ$™yKš œœœœœ™GJšœ œ™(Kšœ'™'Jšœ5™5Jšœœ™#Jšœ œ™%Jšœ/™/Jšœ)™)J™Jšœ2™2Jšœœ™ Jšœœ™"Jšœ/™/Jšœ&™&J™šœœœ™+J™(Jšœ œœœ™šœœ™Jšœ2œœ™CJšœ2œœ™CJšœ2œœ™CJšœ™—Jšœ™—Kšœ<œœ™IJšœœ ™Kšœ,™.J™K™—šžœ œœ™Jšœ1˜1J˜—Jšœ˜J˜—Jšœ ˜ Jšœ@˜@Jšœœ ˜JšœH˜HJšœG˜GKšœ[˜[J˜—šœ˜ Kšœ[˜[Jšœ˜——Jšœ˜J˜—šž œœΔœœ4˜‘K˜šž œ"˜.šžœ˜0Jšœ™#šœœ˜Jšœœ:˜^JšœH˜HJ˜—Jšœ˜—Jšœœ œœœœIœœ˜³KšœK˜KK˜K˜—K˜Kšœg˜gKšœ˜K˜—š žœœœOœœ$˜“KšœœI˜mJšœ2œœ˜?šœ-œœ˜@šœœ˜Kšœ ˜ Kšœ˜K˜—šœœ˜Kšœœ!˜3KšœY˜YK˜—Kšœ˜—Kšœ˜Kšœ˜J˜—Jšœœ˜"Jšœœ˜"Kšœœ6˜JJš œ œœœœ˜9šœœœ˜+J˜(Jšœ œœœ˜šœœ˜Jšœ2œœ˜CJšœ2œœ˜CJšœ2œœ˜CJšœ˜—Jšœ˜—Jšœ˜——…—*Β`T