DIRECTORY Basics, BasicTime, BitOps, BrineIO, Core, CoreClasses, CoreFlat, CoreIO, CoreOps, CoreProperties, IO, Ports, Process, RefTab, Rope, Rosemary, SafeStorage, SymTab, TerminalIO; RosemaryImpl: CEDAR PROGRAM IMPORTS Basics, BasicTime, BitOps, BrineIO, CoreClasses, CoreFlat, CoreIO, CoreOps, CoreProperties, IO, Ports, Process, RefTab, Rope, SafeStorage, SymTab, TerminalIO EXPORTS Rosemary = BEGIN OPEN Rosemary; sizeHackEnable: BOOL _ FALSE; -- converts transistor instance name into transistor conductivity sizeHackType: TYPE = Ports.Drive[driveWeak .. driveStrong]; sizeHackNames: ARRAY sizeHackType OF ROPE _ ["driveWeak", "driveMediumWeak", "drive", "driveMediumStrong", "driveStrong"]; ROPE: TYPE = Core.ROPE; WordAsBits: TYPE = PACKED ARRAY [0..16) OF BOOL; DWordAsBits: TYPE = PACKED ARRAY [0..32) OF BOOL; roseBehaveProp: ATOM = CoreProperties.RegisterProperty[prop: $RoseBehave]; roseWireDataProp: ATOM = CoreIO.RegisterProperty[prop: CoreProperties.RegisterProperty[prop: $RoseWireData, properties: CoreProperties.Props[[CoreProperties.propPrint, NEW[CoreProperties.PropPrintProc _ RoseWireDataPrint]]]], write: RoseWireDataWrite, read: RoseWireDataRead]; RoseWireDataPrint: CoreProperties.PropPrintProc = { roseWireData: RoseWireData _ NARROW[val]; CoreOps.PrintIndent[indent, to]; IO.PutF[to, "%g: ", IO.atom[roseWireDataProp]]; IO.PutRope[to, Ports.levelNames[roseWireData.value]]; IO.PutRope[to, " "]; IO.PutRope[to, Ports.driveNames[roseWireData.size]]; IO.PutRope[to, IF roseWireData.memory THEN " T" ELSE " F"]; }; RoseWireDataWrite: CoreIO.PropWriteProc = { roseWireData: RoseWireData _ NARROW[value]; BrineIO.WriteID[stream, Ports.levelNames[roseWireData.value]]; BrineIO.WriteID[stream, Ports.driveNames[roseWireData.size]]; BrineIO.WriteBool[stream, roseWireData.memory]; }; RoseWireDataRead: CoreIO.PropReadProc = { roseWireData: RoseWireData _ NEW[RoseWireDataRec]; roseWireData.value _ Ports.FindLevel[BrineIO.ReadID[stream]]; roseWireData.size _ Ports.FindDrive[BrineIO.ReadID[stream]]; roseWireData.memory _ BrineIO.ReadBool[stream]; value _ roseWireData; }; roseFixedWireProp: ATOM = CoreIO.RegisterProperty[prop: CoreProperties.RegisterProperty[prop: $RoseFixedWire, properties: CoreProperties.Props[[CoreProperties.propPrint, NEW[CoreProperties.PropPrintProc _ RoseFixedWirePrint]]]], write: RoseFixedWireWrite, read: RoseFixedWireRead]; RoseFixedWirePrint: CoreProperties.PropPrintProc = { lev: REF Ports.Level _ NARROW[val]; CoreOps.PrintIndent[indent, to]; IO.PutF[to, "%g: ", IO.atom[roseFixedWireProp]]; IO.PutRope[to, Ports.levelNames[lev^]]; }; RoseFixedWireWrite: CoreIO.PropWriteProc = { level: REF Ports.Level _ NARROW[value]; BrineIO.WriteID[stream, Ports.levelNames[level^]]; }; RoseFixedWireRead: CoreIO.PropReadProc = { level: REF Ports.Level _ NEW[Ports.Level]; level^ _ Ports.FindLevel[BrineIO.ReadID[stream]]; value _ level; }; roseTransistorSizeProp: ATOM = CoreIO.RegisterProperty[prop: CoreProperties.RegisterProperty[prop: $RoseTransistorSize, properties: CoreProperties.Props[[CoreProperties.propPrint, NEW[CoreProperties.PropPrintProc _ RoseTransistorSizePrint]]]], write: RoseTransistorSizeWrite, read: RoseTransistorSizeRead]; RoseTransistorSizePrint: CoreProperties.PropPrintProc = { size: REF Ports.Drive _ NARROW[val]; CoreOps.PrintIndent[indent, to]; IO.PutF[to, "%g: ", IO.atom[roseTransistorSizeProp]]; IO.PutRope[to, Ports.driveNames[size^]]; }; RoseTransistorSizeWrite: CoreIO.PropWriteProc = { size: REF Ports.Drive _ NARROW[value]; BrineIO.WriteID[stream, Ports.driveNames[size^]]; }; RoseTransistorSizeRead: CoreIO.PropReadProc = { size: REF Ports.Drive _ NEW[Ports.Drive]; size^ _ Ports.FindDrive[BrineIO.ReadID[stream]]; value _ size; }; roseClassTable: SymTab.Ref _ SymTab.Create[]; Stop: PUBLIC SIGNAL [msg: ROPE _ NIL, data: REF ANY _ NIL, reason: ATOM _ $Client] = CODE; BindCellType: PUBLIC PROC [cellType: Core.CellType, roseClassName: ROPE] RETURNS [sameCellType: Core.CellType] = { CoreProperties.PutCellTypeProp[on: cellType, prop: roseBehaveProp, value: roseClassName]; sameCellType _ cellType; }; BindCellClass: PUBLIC PROC [cellClass: Core.CellClass, roseClassName: ROPE] RETURNS [sameCellClass: Core.CellClass] = { CoreProperties.PutCellClassProp[on: cellClass, prop: roseBehaveProp, value: roseClassName]; sameCellClass _ cellClass; }; Register: PUBLIC PROC [roseClassName: ROPE, init: InitProc _ NIL, evalSimple: EvalProc _ NIL, copy: StateCopyProc _ NIL, scheduleIfClockEval: BOOL _ FALSE] RETURNS [sameRoseClassName: ROPE] = { rct: RoseCellType _ NARROW[SymTab.Fetch[x: roseClassTable, key: roseClassName].val]; IF rct#NIL THEN { rct.init _ init; rct.evalSimple _ evalSimple; rct.copy _ copy; rct.scheduleIfClockEval _ scheduleIfClockEval; } ELSE IF NOT SymTab.Insert[x: roseClassTable, key: roseClassName, val: NEW[RoseCellTypeRec _ [init: init, evalSimple: evalSimple, copy: copy, scheduleIfClockEval: scheduleIfClockEval]]] THEN ERROR; sameRoseClassName _ roseClassName; }; SetFixedWire: PUBLIC PROC [wire: Core.Wire, level: Ports.Level _ L] RETURNS [sameWire: Core.Wire] = { CoreProperties.PutWireProp[on: wire, prop: roseFixedWireProp, value: NEW[Ports.Level _ level]]; sameWire _ wire; }; SetWire: PUBLIC PROC [wire: Core.Wire, level: Ports.Level _ L, size: WireSize _ charge, memory: BOOL _ FALSE] RETURNS [sameWire: Core.Wire] = { CoreProperties.PutWireProp[on: wire, prop: roseWireDataProp, value: NEW[RoseWireDataRec _ [level, size, memory]]]; sameWire _ wire; }; SetTransistorCellTypeSize: PUBLIC PROC [transistor: Core.CellType, size: TransistorSize] RETURNS [sameTransistor: Core.CellType] = { CoreProperties.PutCellTypeProp[on: transistor, prop: roseTransistorSizeProp, value: NEW[Ports.Drive _ size]]; sameTransistor _ transistor; }; SetTransistorInstanceSize: PUBLIC PROC [transistor: CoreClasses.CellInstance, size: TransistorSize] RETURNS [sameTransistor: CoreClasses.CellInstance] = { CoreProperties.PutCellInstanceProp[on: transistor, prop: roseTransistorSizeProp, value: NEW[Ports.Drive _ size]]; sameTransistor _ transistor; }; Instantiate: PUBLIC PROC [cellType: Core.CellType, testPort: Ports.Port, cutSet: CoreFlat.CutSet _ NIL, statePoints: NAT _ 0] RETURNS [simulation: Simulation] = { ComputeInDegree: PROC [wire: Core.Wire, bindings: RefTab.Ref _ NIL] = { key: Core.Wire; wireData: WireData; [key, wireData] _ FindBind[wire, bindings]; IF wireData=NIL THEN { wireData _ NEW[WireDataRec]; IF NOT RefTab.Insert[x: wireTable, key: key, val: wireData] THEN ERROR; }; IF wireData.valid THEN wireData.multiInPointers _ TRUE ELSE { wireData.valid _ TRUE; wireData.multiInPointers _ FALSE; wireData.connections _ 0; wireData.channels _ 0; wireData.gates _ 0; wireData.portLeaf _ FALSE; wireData.boolPort _ FALSE; wireData.allocated _ FALSE; FOR sub: NAT IN [0..wire.size) DO ComputeInDegree[wire[sub], bindings]; ENDLOOP; }; }; MarkPortLeavesCountConnections: PROC [cellType: Core.CellType, bindings: RefTab.Ref, wire: Core.Wire, checkPort: BOOL, type: Ports.LevelType, visited: RefTab.Ref] = { wireData: WireData _ FindPublicBind[wire, bindings]; IF NOT RefTab.Fetch[x: visited, key: wire].found THEN { IF NOT RefTab.Insert[x: visited, key: wire, val: $Visited] THEN ERROR; wireData.connections _ wireData.connections + 1; IF checkPort THEN { type _ Ports.WirePortType[cellType, wire].levelType; IF type # composite THEN { wireData.portLeaf _ TRUE; checkPort _ FALSE; }; }; FOR sub: NAT IN [0..wire.size) DO MarkPortLeavesCountConnections[cellType, bindings, wire[sub], checkPort, type, visited]; ENDLOOP; }; IF type=b OR type=bs OR type=c OR type=lc OR type=q THEN wireData.boolPort _ TRUE; }; FindPublicBind: PROC [wire: Core.Wire, bindings: RefTab.Ref] RETURNS [wireData: WireData] = { IF bindings=NIL THEN wireData _ NARROW[RefTab.Fetch[x: wireTable, key: wire].val] ELSE { flatWire: CoreFlat.FlatWire _ NARROW[RefTab.Fetch[x: bindings, key: wire].val]; IF flatWire=NIL THEN ERROR; wireData _ NARROW[RefTab.Fetch[x: wireTable, key: flatWire.wire].val]; }; }; FindBind: PROC [wire: Core.Wire, bindings: RefTab.Ref] RETURNS [leftUpper: Core.Wire, wireData: WireData] = { flatWire: CoreFlat.FlatWire _ IF bindings=NIL THEN NIL ELSE NARROW[RefTab.Fetch[x: bindings, key: wire].val]; leftUpper _ IF flatWire=NIL THEN wire ELSE flatWire.wire; wireData _ NARROW[RefTab.Fetch[x: wireTable, key: leftUpper].val]; }; GatherDataAllocateWires: CoreFlat.BoundFlatCellProc = { Process.CheckForAbort[]; SELECT TRUE FROM cell.class=CoreClasses.transistorCellClass => { public: Core.Wire _ cell.public; wireData: WireData _ FindPublicBind[public[gate], bindings]; wireData.gates _ wireData.gates + 1; wireData.portLeaf _ TRUE; wireData _ FindPublicBind[public[ch1], bindings]; wireData.channels _ wireData.channels + 1; wireData.portLeaf _ TRUE; wireData _ FindPublicBind[public[ch2], bindings]; wireData.channels _ wireData.channels + 1; wireData.portLeaf _ TRUE; }; CoreFlat.CutSetMemberResolved[flatCell, instance, cell, cutSet] => { public: Core.Wire _ cell.public; visited: RefTab.Ref _ RefTab.Create[]; FOR i: NAT IN [0..public.size) DO MarkPortLeavesCountConnections[cell, bindings, public[i], TRUE, composite, visited] ENDLOOP; }; cell.class=CoreClasses.recordCellClass => { ActualInDegree: PROC [wire: Core.Wire] = { wireData: WireData _ FindBind[wire, bindings].wireData; IF wireData=NIL THEN FOR sub: NAT IN [0..wire.size) DO ActualInDegree[wire[sub]]; ENDLOOP ELSE wireData.multiInPointers _ TRUE; }; cellTypeRCT: CoreClasses.RecordCellType _ NARROW[cell.data]; internal: Core.Wire _ cellTypeRCT.internal; FOR i:NAT IN [0..internal.size) DO ComputeInDegree[internal[i], bindings]; ENDLOOP; FOR i:NAT IN [0..cellTypeRCT.size) DO actual: Core.Wire _ cellTypeRCT[i].actual; FOR a:NAT IN [0..actual.size) DO ActualInDegree[actual[a]]; ENDLOOP; ENDLOOP; CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, GatherDataAllocateWires]; FOR i: NAT IN [0..internal.size) DO [] _ AllocateRoseWires[internal[i], flatCell, bindings]; ENDLOOP; }; ENDCASE => CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, GatherDataAllocateWires]; Process.CheckForAbort[]; }; AllocateRoseWires: PROC [wire: Core.Wire, flatCell: CoreFlat.FlatCellTypeRec, bindings: RefTab.Ref, publicWireRoots: BOOL _ FALSE] RETURNS [public: BOOL _ FALSE, allocated: BOOL _ FALSE] = { flatWire: CoreFlat.FlatWire _ IF bindings=NIL THEN NIL ELSE NARROW[RefTab.Fetch[x: bindings, key: wire].val]; IF NOT (public _ flatWire#NIL) THEN { wireData: WireData _ NARROW[RefTab.Fetch[x: wireTable, key: wire].val]; IF wireData.allocated THEN allocated _ TRUE ELSE { somePublic: BOOL _ FALSE; FOR sub: NAT IN [0..wire.size) DO subPublic, subAllocated: BOOL; [subPublic, subAllocated] _ AllocateRoseWires[wire[sub], flatCell, bindings, publicWireRoots]; allocated _ allocated OR subAllocated; somePublic _ somePublic OR subPublic; ENDLOOP; IF allocated OR somePublic THEN { FOR sub: NAT IN [0..wire.size) DO subFlat: CoreFlat.FlatWire _ IF bindings=NIL THEN NIL ELSE NARROW[RefTab.Fetch[x: bindings, key: wire[sub]].val]; IF subFlat=NIL THEN { subWireData: WireData _ NARROW[RefTab.Fetch[x: wireTable, key: wire[sub]].val]; IF NOT subWireData.allocated THEN AllocateWire[wire[sub], subWireData, flatCell, publicWireRoots]; }; ENDLOOP; wireData.allocated _ TRUE; allocated _ TRUE; } ELSE { IF wireData.multiInPointers OR wireData.portLeaf THEN { AllocateWire[wire, wireData, flatCell, publicWireRoots]; allocated _ TRUE; }; }; }; wireData.valid _ FALSE; }; }; AllocateWire: PROC [wire: Core.Wire, wireData: WireData, flatCell: CoreFlat.FlatCellTypeRec, publicWireRoots: BOOL] = { roseWire: RoseWire; wireSize: NAT; fixed: BOOL; [fixed, wireSize, roseWire] _ InitWire[wire, publicWireRoots]; IF wireData.connections>0 THEN { roseWire.connections _ NEW[FieldSeq[wireData.connections]]; FOR i: CARDINAL IN [0..roseWire.connections.size) DO roseWire.connections[i] _ NIL; ENDLOOP; }; IF wireSize=1 AND NOT fixed THEN { roseWire.channels _ AllocateTransistorPointers[wireData.channels]; roseWire.notOffChannels _ AllocateTransistorPointers[wireData.channels]; roseWire.gates _ AllocateTransistorPointers[wireData.gates]; }; roseWire.wire.flatCell _ flatCell; IF NOT RefTab.Insert[x: simulation.coreToRoseWires, key: roseWire, val: roseWire] THEN ERROR; maxRoseWireSize _ MAX[maxRoseWireSize, wireSize]; IF wireData.boolPort THEN simulation.roseBoolWires _ CONS[roseWire, simulation.roseBoolWires]; wireData.allocated _ TRUE; }; AllocateTransistorPointers: PROC [count: CARDINAL] RETURNS [transistors: RoseTransistors _ NIL] = { IF count>0 THEN { transistors _ NEW[RoseTransistorSeq[count]]; FOR i: CARDINAL IN [0..transistors.size) DO transistors[i] _ NIL; ENDLOOP; }; }; ComputeBindings: PROC [bindings: RefTab.Ref, port: Ports.Port, wire: Core.Wire, binds: PortBindings, firstFreeBinding: CARDINAL, instance: RoseCellInstance _ NIL, visited: RefTab.Ref] RETURNS [newFirstFreeBinding: CARDINAL] = { newFirstFreeBinding _ firstFreeBinding; IF port.levelType=composite THEN { FOR subPort: NAT IN [0..port.size) DO newFirstFreeBinding _ ComputeBindings[bindings, port[subPort], wire[subPort], binds, newFirstFreeBinding, instance, visited]; ENDLOOP; } ELSE { IF NOT RefTab.Fetch[x: visited, key: port].found THEN { portBinding: PortBinding _ NEW[PortBindingRec _ [ clientPort: port, currentDrive: port.d, instance: instance]]; portBinding.fields _ NEW[FieldSeq[CountFields[bindings: bindings, wire: wire, bound: RefTab.Create[]]]]; [] _ ComputeFields[bindings: bindings, wire: wire, portBinding: portBinding, valueStart: 0, bound: RefTab.Create[], firstFreeField: 0]; binds[newFirstFreeBinding] _ portBinding; newFirstFreeBinding _ newFirstFreeBinding + 1; IF NOT RefTab.Insert[x: visited, key: port, val: $Visited] THEN ERROR; }; }; }; CountFields: PROC [bindings: RefTab.Ref, wire: Core.Wire, bound: RefTab.Ref] RETURNS [fieldCount: CARDINAL _ 0] = { IF LookUpRoseWire[wire, bindings]=NIL THEN { FOR subWire: NAT IN [0..wire.size) DO fieldCount _ fieldCount + CountFields[bindings, wire[subWire], bound]; ENDLOOP; } ELSE { IF NOT RefTab.Fetch[x: bound, key: wire].found THEN { fieldCount _ 1; IF NOT RefTab.Insert[x: bound, key: wire, val: $Bound] THEN ERROR; }; }; }; ComputeFields: PROC [bindings: RefTab.Ref, wire: Core.Wire, portBinding: PortBinding, valueStart: NAT, bound: RefTab.Ref, firstFreeField: CARDINAL] RETURNS [newFirstFreeField: CARDINAL, newValueStart: NAT] = { roseWire: RoseWire _ LookUpRoseWire[wire, bindings]; newValueStart _ valueStart; newFirstFreeField _ firstFreeField; IF roseWire = NIL THEN { FOR subWire: NAT IN [0..wire.size) DO [newFirstFreeField, newValueStart] _ ComputeFields[bindings, wire[subWire], portBinding, newValueStart, bound, newFirstFreeField]; ENDLOOP; } ELSE { IF NOT RefTab.Fetch[x: bound, key: wire].found THEN { size: NAT _ IF roseWire.currentValue=NIL THEN 1 ELSE roseWire.currentValue.size; field: Field _ NEW[FieldRec _ [ portBinding: portBinding, portStartBit: valueStart, roseWire: roseWire, currentValue: AllocateLevelSequence[size]]]; IF portBinding.clientPort.driveType=separate THEN field.currentDrive _ AllocateDriveSequence[size, portBinding.clientPort.ds]; portBinding.fields[firstFreeField] _ field; newFirstFreeField _ newFirstFreeField + 1; newValueStart _ newValueStart + field.currentValue.size; roseWire.connections[roseWire.firstFreeConnection] _ field; roseWire.firstFreeConnection _ roseWire.firstFreeConnection + 1; IF NOT RefTab.Insert[x: bound, key: wire, val: $Bound] THEN ERROR; }; }; }; AllocateInstances: CoreFlat.BoundFlatCellProc = { Process.CheckForAbort[]; SELECT TRUE FROM cell.class=CoreClasses.transistorCellClass => { InsertTransistor: PROC [transistors: RoseTransistors] = { IF transistors#NIL THEN FOR t: NAT IN [0..transistors.size) DO IF transistors[t]=NIL THEN { transistors[t] _ roseTransistor; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; }; public: Core.Wire _ cell.public; coreTransistor: CoreClasses.Transistor _ NARROW[cell.data]; roseTransistor: RoseTransistor _ NEW[RoseTransistorRec]; transistorSizeRef: REF Ports.Drive _ NARROW[CoreProperties.GetCellInstanceProp[from: instance, prop: roseTransistorSizeProp]]; roseTransistor.gate _ LookUpRoseWire[public[gate], bindings]; InsertTransistor[roseTransistor.gate.gates]; roseTransistor.ch1 _ LookUpRoseWire[public[ch1], bindings]; InsertTransistor[roseTransistor.ch1.channels]; roseTransistor.ch2 _ LookUpRoseWire[public[ch2], bindings]; InsertTransistor[roseTransistor.ch2.channels]; IF transistorSizeRef=NIL THEN transistorSizeRef _ NARROW[CoreProperties.GetCellTypeProp[from: cell, prop: roseTransistorSizeProp]]; IF transistorSizeRef#NIL THEN roseTransistor.conductivity _ transistorSizeRef^; IF sizeHackEnable THEN { name: ROPE _ CoreClasses.GetCellInstanceName[instance]; IF name#NIL THEN FOR drv: Ports.Drive IN Ports.Drive DO IF Rope.Equal[Ports.driveNames[drv], name] THEN { roseTransistor.conductivity _ drv; EXIT; }; REPEAT FINISHED => FOR drv: Ports.Drive IN sizeHackType DO IF Rope.Equal[sizeHackNames[drv], name] THEN { roseTransistor.conductivity _ drv; EXIT; }; ENDLOOP; ENDLOOP; }; roseTransistor.type _ coreTransistor.type; roseTransistor.instance _ flatCell; transistorCount _ transistorCount + 1; }; CoreFlat.CutSetMemberResolved[flatCell, instance, cell, cutSet] => { public: Core.Wire _ cell.public; roseInstance: RoseCellInstance _ NEW[RoseCellInstanceRec]; roseInstance.roseCellType _ FindRoseCellTypeOrComplain[cell]; roseInstance.publicPort _ Ports.CreatePort[cell]; roseInstance.portBindings _ NEW[PortBindingSeq[Ports.PortLeaves[ roseInstance.publicPort]]]; IF roseInstance.portBindings.size#ComputeBindings[bindings: bindings, port: roseInstance.publicPort, wire: public, binds: roseInstance.portBindings, firstFreeBinding: 0, instance: roseInstance, visited: RefTab.Create[]] THEN ERROR; IF roseInstance.roseCellType.init#NIL THEN roseInstance.state _ roseInstance.roseCellType.init[cellType: cell, p: roseInstance.publicPort].stateAny; roseInstance.instance _ flatCell; IF NOT RefTab.Insert[x: simulation.coreToRoseInstances, key: roseInstance, val: roseInstance] THEN ERROR; instanceCount _ instanceCount + 1; }; ENDCASE => CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, AllocateInstances]; Process.CheckForAbort[]; }; LookUpRoseWire: PROC [wire: Core.Wire, bindings: RefTab.Ref] RETURNS [roseWire: RoseWire] = { IF bindings=NIL THEN { wireKey.flatCell _ CoreFlat.rootCellType; wireKey.wire _ wire; roseWire _ NARROW[RefTab.Fetch[x: simulation.coreToRoseWires, key: wireKey].val]; } ELSE { leftUpper: CoreFlat.FlatWire _ NARROW[RefTab.Fetch[x: bindings, key: wire].val]; roseWire _ NARROW[RefTab.Fetch[x: simulation.coreToRoseWires, key: leftUpper].val]; }; }; ComputeMaxVicinity: RefTab.EachPairAction = { roseWire: RoseWire _ NARROW[val]; IF roseWire.wireDrive=infinite THEN UpdateReaders[simulation, roseWire, NIL] ELSE IF NOT roseWire.mark THEN maxVicinity _ MAX[maxVicinity, CountVicinity[roseWire]]; }; CountVicinity: PROC [wire: RoseWire, currentCount: NAT _ 0] RETURNS [newCount: NAT] = { channels: RoseTransistors _ wire.channels; wire.mark _ TRUE; newCount _ currentCount + 1; IF channels#NIL THEN FOR t: CARDINAL IN [0..channels.size) DO tran: RoseTransistor _ channels[t]; otherWire: RoseWire _ tran.ch1; IF otherWire=wire THEN otherWire _ tran.ch2; IF otherWire.wireDrive#infinite AND NOT otherWire.mark THEN newCount _ CountVicinity[otherWire, newCount]; ENDLOOP; }; WireData: TYPE = REF WireDataRec; WireDataRec: TYPE = RECORD [ valid: BOOL _ FALSE, multiInPointers: BOOL _ FALSE, connections: CARDINAL _ 0, channels: CARDINAL _ 0, gates: CARDINAL _ 0, portLeaf: BOOL _ FALSE, boolPort: BOOL _ FALSE, allocated: BOOL _ FALSE]; time: BasicTime.GMT _ BasicTime.Now[]; transistorCount: INT _ 0; instanceCount: INT _ 0; gate: NAT = CoreClasses.TransistorPort.gate.ORD; ch1: NAT = CoreClasses.TransistorPort.ch1.ORD; ch2: NAT = CoreClasses.TransistorPort.ch2.ORD; maxRoseWireSize: NAT _ 0; maxVicinity: NAT _ 0; wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; wireTable: RefTab.Ref _ RefTab.Create[mod: 1019]; priority: Process.Priority _ Process.GetPriority[]; Process.SetPriority[Process.priorityBackground]; TerminalIO.PutF["Rosemary expanding cell %g\n", IO.rope[CoreOps.GetCellTypeName[cellType]]]; simulation _ NewSimulation[]; simulation.cellType _ cellType; simulation.testPort _ testPort; simulation.publicBindings _ NEW[PortBindingSeq[Ports.PortLeaves[testPort]]]; simulation.coreToRoseWires _ RefTab.Create[mod: 1019, equal: RoseWireEqual, hash: RoseWireHash]; simulation.coreToRoseInstances _ RefTab.Create[mod: 1019, equal: RoseInstanceEqual, hash: RoseInstanceHash]; simulation.coreToRoseValues _ RefTab.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash]; { public: Core.Wire _ cellType.public; visited: RefTab.Ref _ RefTab.Create[]; FOR i: NAT IN [0..public.size) DO ComputeInDegree[public[i]]; ENDLOOP; FOR i: NAT IN [0..public.size) DO MarkPortLeavesCountConnections[cellType, NIL, public[i], TRUE, composite, visited]; ENDLOOP; GatherDataAllocateWires[cellType]; FOR i: NAT IN [0..public.size) DO [] _ AllocateRoseWires[public[i], CoreFlat.rootCellType, NIL, TRUE]; ENDLOOP; }; IF simulation.publicBindings.size#ComputeBindings[bindings: NIL, port: testPort, wire: cellType.public, binds: simulation.publicBindings, firstFreeBinding: 0, visited: RefTab.Create[]] THEN ERROR; AllocateInstances[cellType]; simulation.scratchValue _ NEW[Ports.LevelSequenceRec[maxRoseWireSize]]; simulation.scratchDrive _ NEW[Ports.DriveSequenceRec[maxRoseWireSize]]; [] _ RefTab.Pairs[x: simulation.coreToRoseWires, action: ComputeMaxVicinity]; FOR strength: Ports.Drive IN Ports.Drive DO simulation.vicinityByStrength[strength].wires _ NEW[RoseWireSeq[maxVicinity]]; ENDLOOP; AllocateStatePoints[simulation, statePoints]; EstablishInvariants[simulation]; Process.SetPriority[priority]; PrintPeriod[IO.PutFR["Rosemary expanded %g transistors and %g instances in", IO.int[transistorCount], IO.int[instanceCount]], time, BasicTime.Now[]]; }; PrintPeriod: PUBLIC PROC [prefix: Rope.ROPE, from, to: BasicTime.GMT] = { period: BasicTime.UnpackedPeriod _ BasicTime.UnpackPeriod[BasicTime.Period[from, to]]; TerminalIO.PutRope[prefix]; TerminalIO.PutF[" %g hours", IO.int[period.hours]]; TerminalIO.PutF[" %g minutes", IO.int[period.minutes]]; TerminalIO.PutF[" %g seconds", IO.int[period.seconds]]; TerminalIO.PutRope["\n"]; IF period.negative THEN ERROR; }; InitWire: PROC [coreWire: Core.Wire, publicWireRoots: BOOL] RETURNS [fixed: BOOL, wireSize: NAT, roseWire: RoseWire] = { FetchValue: PROC [wire: Core.Wire] RETURNS [wireDrive: Ports.Drive _ charge, wireLevel: Ports.Level _ L, memory: BOOL _ FALSE] = { wireData: RoseWireData _ NARROW[CoreProperties.GetWireProp[from: coreWire, prop: roseWireDataProp]]; wireFixedRef: REF Ports.Level _ NARROW[CoreProperties.GetWireProp[from: coreWire, prop: roseFixedWireProp]]; fixed _ wireFixedRef#NIL; IF wireData#NIL THEN { wireDrive _ wireData.size; wireLevel _ wireData.value; memory _ wireData.memory; }; IF fixed THEN { wireDrive _ infinite; wireLevel _ wireFixedRef^ }; }; GetValue: PROC [wire: Core.Wire] = { roseWire.currentValue[bit] _ FetchValue[wire].wireLevel; bit _ bit + 1; }; bit: NAT _ 0; roseWire _ NEW[RoseWireRec]; wireSize _ CoreOps.WireBits[coreWire]; IF wireSize>1 THEN { roseWire.currentValue _ AllocateLevelSequence[wireSize]; CoreOps.VisitRootAtomics[coreWire, GetValue]; } ELSE { [roseWire.wireDrive, roseWire.wireLevel, roseWire.memory] _ FetchValue[coreWire]; roseWire.switchDrive _ roseWire.wireDrive; }; roseWire.wire.wire _ coreWire; roseWire.wire.wireRoot _ IF publicWireRoots THEN public ELSE internal; }; EstablishInvariants: PROC [simulation: Simulation] = { Instance: RefTab.EachPairAction = { roseInstance: RoseCellInstance _ NARROW[val]; CleanUp[simulation: simulation, bindings: roseInstance.portBindings, allowUpdate: FALSE, updateProc: NIL]; IF roseInstance.nextNeedEval=NIL THEN { roseInstance.nextNeedEval _ simulation.instanceNeedEval; simulation.instanceNeedEval _ roseInstance; }; }; Wire: RefTab.EachPairAction = { roseWire: RoseWire _ NARROW[val]; roseWire.mark _ FALSE; IF roseWire.connections#NIL THEN RecomputeValue[simulation: simulation, wire: roseWire, forceReaderUpdate: TRUE, updateProc: NIL]; Perturb[simulation, roseWire]; IF roseWire.channels#NIL THEN { roseWire.validNotOffChannels _ 0; FOR t: CARDINAL IN [0..roseWire.channels.size) DO tran: RoseTransistor _ roseWire.channels[t]; IF TranOn[tran, tran.gate.wireLevel]#off THEN { roseWire.notOffChannels[roseWire.validNotOffChannels] _ tran; roseWire.validNotOffChannels _ roseWire.validNotOffChannels + 1; }; ENDLOOP; }; }; CleanUp[simulation: simulation, bindings: simulation.publicBindings, allowUpdate: FALSE, updateProc: NIL]; [] _ RefTab.Pairs[x: simulation.coreToRoseInstances, action: Instance]; [] _ RefTab.Pairs[x: simulation.coreToRoseWires, action: Wire]; }; FindRoseCellTypeOrComplain: PROC [cellType: Core.CellType] RETURNS [roseCellType: RoseCellType] = { roseCellType _ FindRoseCellType[cellType]; IF roseCellType=NIL THEN ERROR Stop[msg: Rope.Cat["Couldn't find behaviour proc for cell type:", CoreOps.GetCellTypeName[cellType]], data: cellType]; }; FindRoseCellType: PROC [cellType: Core.CellType] RETURNS [roseCellType: RoseCellType] = { roseClassName: ROPE _ NARROW[CoreProperties.GetCellTypeProp[from: cellType, prop: roseBehaveProp]]; IF roseClassName=NIL THEN roseClassName _ NARROW[CoreProperties.GetCellClassProp[from: cellType.class, prop: roseBehaveProp]]; IF roseClassName=NIL THEN roseClassName _ CoreOps.GetCellTypeName[cellType]; roseCellType _ NARROW[SymTab.Fetch[x: roseClassTable, key: roseClassName].val]; }; AllocateLevelSequence: PROC [count: NAT] RETURNS [ls: Ports.LevelSequence] = { ls _ NEW[Ports.LevelSequenceRec[count]]; FOR bit: NAT IN [0..count) DO ls[bit] _ L; ENDLOOP; }; AllocateDriveSequence: PROC [size: NAT, initDrive: Ports.DriveSequence] RETURNS [drives: Ports.DriveSequence] = { drives _ NEW[Ports.DriveSequenceRec[size]]; FOR bit: NAT IN [0..size) DO drives[bit] _ initDrive[bit]; ENDLOOP; }; Initialize: PUBLIC PROC [simulation: Simulation, steady: BOOL _ TRUE, updateCellProc: UpdateCellProc _ NIL] = { SetWire: RefTab.EachPairAction = { level: Ports.Level _ IF steady THEN L ELSE X; roseWire: RoseWire _ NARROW[val]; IF roseWire.wireDrive=infinite THEN RETURN; IF roseWire.currentValue=NIL THEN roseWire.wireLevel _ level ELSE FOR bit: NAT IN [0..roseWire.currentValue.size) DO roseWire.currentValue[bit] _ level; ENDLOOP; }; SetState: RefTab.EachPairAction = { roseInstance: RoseCellInstance _ NARROW[val]; cellType: Core.CellType _ CoreFlat.ResolveFlatCellType[simulation.cellType, roseInstance.instance].cellType; stateValue: Ports.LevelSequence; Ports.RenewPort[cellType: cellType, port: roseInstance.publicPort]; IF roseInstance.roseCellType.init#NIL THEN { [roseInstance.state, stateValue] _ roseInstance.roseCellType.init[cellType, roseInstance.publicPort, roseInstance.state, steady]; IF updateCellProc#NIL THEN updateCellProc[roseInstance, stateValue]; }; }; simulation.mosSimTime _ 0; [] _ RefTab.Pairs[x: simulation.coreToRoseWires, action: SetWire]; [] _ RefTab.Pairs[x: simulation.coreToRoseInstances, action: SetState]; EstablishInvariants[simulation]; }; SettleToTest: PUBLIC PROC [simulation: Simulation, flatCell: CoreFlat.FlatCellType, test: Ports.Port] = { roseInstance: RoseCellInstance _ NARROW[RefTab.Fetch[x: simulation.coreToRoseInstances, key: flatCell].val]; IF roseInstance=NIL THEN ERROR -- wrong procedure ELSE { SetDrive: Ports.EachPortPairProc = { IF onePort.levelType#composite THEN { IF onePort.d#none THEN anotherPort.d _ expect ELSE { binding: PortBinding; someForce: BOOL _ FALSE; someNotForce: BOOL _ FALSE; FOR bind: NAT IN [0..settledPortBindings.size) DO binding _ settledPortBindings[bind]; IF binding.clientPort=onePort THEN EXIT; REPEAT FINISHED => ERROR; ENDLOOP; FOR fieldIndex: NAT IN [0..binding.fields.size) DO roseWire: RoseWire _ binding.fields[fieldIndex].roseWire; fieldForce: BOOL _ FALSE; IF roseWire.currentValue=NIL THEN { IF roseWire.switchDrive>=force THEN fieldForce _ TRUE; } ELSE { connections: Fields _ roseWire.connections; FOR connectionIndex: NAT IN [0..connections.size) DO IF connections[connectionIndex].portBinding.currentDrive >= force THEN { fieldForce _ TRUE; EXIT; }; ENDLOOP; }; someForce _ someForce OR fieldForce; someNotForce _ someNotForce OR NOT fieldForce; ENDLOOP; IF someForce AND someNotForce THEN ERROR; anotherPort.d _ IF someForce THEN force ELSE none; }; }; }; settled: Ports.Port _ roseInstance.publicPort; settledPortBindings: PortBindings _ roseInstance.portBindings; Ports.CopyPortValue[from: settled, to: test]; IF Ports.VisitPortPair[onePort: settled, anotherPort: test, eachPortPair: SetDrive] THEN ERROR; }; }; Settle: PUBLIC PROC [simulation: Simulation, updateProc: UpdateProc _ NIL, memory: BOOL _ TRUE, clockEval: BOOL _ FALSE, updateCellProc: UpdateCellProc _ NIL] ~ { priority: Process.Priority _ Process.GetPriority[]; Process.SetPriority[Process.priorityBackground]; { ENABLE UNWIND => Process.SetPriority[priority]; CleanUp[simulation: simulation, bindings: simulation.publicBindings, updateProc: updateProc]; IF NOT clockEval THEN UNTIL simulation.instanceNeedEvalWhenNotClockEval=NIL DO instance: RoseCellInstance _ simulation.instanceNeedEvalWhenNotClockEval; simulation.instanceNeedEvalWhenNotClockEval _ instance.nextNeedEvalWhenNotClockEval; instance.nextNeedEvalWhenNotClockEval _ NIL; IF instance.nextNeedEval=NIL THEN { instance.nextNeedEval _ simulation.instanceNeedEval; simulation.instanceNeedEval _ instance; }; ENDLOOP; UNTIL simulation.instanceNeedEval=NIL AND simulation.perturbed=NIL DO UNTIL simulation.instanceNeedEval=NIL DO instance: RoseCellInstance _ simulation.instanceNeedEval; stateValue: Ports.LevelSequence; simulation.instanceNeedEval _ instance.nextNeedEval; instance.nextNeedEval _ NIL; stateValue _ instance.roseCellType.evalSimple[p: instance.publicPort, stateAny: instance.state, clockEval: clockEval]; IF updateCellProc#NIL THEN updateCellProc[instance, stateValue]; IF clockEval AND instance.roseCellType.scheduleIfClockEval AND instance.nextNeedEvalWhenNotClockEval=NIL THEN { instance.nextNeedEvalWhenNotClockEval _ simulation.instanceNeedEvalWhenNotClockEval; simulation.instanceNeedEvalWhenNotClockEval _ instance; }; CleanUp[simulation: simulation, bindings: instance.portBindings, updateProc: updateProc]; Process.CheckForAbort[]; ENDLOOP; simulation.mosSimTime _ simulation.mosSimTime+1; -- curent step number UpdatePerturbed[simulation: simulation, updateProc: updateProc, memory: memory]; Process.CheckForAbort[]; ENDLOOP; { noMore: BOOL _ FALSE; FOR roseWires: LIST OF RoseWire _ simulation.roseBoolWires, roseWires.rest UNTIL roseWires=NIL DO roseWire: RoseWire _ roseWires.first; CheckLevel: PROC [level: Ports.Level] = { IF level=X THEN SIGNAL Stop["Wire with bool port settled to an X", NEW[CoreFlat.FlatWireRec _ roseWire.wire], $BoolWireHasX]; }; IF roseWire.currentValue=NIL THEN CheckLevel[roseWire.wireLevel] ELSE FOR bit: CARDINAL IN [0..roseWire.currentValue.size) DO CheckLevel[roseWire.currentValue[bit]]; IF noMore THEN EXIT; ENDLOOP; IF noMore THEN EXIT; ENDLOOP; }; }; Process.SetPriority[priority]; }; CleanUp: PROC [simulation: Simulation, bindings: PortBindings, allowUpdate: BOOL _ TRUE, updateProc: UpdateProc] = { FOR binds: CARDINAL IN [0..bindings.size) DO bind: PortBinding _ bindings[binds]; client: Ports.Port _ bind.clientPort; changeDrive: BOOL _ bind.currentDrive#client.d; IF changeDrive THEN bind.currentDrive _ client.d; SELECT client.levelType FROM l, b => { field: Field _ bind.fields[0]; changeValue: BOOL _ FALSE; clientLevel: Ports.Level _ IF client.levelType=l THEN client.l ELSE IF client.b THEN H ELSE L; IF field.currentValue[0]#clientLevel THEN { changeValue _ TRUE; field.currentValue[0] _ clientLevel; }; UpdateReader[simulation, field]; IF allowUpdate AND (changeDrive OR changeValue) THEN RecomputeValue[simulation, field.roseWire, FALSE, updateProc]; }; ls, bs, c, lc, q => { clientDrive: Ports.DriveSequence _ client.ds; separateDrive: BOOL _ client.driveType=separate; IF separateDrive THEN changeDrive _ FALSE; FOR fields: CARDINAL IN [0..bind.fields.size) DO field: Field _ bind.fields[fields]; fieldValue: Ports.LevelSequence _ field.currentValue; changeValue: BOOL _ FALSE; fieldStart: NAT _ field.portStartBit+client.fieldStart; fieldDrive: Ports.DriveSequence _ field.currentDrive; FOR bit: NAT IN [0..fieldValue.size) DO thisBit: NAT _ bit+fieldStart; clientLevel: Ports.Level _ SELECT client.levelType FROM ls => client.ls[thisBit], bs => IF client.bs[thisBit] THEN H ELSE L, c => IF LOOPHOLE[client.c, WordAsBits][thisBit] THEN H ELSE L, lc => IF (IF thisBit < 16 THEN LOOPHOLE[Basics.HighHalf[client.lc], WordAsBits][thisBit] ELSE LOOPHOLE[Basics.LowHalf[client.lc], WordAsBits][thisBit - 16]) THEN H ELSE L, q => IF BitOps.EBFQ[client.q, thisBit, 64] THEN H ELSE L, ENDCASE => ERROR; IF separateDrive THEN IF fieldDrive[bit]#clientDrive[thisBit] THEN { changeDrive _ TRUE; fieldDrive[bit] _ clientDrive[thisBit]; }; IF fieldValue[bit]#clientLevel THEN { changeValue _ TRUE; fieldValue[bit] _ clientLevel; }; ENDLOOP; UpdateReader[simulation, field]; IF allowUpdate AND (changeDrive OR changeValue) THEN RecomputeValue[simulation, field.roseWire, FALSE, updateProc]; ENDLOOP; }; ENDCASE => ERROR; ENDLOOP; }; RecomputeValue: PROC [simulation: Simulation, wire: RoseWire, forceReaderUpdate: BOOL, updateProc: UpdateProc] = { wireValue: Ports.LevelSequence _ wire.currentValue; IF wireValue=NIL THEN { scratchLevel: Ports.Level _ X; scratchDrive: Ports.Drive _ none; FOR writers: CARDINAL IN [0..wire.connections.size) DO writer: Field _ wire.connections[writers]; writerLevel: Ports.Level _ writer.currentValue[0]; writerDrive: Ports.Drive _ IF writer.currentDrive=NIL THEN writer.portBinding.currentDrive ELSE writer.currentDrive[0]; IF writerDrive > scratchDrive THEN { scratchLevel _ writerLevel; scratchDrive _ writerDrive; } ELSE IF writerDrive = scratchDrive AND scratchLevel # writerLevel AND writerDrive > none THEN scratchLevel _ X; ENDLOOP; IF scratchLevel#wire.connectionLevel OR scratchDrive#wire.connectionDrive OR forceReaderUpdate THEN { wire.connectionLevel _ scratchLevel; wire.connectionDrive _ scratchDrive; Perturb[simulation, wire]; }; } ELSE { scratchValue: Ports.LevelSequence _ simulation.scratchValue; scratchDrive: Ports.DriveSequence _ simulation.scratchDrive; changeWire: BOOL _ FALSE; FOR bit: NAT IN [0..wireValue.size) DO scratchValue[bit] _ wireValue[bit]; scratchDrive[bit] _ wire.wireDrive; ENDLOOP; FOR writers: CARDINAL IN [0..wire.connections.size) DO writer: Field _ wire.connections[writers]; writerValue: Ports.LevelSequence _ writer.currentValue; separateDrive: BOOL _ writer.currentDrive#NIL; writerDrive: Ports.Drive _ writer.portBinding.currentDrive; FOR bit: NAT IN [0..writerValue.size) DO sd: Ports.Drive _ scratchDrive[bit]; IF separateDrive THEN writerDrive _ writer.currentDrive[bit]; IF writerDrive > sd THEN { scratchValue[bit] _ writerValue[bit]; scratchDrive[bit] _ writerDrive; } ELSE IF writerDrive = sd AND scratchValue[bit] # writerValue[bit] AND writerDrive > none THEN scratchValue[bit] _ X; ENDLOOP; ENDLOOP; FOR bit: NAT IN [0..wireValue.size) DO IF wireValue[bit] # scratchValue[bit] THEN { wireValue[bit] _ scratchValue[bit]; changeWire _ TRUE; }; ENDLOOP; IF changeWire OR forceReaderUpdate THEN UpdateReaders[simulation, wire, updateProc]; }; }; UpdateReaders: PROC [simulation: Simulation, wire: RoseWire, updateProc: UpdateProc] = { IF updateProc#NIL THEN updateProc[wire]; IF wire.connections#NIL THEN FOR readers: CARDINAL IN [0..wire.connections.size) DO reader: Field _ wire.connections[readers]; instance: RoseCellInstance _ reader.portBinding.instance; IF instance#NIL THEN IF instance.nextNeedEval=NIL THEN { instance.nextNeedEval _ simulation.instanceNeedEval; simulation.instanceNeedEval _ instance; }; UpdateReader[simulation, reader]; ENDLOOP; }; UpdateReader: PROC [simulation: Simulation, reader: Field] = { ToBool: PROC [level: Ports.Level, old: BOOL] RETURNS [new: BOOL] = { new _ SELECT level FROM L => FALSE, X => old, H => TRUE, ENDCASE => ERROR; }; wire: RoseWire _ reader.roseWire; wireValue: Ports.LevelSequence _ wire.currentValue; readerValue: Ports.Port _ reader.portBinding.clientPort; readerStart: NAT _ reader.portStartBit+readerValue.fieldStart; SELECT readerValue.levelType FROM l => readerValue.l _ wire.wireLevel; b => readerValue.b _ ToBool[wire.wireLevel, readerValue.b]; ls => { IF wireValue=NIL THEN readerValue.ls[readerStart] _ wire.wireLevel ELSE FOR bit: NAT IN [0..wireValue.size) DO readerValue.ls[bit+readerStart] _ wireValue[bit]; ENDLOOP; }; bs => { IF wireValue=NIL THEN readerValue.bs[readerStart] _ ToBool[wire.wireLevel, readerValue.bs[readerStart]] ELSE FOR bit: NAT IN [0..wireValue.size) DO readerValue.bs[bit+readerStart] _ ToBool[wireValue[bit], readerValue.bs[bit+readerStart]]; ENDLOOP; }; c => { asBits: WordAsBits _ LOOPHOLE[readerValue.c]; IF wireValue=NIL THEN asBits[readerStart] _ ToBool[wire.wireLevel, asBits[readerStart]] ELSE FOR bit: NAT IN [0..wireValue.size) DO thisBit: NAT _ bit+readerStart; asBits[thisBit] _ ToBool[wireValue[bit], asBits[thisBit]]; ENDLOOP; readerValue.c _ LOOPHOLE[asBits]; }; lc => { asBits: DWordAsBits _ LOOPHOLE[Basics.SwapHalves[LOOPHOLE[readerValue.lc]]]; IF wireValue=NIL THEN asBits[readerStart] _ ToBool[wire.wireLevel, asBits[readerStart]] ELSE FOR bit: NAT IN [0..wireValue.size) DO thisBit: NAT _ bit+readerStart; asBits[thisBit] _ ToBool[wireValue[bit], asBits[thisBit]]; ENDLOOP; readerValue.lc _ LOOPHOLE[Basics.SwapHalves[LOOPHOLE[asBits]]]; }; q => { fieldSize: NAT _ 64 - readerValue.fieldStart; IF wireValue=NIL THEN readerValue.q _ BitOps.IBIQ[ToBool[wire.wireLevel, BitOps.EBFQ[readerValue.q, reader.portStartBit, fieldSize]], readerValue.q, reader.portStartBit, fieldSize] ELSE FOR bit: NAT IN [0..wireValue.size) DO thisBit: NAT _ bit+reader.portStartBit; readerValue.q _ BitOps.IBIQ[ToBool[wireValue[bit], BitOps.EBFQ[readerValue.q, thisBit, fieldSize]], readerValue.q, thisBit, fieldSize]; ENDLOOP; }; ENDCASE => ERROR; }; Conductance: TYPE = {on, off, unknown}; TranOn: PROC [tran: RoseTransistor, gateValue: Ports.Level] RETURNS [cond: Conductance] = { cond _ SELECT tran.type FROM nE => SELECT gateValue FROM L => off, H => on, X => unknown, ENDCASE => ERROR, pE => SELECT gateValue FROM L => on, H => off, X => unknown, ENDCASE => ERROR, nD => on, ENDCASE => ERROR; }; UpdatePerturbed: PROC [simulation: Simulation, updateProc: UpdateProc, memory: BOOL _ TRUE] = { PushWireByStrength: PROC [wire: RoseWire, thisDrive: Ports.Drive] = { simulation.vicinityByStrength[thisDrive].wires[ simulation.vicinityByStrength[thisDrive].firstFree] _ wire; simulation.vicinityByStrength[thisDrive].firstFree _ simulation.vicinityByStrength[thisDrive].firstFree+1; }; PushWhat: TYPE = {switch, up, down}; FindVicinity: PROC [wire: RoseWire, what: PushWhat] = { UpDownStrength: PROC [notLevel: Ports.Level] RETURNS [strength: Ports.Drive] = { level: Ports.Level; IF wire.wireDrive>wire.connectionDrive THEN { level _ wire.wireLevel; strength _ wire.wireDrive; } ELSE { level _ wire.connectionLevel; strength _ wire.connectionDrive; }; IF level=notLevel THEN strength _ none; }; wireDrive: Ports.Drive _ SELECT what FROM switch => IF wire.wireDrive>wire.connectionDrive THEN wire.wireDrive ELSE wire.connectionDrive, up => UpDownStrength[L], down => UpDownStrength[H], ENDCASE => ERROR; channels: RoseTransistors _ wire.notOffChannels; wire.mark _ TRUE; FOR t: CARDINAL IN [0..wire.validNotOffChannels) DO tran: RoseTransistor _ channels[t]; tranCond: Conductance _ TranOn[tran, tran.gate.wireLevel]; otherWire: RoseWire _ tran.ch1; IF otherWire=wire THEN otherWire _ tran.ch2; IF otherWire.wireDrive=infinite THEN { IF ((what=switch AND tranCond=on) OR (what=up AND otherWire.wireLevel#L) OR (what=down AND otherWire.wireLevel#H)) AND wireDrive < tran.conductivity THEN wireDrive _ tran.conductivity; } ELSE IF NOT otherWire.mark THEN FindVicinity[otherWire, what]; ENDLOOP; IF what#switch AND wireDrive < wire.switchDrive THEN wireDrive _ none; PushWireByStrength[wire, wireDrive]; SELECT what FROM switch => wire.switchDrive _ wireDrive; up => wire.upDrive _ wireDrive; down => wire.downDrive _ wireDrive; ENDCASE => ERROR; }; PushStrength: PROC [what: PushWhat] = { FOR thisDrive: Ports.Drive DECREASING IN [none..infinite) DO firstFreeWire: CARDINAL; UNTIL (firstFreeWire _ simulation.vicinityByStrength[thisDrive].firstFree)=0 DO wire: RoseWire _ simulation.vicinityByStrength[thisDrive].wires[ firstFreeWire-1]; channels: RoseTransistors _ wire.notOffChannels; wire.mark _ FALSE; simulation.vicinityByStrength[thisDrive].firstFree _ firstFreeWire-1; IF thisDrive=none OR thisDrive < (SELECT what FROM switch => wire.switchDrive, up => wire.upDrive, down => wire.downDrive, ENDCASE => ERROR) THEN LOOP; FOR t: CARDINAL IN [0..wire.validNotOffChannels) DO tran: RoseTransistor _ channels[t]; tranCond: Conductance _ TranOn[tran, tran.gate.wireLevel]; driveThrough: Ports.Drive _ MIN[thisDrive, tran.conductivity]; otherWire: RoseWire _ tran.ch1; IF otherWire=wire THEN otherWire _ tran.ch2; SELECT what FROM switch => IF tranCond=on AND driveThrough > otherWire.switchDrive THEN { otherWire.switchDrive _ driveThrough; PushWireByStrength[otherWire, driveThrough]; }; up => IF driveThrough >= otherWire.switchDrive AND driveThrough > otherWire.upDrive THEN { otherWire.upDrive _ driveThrough; PushWireByStrength[otherWire, driveThrough]; }; down => IF driveThrough >= otherWire.switchDrive AND driveThrough > otherWire.downDrive THEN { otherWire.downDrive _ driveThrough; PushWireByStrength[otherWire, driveThrough]; }; ENDCASE => ERROR; ENDLOOP; ENDLOOP; ENDLOOP; }; UpdateRecomputed: PROC = { FOR thisWire: RoseWire _ recomputed, thisWire.nextRecomputed UNTIL thisWire=NIL DO wireLevel: Ports.Level _ SELECT TRUE FROM thisWire.upDrive=none AND (memory OR thisWire.memory OR thisWire.downDrive>=force) => L, thisWire.downDrive=none AND (memory OR thisWire.memory OR thisWire.upDrive>=force) => H, ENDCASE => X; IF thisWire.wireLevel#wireLevel THEN { gates: RoseTransistors _ thisWire.gates; IF gates#NIL THEN FOR t: CARDINAL IN [0..gates.size) DO CheckAddOrRemove: PROC [channel: RoseWire] = { IF channel.channels#NIL THEN SELECT TRUE FROM wasNotOff AND NOT isNotOff => { FOR v: CARDINAL IN [0..channel.validNotOffChannels) DO IF channel.notOffChannels[v]=tran THEN { FOR c: CARDINAL IN [v+1..channel.validNotOffChannels) DO channel.notOffChannels[c-1] _ channel.notOffChannels[c]; ENDLOOP; channel.validNotOffChannels _ channel.validNotOffChannels - 1; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; }; NOT wasNotOff AND isNotOff => { channel.notOffChannels[channel.validNotOffChannels] _ tran; channel.validNotOffChannels _ channel.validNotOffChannels + 1; }; ENDCASE; }; tran: RoseTransistor _ gates[t]; wasNotOff: BOOL _ TranOn[tran, thisWire.wireLevel]#off; isNotOff: BOOL _ TranOn[tran, wireLevel]#off; Perturb[simulation, tran.ch1]; Perturb[simulation, tran.ch2]; CheckAddOrRemove[tran.ch1]; CheckAddOrRemove[tran.ch2]; ENDLOOP; thisWire.wireLevel _ wireLevel; UpdateReaders[simulation, thisWire, updateProc]; }; ENDLOOP; }; recomputed: RoseWire _ NIL; UNTIL simulation.perturbed=NIL DO FastFindVicinity: PROC [wire: RoseWire] = { channels: RoseTransistors _ wire.notOffChannels; valid: CARDINAL _ wire.validNotOffChannels; wire.mark _ TRUE; IF wire.wireLevel#sameValue OR wire.connections#NIL THEN { allSameValue _ FALSE; singleInfiniteNoUnknownConductance _ FALSE; }; FOR t: CARDINAL IN [0..valid) DO tran: RoseTransistor _ channels[t]; tranCond: Conductance _ TranOn[tran, tran.gate.wireLevel]; otherWire: RoseWire _ tran.ch1; IF otherWire=wire THEN otherWire _ tran.ch2; IF tranCond=unknown THEN singleInfiniteNoUnknownConductance _ FALSE; IF otherWire.wireDrive=infinite THEN { IF infiniteFound AND infiniteValue#otherWire.wireLevel THEN singleInfiniteNoUnknownConductance _ FALSE; infiniteFound _ TRUE; infiniteValue _ otherWire.wireLevel; IF otherWire.wireLevel#sameValue THEN allSameValue _ FALSE; } ELSE IF NOT otherWire.mark THEN FastFindVicinity[otherWire]; ENDLOOP; { next: RoseWire _ wire.nextPerturbedWire; previous: RoseWire _ wire.previousPerturbedWire; IF next#NIL THEN next.previousPerturbedWire _ previous; IF previous#NIL THEN previous.nextPerturbedWire _ next; IF simulation.perturbed=wire THEN simulation.perturbed _ next; wire.nextPerturbedWire _ NIL; wire.previousPerturbedWire _ NIL; wire.nextRecomputed _ recomputed; recomputed _ wire; wire.nextVicinityWire _ vicinityWire; vicinityWire _ wire; }; }; ForceUpDown: PROC [up, down: Ports.Drive] = { FOR thisWire: RoseWire _ vicinityWire, thisWire.nextVicinityWire UNTIL thisWire=NIL DO thisWire.mark _ FALSE; thisWire.upDrive _ up; thisWire.downDrive _ down; ENDLOOP; }; wire: RoseWire _ simulation.perturbed; vicinityWire: RoseWire _ NIL; infiniteFound: BOOL _ FALSE; infiniteValue: Ports.Level _ X; singleInfiniteNoUnknownConductance: BOOL _ TRUE; allSameValue: BOOL _ TRUE; sameValue: Ports.Level _ wire.wireLevel; FastFindVicinity[wire]; SELECT TRUE FROM infiniteFound AND singleInfiniteNoUnknownConductance => { SELECT infiniteValue FROM L => ForceUpDown[none, infinite]; H => ForceUpDown[infinite, none]; ENDCASE => ERROR; }; allSameValue => { strength: Ports.Drive _ IF infiniteFound THEN infinite ELSE charge; SELECT sameValue FROM L => ForceUpDown[none, strength]; H => ForceUpDown[strength, none]; X => ForceUpDown[strength, strength]; ENDCASE => ERROR; } ENDCASE => { FOR thisWire: RoseWire _ vicinityWire, thisWire.nextVicinityWire UNTIL thisWire=NIL DO thisWire.mark _ FALSE; ENDLOOP; FindVicinity[wire, switch]; PushStrength[switch]; FindVicinity[wire, up]; PushStrength[up]; FindVicinity[wire, down]; PushStrength[down]; }; ENDLOOP; UpdateRecomputed[]; }; Perturb: PROC [simulation: Simulation, wire: RoseWire] = { IF wire.nextPerturbedWire=NIL AND wire.previousPerturbedWire=NIL AND simulation.perturbed#wire AND wire.wireDrive flat _ wireKey^; wireKey: RoseWire => flat _ wireKey.wire; ENDCASE => ERROR; }; RoseWireHash: PROC [key: REF ANY] RETURNS [hash: CARDINAL] = { hash _ CoreFlat.FlatWireHashRec[RoseWireHashNarrow[key]]; }; RoseWireEqual: PROC [key1, key2: REF ANY] RETURNS [equal: BOOL] = { equal _ CoreFlat.FlatWireEqualRec[RoseWireHashNarrow[key1], RoseWireHashNarrow[key2]]; }; RoseInstanceHashNarrow: PROC [key: REF ANY] RETURNS [flat: CoreFlat.FlatCellTypeRec] = { WITH key SELECT FROM instanceKey: CoreFlat.FlatCellType => flat _ instanceKey^; instanceKey: RoseCellInstance => flat _ instanceKey.instance; ENDCASE => ERROR; }; RoseInstanceHash: PROC [key: REF ANY] RETURNS [hash: CARDINAL] = { hash _ CoreFlat.FlatCellTypeHashRec[RoseInstanceHashNarrow[key]]; }; RoseInstanceEqual: PROC [key1, key2: REF ANY] RETURNS [equal: BOOL] = { equal _ CoreFlat.FlatCellTypeEqualRec[RoseInstanceHashNarrow[key1], RoseInstanceHashNarrow[key2]]; }; finalizationQueue: SafeStorage.FinalizationQueue; simulations: RefTab.Ref; -- keep a pointer to active simulations for finalization NewSimulation: PROC [] RETURNS [simulation: Simulation] ~ { simulation _ NEW [SimulationRec]; IF NOT RefTab.Insert[simulations, simulation, NIL] THEN ERROR; SafeStorage.EnableFinalization[simulation]; }; DestroySimulation: PROC [sim: Simulation] ~ { EraseRoseWire: RefTab.EachPairAction ~ { roseWire: RoseWire _ NARROW [val]; roseWire^ _ []; }; EraseRoseCellInstance: RefTab.EachPairAction ~ { roseCellInstance: RoseCellInstance _ NARROW [val]; ErasePortBindings[roseCellInstance.portBindings]; roseCellInstance^ _ []; }; ErasePortBindings: PROC [portBindings: PortBindings] ~ { FOR i: NAT IN [0..portBindings.size) DO portBindings.elements[i]^ _ []; -- remove all `Fields' to avoid circularities ENDLOOP; }; [] _ RefTab.Pairs[sim.coreToRoseWires, EraseRoseWire]; RefTab.Erase[sim.coreToRoseWires]; [] _ RefTab.Pairs[sim.coreToRoseInstances, EraseRoseCellInstance]; RefTab.Erase[sim.coreToRoseInstances]; RefTab.Erase[sim.coreToRoseValues]; -- no need to to anything about internals ErasePortBindings[sim.publicBindings]; sim^ _ []; }; SimulationFinalizer: PROC [] ~ { sim: Simulation; DO -- forever sim _ NARROW [SafeStorage.FQNext[finalizationQueue]]; IF NOT RefTab.Delete[simulations, sim] THEN ERROR; DestroySimulation[sim]; sim _ NIL; ENDLOOP; }; Initialization: PROC [] ~ { sim: Simulation _ NEW [SimulationRec]; finalizationQueue _ SafeStorage.NewFQ[]; simulations _ RefTab.Create[]; SafeStorage.EstablishFinalization[SafeStorage.GetReferentType[sim], 1, finalizationQueue]; sim _ NIL; TRUSTED { Process.Detach [ FORK SimulationFinalizer[] ] }; }; Initialization[]; END. "RosemaryImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Barth, January 5, 1988 11:36:18 am PST Bertrand Serlet May 5, 1988 10:54:35 pm PDT Last Edited by: Louis Monier January 20, 1987 10:40:25 am PST Last Edited by: Ross March 16, 1987 3:15:19 pm PST Jean-Marc Frailong December 17, 1987 5:13:30 pm PST EUWireTrap: CoreFlat.FlatWireRec; -- Hack EUGndWireTrap: CoreFlat.FlatWireRec; -- Hack hackWireData: REF ANY; -- Hack hackChannels: CARDINAL _ 0; -- Hack maxHackChannels: CARDINAL _ 0; -- Hack TrapEnable: BOOL _ FALSE; -- Hack HackStop: SIGNAL = CODE; -- Hack Behaviour Registration Instantiation IF EUWireTrap.wire=key THEN SIGNAL HackStop; -- Hack IF EUWireTrap.wire=key THEN SIGNAL HackStop; -- Hack IF EUWireTrap.wire=wire THEN TrapEnable _ TRUE; -- Hack IF wire=EUGndWireTrap.wire THEN { hackWireData _ wireData; hackChannels _ wireData.channels; maxHackChannels _ MAX[wireData.channels, maxHackChannels]; }; -- Hack IF TrapEnable AND Rope.Equal[CoreOps.GetShortWireName[wire], "Gnd"] THEN { IF flatWire.wire#EUWireTrap.wire THEN SIGNAL HackStop; }; -- Hack IF enableHack THEN IF CoreFlat.InstancePathEqual[flatCell.path, hackWireCellPath] THEN SIGNAL HackStop[]; -- Hack IF enableHack THEN IF CoreFlat.FlatCellTypeEqualRec[flatCell, hackCell] THEN SIGNAL HackStop[]; -- Hack IF EUWireTrap.wire=wire THEN SIGNAL HackStop; -- Hack enableHack: BOOL _ Rope.Equal[CoreOps.GetCellTypeName[cellType], "EU"]; -- Hack hackCell: CoreFlat.FlatCellTypeRec _ IF enableHack THEN CoreFlat.ParseCellTypePath[cellType, "/140/0"] ELSE []; -- Hack hackWireCellPath: CoreFlat.InstancePath _ []; IF enableHack THEN CoreFlat.ParseWirePath[cellType, "/140/0(Inner)/0(Control)/0(BothAlps)/0(DPControl)/0(UpsideDownDPControl)/28/80(OutputDriver)/0(Inverter)/0.public.ch2"] ELSE []; -- Hack hackWireCellPath.length _ 31; -- Hack hackWireCellPath.bits[0] _ TRUE; -- Hack hackWireCellPath.bits[4] _ TRUE; -- Hack hackWireCellPath.bits[5] _ TRUE; -- Hack hackWireCellPath.bits[15] _ TRUE; -- Hack hackWireCellPath.bits[16] _ TRUE; -- Hack hackWireCellPath.bits[17] _ TRUE; -- Hack hackWireCellPath.bits[20] _ TRUE; -- Hack hackWireCellPath.bits[22] _ TRUE; -- Hack Relaxation State Access Hash Table Utilities Garbage Collection Initialization of the finalization of Rosemary simulations Κ@_– "cedar" style˜codešœ™Kšœ Οmœ7™BKšœ#Οk™&Kšœ+™+Kšœ:ž™=Kšœ/ž™2Kšœ0ž™3K™—šž ˜ Kšœ$˜$Kšœ>˜>KšžœJ˜L—K˜•StartOfExpansion[]šΠbn œžœž˜Kšžœ]žœ?˜₯Kšžœ ˜Kšœžœžœ ˜—K˜KšΟn œΟc™*Kš  œ‘™-Kšœžœžœ‘™Kšœžœ‘™$Kšœžœ‘™'Kš  œžœžœ‘™"Kš œžœžœ‘™!K™Kšœžœžœ‘A˜`Kšœžœ*˜˜>Kšœ=˜=Kšœ/˜/K˜K˜—š œ˜)Kšœžœ˜2Kšœ=˜=Kšœ<˜žœ/˜šKšœXžœ˜qKšœ˜Jšœ˜J˜—š   œžœžœKžœžœžœ˜’K˜š œžœ*žœ˜GKšœ˜Kšœ˜Kšœ+˜+šžœ žœžœ˜Kšžœžœžœ ‘™5Kšœ žœ˜Kšžœžœ6žœžœ˜GK˜—Kšžœžœž˜6šžœ˜Kšžœžœžœ ‘™5Kšœžœ˜Kšœžœ˜!Kšœ˜Kšœ˜Kšœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜šžœžœžœž˜!Kšœ%˜%Kšžœ˜—Kšœ˜—Kšžœžœžœ‘™8Kšœ˜K˜—š œžœMžœ1˜¦Kšœ4˜4šžœžœ+žœ˜7Kšžœžœ5žœžœ˜FKšœ0˜0šžœ žœ˜Kšœ4˜4šžœžœ˜Kšœžœ˜Kšœ žœ˜K˜—K˜—šžœžœžœž˜!KšœX˜XKšžœ˜—K˜—Kšžœžœ žœžœ žœžœžœ˜RKšœ˜K˜—š œžœ)žœ˜]Kšžœ žœžœ žœ+˜Qšžœ˜Kšœžœ+˜OKšžœ žœžœžœ˜Kšœ žœ5˜Fšžœžœ™!Kšœ™Kšœ!™!Kšœžœ%™:Kšœ‘™ —šžœ žœ3žœ™JKšžœžœžœ ™6Kšœ‘™ —K˜—K˜K˜—š œžœ)žœ/˜mKš œžœ žœžœžœžœžœ+˜mKš œ žœ žœžœžœ˜9Kšœ žœ1˜BK˜K˜—š œ ˜7K˜šžœžœž˜šœ/˜/Kšœ ˜ Kšœ<˜˜>šžœžœ˜ Kšœžœ!˜;šžœžœžœ ž˜4Kšœžœ˜Kšžœ˜—K˜—šžœ žœžœžœ˜"KšœB˜BKšœH˜HKšœ<˜šžœžœžœ˜Kšœ ˜ Kšžœ˜K˜—šž˜Kšžœžœ˜—Kšžœ˜—K˜K˜—Kšœ ˜ Kšœ)žœ ˜;Kšœ!žœ˜8KšœžœžœS˜~Kšœ=˜=Kšœ,˜,Kšœ;˜;Kšœ.˜.Kšœ;˜;Kšœ.˜.KšžœžœžœžœK˜ƒKšžœžœžœ2˜Ošžœžœ˜Kšœžœ-˜7š žœžœžœžœžœ ž˜7šžœ)žœ˜1Kšœ"˜"Kšžœ˜Kšœ˜—š žœžœžœžœž˜:šžœ&žœ˜.Kšœ"˜"Kšžœ˜Kšœ˜—Kšžœ˜—Kšžœ˜—K˜—Kšœ*˜*Kšœ#˜#K˜&K˜—šœD˜DKšœ ˜ Kšœ!žœ˜:Kšœ=˜=Kšœ1˜1Kšœžœ=˜\KšžœΪžœžœ˜ηšžœ žœž˜*Kšœi˜i—Kšœ!˜!KšžœžœXžœžœ˜iK˜"K˜—Kšžœ˜†—K˜K˜K˜—š œžœ)žœ˜]šžœ žœžœ˜Kšœ)˜)Kšœ˜Kšœ žœ@˜QKšœ˜—šžœ˜Kšœžœ+˜PKšœ žœC˜TK˜—Kšœ˜K˜—šŸœ˜-Kšœžœ˜!Kšžœžœ%žœ˜LKš žœžœžœžœžœ'˜WK˜K˜—š   œžœ žœžœ žœ˜WKšœ*˜*Kšœ žœ˜Kšœ˜š žœ žœžœžœžœžœž˜=Kšœ#˜#K˜Kšžœžœ˜,Kšžœžœžœžœ/˜jKšžœ˜—K˜K˜—Kšœ žœžœ ˜!šœ žœžœ˜Kšœžœžœ˜Kšœžœžœ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœ žœžœ˜Kšœ žœžœ˜šœ žœžœ˜K™——Jšœžœ˜&Jšœžœ˜Jšœžœ˜Kšœžœ#žœ˜0Kšœžœ"žœ˜.Kšœžœ"žœ˜.Kšœžœ˜Kšœ žœ˜Kšœžœ˜7Kšœ1˜1Kšœ žœ9‘™PKšœ%žœ žœ0žœ‘™xKšœ-™-Kšžœ žœ›žœ‘™ΎKšœ‘™&Kšœžœ‘™)Kšœžœ‘™)Kšœžœ‘™)Kšœžœ‘™*Kšœžœ‘™*Kšœžœ‘™*Kšœžœ‘™*Kšœžœ‘™*Kšœ3˜3Kšœ0˜0Kšœ0žœ*˜\Kšœ˜Kšœ˜Kšœ˜Kšœžœ-˜LKšœ`˜`Kšœl˜lKšœh˜hšœ˜Kšœ$˜$Kšœ&˜&šžœžœžœž˜!Kšœ˜Kšžœ˜—šžœžœžœž˜!Kšœ)žœ žœ˜SKšžœ˜—Kšœ"˜"šžœžœžœž˜!Kšœ9žœžœ˜DKšžœ˜—K˜—Kšžœ:žœzžœžœ˜ΔKšœ˜Kšœžœ*˜GKšœžœ*˜GKšœM˜Mšžœžœ ž˜+Kšœ0žœ˜NKšžœ˜—K˜-K˜ Kšœ˜Jšœ žœ?žœžœ-˜•˜K™——š   œžœžœžœžœ˜IKšœV˜VK˜Kšœžœ˜3Kšœžœ˜7Kšœžœ˜7Kšœ˜Kšžœžœžœ˜Kšœ˜K˜—š  œžœ(žœžœ žœ žœ˜xK˜š   œžœžœGžœžœ˜‚KšœžœE˜dKšœžœžœF˜lKšœžœ˜šžœ žœžœ˜Kšœ˜Kšœ˜Kšœ˜K˜—šžœžœ˜Kšœ˜Kšœ˜K˜—K˜K˜—š œžœ˜$Kšœ8˜8K˜K˜K˜—Kšœžœ˜ Kšœ žœ˜Kšœ&˜&šžœ žœ˜Kšœ8˜8Kšœ-˜-Kšœ˜—šžœ˜KšœQ˜QKšœ*˜*K˜—Kšœ˜Kšœžœžœžœ ˜FK˜K˜—š œžœ˜6K˜šŸœ˜#Kšœ!žœ˜-KšœRžœžœ˜jšžœžœžœ˜'Kšœ8˜8Kšœ+˜+K˜—K˜K˜—šŸœ˜Kšœžœ˜!Kšœžœ˜Kš žœžœžœKžœžœ˜‚K˜šžœžœžœ˜Kšœ!˜!šžœžœžœž˜1Kšœ,˜,šžœ'žœ˜/Kšœ=˜=Kšœ@˜@K˜—Kšžœ˜—K˜—K˜K˜—KšœRžœžœ˜jKšœG˜GKšœ?˜?K˜K˜—š œžœžœ!˜cKšœ*˜*Kšžœžœžœžœw˜•K˜K˜—š œžœžœ!˜YKšœžœžœG˜cKšžœžœžœžœN˜~Kšžœžœžœ3˜LKšœžœ:˜OK˜K˜—š œžœ žœžœ˜NKšœžœ ˜(šžœžœžœ žœ˜Kšœ ˜ Kšžœ˜—Kšœ˜K˜—š œžœžœ"žœ"˜qKšœ žœ˜+šžœžœžœ žœ˜Kšœ˜Kšžœ˜—Kšœ˜K˜——šœ ™ š   œžœžœ"žœžœ#žœ˜oK˜š œ˜"Kšœžœžœžœ˜-Kšœžœ˜!Kšžœžœžœ˜+Kšžœžœžœ˜<š žœžœžœžœ!ž˜7Kšœ#˜#Kšžœ˜—K˜K˜—š œ˜#Kšœ!žœ˜-Kšœl˜lK˜ KšœC˜Cšžœ žœžœ˜,Kšœ˜Kšžœžœžœ*˜DKšœ˜—K˜K˜—Kšœ˜KšœB˜BKšœG˜GKšœ ˜ Kšœ˜K˜—š  œžœžœP˜iKšœ!žœE˜lKš žœžœžœžœ‘˜1šžœ˜K˜š œ˜$šžœžœ˜%šžœžœžœ˜4Kšœ˜Kšœ žœžœ˜Kšœžœžœ˜šžœžœžœž˜1Kšœ$˜$Kšžœžœžœ˜(Kšžœžœžœ˜Kšžœ˜—šžœ žœžœž˜2Kšœ9˜9Kšœ žœžœ˜šžœžœžœ˜#Kšžœžœžœ˜6Kšœ˜—šžœ˜Kšœ+˜+šžœžœžœž˜4šžœ@žœ˜HKšœ žœ˜Kšžœ˜K˜—Kšžœ˜—K˜—Kšœžœ ˜$Kšœžœžœ ˜.Kšžœ˜—Kšžœ žœžœžœ˜)Kšœžœ žœžœ˜2Kšœ˜—K˜—K˜K˜—Kšœ.˜.Kšœ>˜>Jšœ-˜-KšžœRžœžœ˜_Kšœ˜—Kšœ˜K™—š œžœžœ3žœ žœžœ žœžœ#žœ˜’Kšœ3˜3Kšœ0˜0˜Kšžœžœ"˜/Kšœ]˜]š žœžœ žœžœ-žœž˜NKšœI˜IKšœT˜TKšœ(žœ˜,šžœžœžœ˜#Kšœ4˜4Kšœ'˜'K˜—Kšžœ˜—š žœžœžœžœž˜Ešžœžœž˜(Kšœ9˜9K˜ Kšœ4˜4Kšœžœ˜Kšœv˜vKšžœžœžœ&˜@š žœ žœ+žœ'žœžœ˜oKšœT˜TKšœ7˜7K˜—KšœY˜YK˜Kšžœ˜—Kšœ1‘˜FKšœP˜PK˜Kšžœ˜—šœ˜Kšœžœžœ˜š žœ žœžœ5žœ žœž˜aKšœ%˜%š  œžœ˜)Kšžœ žœžœ-žœ7˜}K˜—Kšžœžœžœ˜@š žœžœžœžœ!ž˜Kšœžœžœžœžœ2žœžœ7žœžœ˜«Kš œžœžœžœžœ˜9Kšžœžœ˜—šžœžœžœ&žœ˜DKšœžœ˜Kšœ'˜'K˜—šžœžœ˜%Kšœžœ˜Kšœ˜K˜—Kšžœ˜—K˜ Kš žœ žœžœžœ,žœ˜sKšžœ˜—K˜—Kšžœžœ˜—Kšžœ˜—J˜J˜—š œžœ=žœ˜rKšœ3˜3šžœ žœžœ˜Kšœ˜Kšœ!˜!šžœ žœžœž˜6Kšœ*˜*Kšœ2˜2Kš œžœžœžœ!žœ˜wšžœžœ˜$Kšœ˜Kšœ˜K˜—Kš žœžœžœžœžœ˜oKšžœ˜—šžœ#žœ#žœžœ˜eKšœ$˜$Kšœ$˜$Kšœ˜K˜—K˜—šžœ˜Kšœ<˜K˜š  œžœžœžœžœ˜Dšœžœž˜Kšœžœ˜ Kšœ ˜ Kšœžœ˜ Kšžœžœ˜—K˜K˜—K˜!Kšœ3˜3Kšœ8˜8Kšœ žœ.˜>šžœž˜!Kšœ$˜$Kšœ;˜;šœ˜Kšžœ žœžœ-˜Bš žœžœžœžœž˜+Kšœ1˜1Kšžœ˜—K˜—šœ˜Kšžœ žœžœR˜gš žœžœžœžœž˜+KšœZ˜ZKšžœ˜—K˜—šœ˜Kšœžœ˜-Kšžœ žœžœC˜Xš žœžœžœžœž˜+Kšœ žœ˜Kšœ:˜:Kšžœ˜—Kšœžœ ˜!K˜—šœ˜Kšœžœžœ˜LKšžœ žœžœC˜Xš žœžœžœžœž˜+Kšœ žœ˜Kšœ:˜:Kšžœ˜—Kšœžœžœ ˜?K˜—šœ˜Kšœ žœ˜-Kš žœ žœžœžœžœa˜΅š žœžœžœžœž˜+Kšœ žœ˜'KšœžœžœI˜‡Kšžœ˜—K˜—Kšžœžœ˜—K˜K˜—Kšœ žœ˜'K˜š œžœ0žœ˜[šœžœ žœ˜šœžœ ž˜Kšœ ˜ Kšœ˜Kšœ ˜ Kšžœžœ˜—šœžœ ž˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšžœžœ˜—Kšœ ˜ Kšžœžœ˜—K˜K˜—š œžœ:žœžœ˜`K˜š œžœ-˜EKšœk˜kKšœj˜jK˜K˜—šœ žœ˜$K˜—š  œžœ%˜7K˜š œžœžœ˜PKšœ˜šžœ%žœ˜-Kšœ˜Kšœ˜K˜—šžœ˜Kšœ˜Kšœ ˜ K˜—Kšžœžœ˜'K˜K˜—šœžœž˜)Kšœ žœ%žœžœ˜_Kšœ˜Kšœ˜Kšžœžœ˜—Kšœ0˜0Kšœ žœ˜šžœžœžœž˜3Kšœ#˜#Kšœ:˜:K˜Kšžœžœ˜,šžœžœ˜&Kšžœžœžœ žœžœ žœžœžœ˜ΈK˜—Kšžœžœžœžœ˜>Kšžœ˜—Kšžœ žœžœ˜FKšœ$˜$šžœž˜Kšœ'˜'Kšœ˜Kšœ#˜#Kšžœžœ˜—K˜K˜—š  œžœ˜'šžœž œžœž˜K˜Kšžœžœ˜,šžœž˜šœ žœ žœ&žœ˜HKšœ%˜%Kšœ,˜,K˜—šœžœ'žœ"žœ˜ZKšœ!˜!Kšœ,˜,K˜—šœžœ'žœ$žœ˜^Kšœ#˜#Kšœ,˜,K˜—Kšžœžœ˜—Kšžœ˜—Kšžœ˜—Kšžœ˜—K˜K˜—š œžœ˜šžœ:žœ žœž˜Ršœžœžœž˜)Kšœžœ žœžœ!˜XKšœžœ žœžœ˜XKšžœ˜ —šžœžœ˜&Kšœ(˜(š žœžœžœžœžœžœž˜7K˜š œžœ˜.š žœžœžœžœžœž˜-šœ žœžœ˜šžœžœžœ"ž˜6šžœ žœ˜(šžœžœžœ$ž˜8Kšœ8˜8Kšžœ˜—Kšœ>˜>Kšžœ˜K˜—Kšžœžœžœ˜Kšžœ˜—K˜—šžœ žœ˜Kšœ;˜;Kšœ>˜>K˜—Kšžœ˜—K˜K˜—Kšœ ˜ Kšœ žœ(˜7Kšœ žœ˜-Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœ˜—Kšœ˜Kšœ0˜0K˜—Kšžœ˜—K˜K˜—Kšœžœ˜šžœžœž˜!K˜š œžœ˜+Kšœ0˜0Kšœžœ˜+Kšœ žœ˜šžœžœžœžœ˜:Kšœžœ˜Kšœ%žœ˜+K˜—šžœžœžœ ž˜ Kšœ#˜#Kšœ:˜:K˜Kšžœžœ˜,Kšžœžœ&žœ˜Dšžœžœ˜&Kšžœžœ#žœ&žœ˜gKšœžœ˜Kšœ$˜$Kšžœžœžœ˜;K˜—Kšžœžœžœžœ˜Kšœžœ˜Kšœžœ˜!Kšœ!˜!Kšœ˜Kšœ%˜%Kšœ˜K˜—K˜K˜—š  œžœ˜-šžœ>žœ žœž˜VKšœžœ˜Kšœ˜Kšœ˜Kšžœ˜—K˜K˜—Kšœ&˜&Kšœžœ˜Kšœžœžœ˜K˜Kšœ$žœžœ˜0Kšœžœžœ˜K˜(Kšœ˜šžœžœž˜šœžœ(˜9šžœž˜Kšœ!˜!Kšœ!˜!Kšžœžœ˜—K˜—šœ˜Kšœžœžœ žœ˜Cšžœ ž˜Kšœ!˜!Kšœ!˜!Kšœ%˜%Kšžœžœ˜—K˜—šžœ˜ šžœ>žœ žœž˜VKšœžœ˜Kšžœ˜—Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜——Kšžœ˜—Kšœ˜K˜K˜—š œžœ-˜:šžœžœžœžœžœžœžœ˜Kšœ-˜-Kšœ%˜%Kšžœ žœžœ*˜AKšœ˜Kšœ˜—Kšœ˜K˜——™ š œžœžœžœ˜&K˜—š  œžœžœžœ%˜ZKšœ˜Kšœ˜K™—š  œžœžœ7žœ!˜uKšœžœ˜Kšœ5˜5šžœ0žœ žœž˜IKšžœ'žœžœ ˜QKšžœ:˜>Kšžœ˜—Kšœžœ'˜2Kšœ˜šžœ&žœžœž˜:KšœE˜Ešžœžœžœ˜Kšœ4˜4Kšœ ˜ K˜—šžœ˜Kšœ žœ˜&šžœžœžœž˜-Kšœ7˜7Kšžœ˜—Kšœ4˜4K˜—Kšžœ˜—K˜K˜—š  œžœžœ7žœ˜mKšœ žœB˜Qšžœžœžœ˜K˜š œžœ˜+Kšœ˜Kšœ˜KšœB˜BKšœ žœ:˜Kšžœ žœžœ˜š žœ žœž œžœž˜0Kšœ˜Kšžœ˜—K˜—šžœ žœ˜Kšœ˜Kšœ˜Kš œ žœžœžœžœ&˜Z—K˜K˜—š  œžœžœ žœžœ žœžœ žœ ˜sKšžœžœ ž˜,š žœžœ žœžœž˜+Kšœ=˜=Kšžœ žœ žœžœ˜%šžœ žœžœ žœ˜%Kšœ˜Kšœ˜Kšœ žœ8˜Išžœ žœžœž˜$Kšœ5˜5Kšžœ˜—šžœ žœžœ˜šœ žœ˜Kšœ˜Kšœ˜Kšœ7˜7—Kšœ žœ˜K˜—Kšžœ˜K˜—Kšžœ˜—Kšœ˜K˜—Kšœžœ˜7Kšœžœ˜9Kšœ˜Kšœ˜šžœžœžœ˜Kšœ ˜ Kšœ˜KšœC˜CKšœ[˜[Kš œ žœžœžœžœžœ5˜yKšœ˜Kšžœžœžœžœ˜BK˜—Kšœ˜KšžœžœJžœžœ˜[K˜—Kšœ˜K˜—š œžœžœ;žœ žœžœžœ˜uKšœ!žœE˜lKšžœžœžœžœ˜1Kšœ˜Kšœ˜K™—š œžœ'žœ˜HK˜šŸ œ˜(Kšœ!žœ˜-šžœžœžœ˜ Kšœm˜mKšœžœ˜4šžœžœžœž˜!Kšœi˜iKšžœ˜—K˜—Kšœ0˜0K˜K˜—šŸ œ˜$Kšœžœ˜!Kš œžœžœžœžœ&žœ6˜œK˜K˜—š œžœžœžœ˜NKšœžœ#˜,šžœžœžœž˜!Kšœ žœ˜+Kšžœ˜—K˜K˜—š œžœžœžœ!˜SKšœžœ(˜1šžœžœžœž˜!Kšœ žœ˜+Kšžœ˜—K˜K˜—š œžœ˜4šžœžœžœž˜ Kšœ˜Kšžœ%žœžœ&˜hšžœžœžœž˜&K˜KšœK˜KKšžœ$žœK˜uKšžœ˜—Kšžœ˜—K˜K˜—Kšžœžœžœ˜KšœL˜LKšœD˜DKšœžœ˜;šžœžœžœž˜"KšœC˜CKšžœ˜—Kšœ0˜0K˜K˜—š  œžœžœ!žœ˜@K˜šŸ œ˜(Kšœ!žœ˜-Kšžœžœžœ_˜}Kšœ,˜,K˜K˜—šŸ œ˜$Kšœžœ˜!šžœžœžœ˜#Kšœžœ˜7Kšœ˜K˜—šžœ˜Kšœžœ˜4Kšœ$˜$šžœžœžœ!ž˜2Kšœ%˜%Kšžœ˜—K˜—K˜K˜—š œžœ˜0šžœžœžœž˜ Kšœ˜Kšžœ%žœ-˜Xšžœžœžœž˜&K˜Kšœ6˜6Kšœ?˜?K˜6Kšœ?˜?šžœžœžœž˜/Kšœ"˜"Kšžœ$žœ#˜MKšžœ˜—Kšžœ˜—Kšžœ˜—K˜K˜—KšœL˜LKšœD˜DKšœR˜RKšœ,˜,K˜K˜—š  œžœžœ!žœ˜BK˜šŸ œ˜(Kšœ!žœ˜-Kšžœžœžœ_˜}Kšœ/˜/Kšœ8˜8Kšœ+˜+K˜K˜—šŸ œ˜$Kšœžœ˜!šžœžœžœ˜#Kšœžœ˜7Kšœ˜Kšœ2˜2Kšœ!žœ˜%Kšžœžœžœ7˜WKšœ ˜ Kšœ%žœžœ˜1K˜—šžœ˜Kšœžœ˜4Kšœ$˜$šžœžœžœ!ž˜2Kšœ%˜%Kšžœ˜—K˜—Kšœ$žœ˜)K˜K˜—š œžœ˜3šžœžœžœž˜ Kšœ˜Kšžœ%žœ-˜Xšžœžœžœž˜&K˜KšœA˜AKšœ4˜4KšœA˜AKšœ4˜4šžœžœžœž˜/Kšœ"˜"Kšžœ$žœ#˜MKšžœ˜—Kšžœ˜—Kšžœ˜—K˜K˜—š œ˜Kšžœ:˜?K˜K˜—Kšœžœ˜"KšœL˜LKšœžœ˜KšœD˜DKšœR˜RKšœ/˜/K˜K˜K˜——™š  œžœžœžœžœ!˜Pšžœžœž˜Kšœ.˜.Kšœ)˜)Kšžœžœ˜—Kšœ˜K˜—š   œžœžœžœžœžœ˜>Jšœ9˜9Kšœ˜K˜—š   œžœžœžœžœ žœ˜CKšœV˜VKšœ˜K˜—š  œžœžœžœžœ%˜Xšžœžœž˜Kšœ:˜:Kšœ=˜=Kšžœžœ˜—Kšœ˜K˜—š  œžœžœžœžœžœ˜BJšœA˜AKšœ˜K˜—š  œžœžœžœžœ žœ˜GKšœb˜bKšœ˜K˜——™Kšœ1˜1šœ‘8˜QK˜—š  œžœžœ˜;Kšœ žœ˜!Kš žœžœ(žœžœžœ˜>Kšœ+˜+K˜K˜—š œžœ˜-š  œ˜(Kšœžœ˜"Kšœ˜K˜—š œ˜0Kšœ%žœ˜2Kšœ1˜1Kšœ˜K˜—š œžœ!˜8šžœžœžœž˜'Kšœ ‘-˜MKšžœ˜—K˜—Kšœ6˜6Kšœ"˜"KšœB˜BKšœ&˜&Kšœ$‘)˜MKšœ&˜&K˜ K˜K˜—š œžœ˜ Kšœ˜šžœ‘ ˜ Kšœžœ)˜5Kšžœžœ!žœžœ˜2J˜Kšœžœ˜ Kšžœ˜—K˜K˜—š œžœ˜K™:Kšœžœ˜&Kšœ(˜(K˜KšœZ˜ZKšœžœ˜ Kšžœžœ˜:K˜K˜—Kšœ˜—Kšžœ˜—…—ζn/ο