<> <> <> <> <> <> <> <<>> 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]; <> <> <> <> <<}; -- Hack>> <> <> <<}; -- Hack>> }; }; 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> NotInstantiated: PUBLIC SIGNAL = CODE; GetFlatWire: PUBLIC PROC [roseWire: RoseWire] RETURNS [flatWire: CoreFlat.FlatWireRec] = { flatWire _ roseWire.wire; }; <<>> WireValue: PUBLIC PROC [simulation: Simulation, flatWire: CoreFlat.FlatWire] RETURNS [value: Ports.LevelSequence] = { firstFreeBit: NAT _ 0; values: RoseValues _ GetValues[simulation, flatWire]; FOR countVals: RoseValues _ values, countVals.rest UNTIL countVals=NIL DO IF countVals.first.roseWire.currentValue=NIL THEN firstFreeBit _ firstFreeBit + 1 ELSE firstFreeBit _ firstFreeBit + countVals.first.fieldWidth; ENDLOOP; value _ NEW[Ports.LevelSequenceRec[firstFreeBit]]; firstFreeBit _ 0; FOR vals: RoseValues _ values, vals.rest UNTIL vals=NIL DO currentValue: Ports.LevelSequence _ vals.first.roseWire.currentValue; IF currentValue=NIL THEN { value[firstFreeBit] _ vals.first.roseWire.wireLevel; firstFreeBit _ firstFreeBit + 1; } ELSE { firstBit: NAT _ vals.first.fieldStart; FOR bit: NAT IN [0..vals.first.fieldWidth) DO value[firstFreeBit + bit] _ currentValue[firstBit+bit]; ENDLOOP; firstFreeBit _ firstFreeBit + vals.first.fieldWidth; }; ENDLOOP; }; GetValues: PUBLIC PROC [simulation: Simulation, flatWire: CoreFlat.FlatWire] RETURNS [values: RoseValues] = { values _ NARROW[RefTab.Fetch[x: simulation.coreToRoseValues, key: flatWire].val]; IF values=NIL THEN { FindHereOrBelow: PROC [wire: Core.Wire] = { roseWire: RoseWire; wireKey.wire _ wire; canonized^ _ CoreFlat.CanonizeWire[simulation.cellType, wireKey^]; roseWire _ NARROW[RefTab.Fetch[simulation.coreToRoseWires, canonized].val]; IF roseWire=NIL THEN { FOR subWire: NAT DECREASING IN [0..wire.size) DO FindHereOrBelow[wire[subWire]]; ENDLOOP; } ELSE values _ CONS[[ roseWire: roseWire, fieldStart: 0, fieldWidth: IF roseWire.currentValue=NIL THEN 1 ELSE roseWire.currentValue.size], values]; }; FindAbove: PROC [root: Core.Wire] RETURNS [foundCore: BOOL _ FALSE, foundRose: BOOL _ FALSE, firstBit: NAT _ 0] = { IF root=canonized.wire THEN foundCore _ TRUE ELSE FOR thisWire: NAT IN [0..root.size) DO [foundCore, foundRose, firstBit] _ FindAbove[root[thisWire]]; IF foundCore AND foundRose THEN EXIT; IF foundCore AND NOT foundRose THEN { roseWire: RoseWire; wireKey.wire _ root; roseWire _ NARROW[RefTab.Fetch[simulation.coreToRoseWires, wireKey].val]; FOR subWire: NAT IN [0..thisWire) DO firstBit _ firstBit + CoreOps.WireBits[root[subWire]] ENDLOOP; IF roseWire#NIL THEN { values _ CONS[[ roseWire: roseWire, fieldStart: firstBit, fieldWidth: CoreOps.WireBits[canonized.wire]], values]; foundRose _ TRUE; }; EXIT; }; ENDLOOP; }; wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; canonized: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; wireKey^ _ flatWire^; FindHereOrBelow[flatWire.wire]; IF values=NIL THEN { parent, wireCell: Core.CellType; wireRoot: Core.Wire; canonized^ _ CoreFlat.CanonizeWire[simulation.cellType, flatWire^]; [parent,,wireCell] _ CoreFlat.ResolveFlatCellType[simulation.cellType, canonized.flatCell]; wireRoot _ IF parent=NIL THEN simulation.cellType.public ELSE NARROW[wireCell.data, CoreClasses.RecordCellType].internal; wireKey^ _ canonized^; IF NOT FindAbove[wireRoot].foundRose THEN ERROR NotInstantiated[]; }; wireKey^ _ flatWire^; IF NOT RefTab.Insert[x: simulation.coreToRoseValues, key: wireKey, val: values] THEN ERROR; }; }; GetState: PUBLIC PROC [simulation: Simulation, flatCell: CoreFlat.FlatCellType] RETURNS [stateAny: REF ANY _ NIL] = { roseInstance: RoseCellInstance _ NARROW[RefTab.Fetch[x: simulation.coreToRoseInstances, key: flatCell].val]; IF roseInstance=NIL THEN ERROR NotInstantiated[]; stateAny _ roseInstance.state; }; <<>> AllocateStatePoints: PROC [simulation: Simulation, statePoints: NAT] = { InstanceState: RefTab.EachPairAction = { roseInstance: RoseCellInstance _ NARROW[val]; IF roseInstance.state#NIL THEN { cellType: Core.CellType _ CoreFlat.ResolveFlatCellType[ simulation.cellType, roseInstance.instance].cellType; roseInstance.statePoints _ NEW[SRASeq[statePoints]]; FOR s: NAT IN [0..statePoints) DO roseInstance.statePoints[s] _ roseInstance.roseCellType.init[cellType, roseInstance.publicPort].stateAny; ENDLOOP; }; AllocatePortBindings[roseInstance.portBindings]; }; WireState: RefTab.EachPairAction = { roseWire: RoseWire _ NARROW[val]; roseWire.statePoints _ IF roseWire.currentValue=NIL THEN NEW[Ports.LevelSequenceRec[statePoints]] ELSE AllocateLevelSequenceSeq[roseWire.currentValue.size]; }; AllocateLevelSequenceSeq: PROC [size: NAT] RETURNS [seq: LevelSequenceSeq] = { seq _ NEW[LevelSequenceSeqRec[statePoints]]; FOR s: NAT IN [0..statePoints) DO seq[s] _ NEW[Ports.LevelSequenceRec[size]]; ENDLOOP; }; AllocateDriveSequenceSeq: PROC [size: NAT] RETURNS [seq: DriveSequenceSequence] = { seq _ NEW[DriveSequenceSequenceRec[statePoints]]; FOR s: NAT IN [0..statePoints) DO seq[s] _ NEW[Ports.DriveSequenceRec[size]]; ENDLOOP; }; AllocatePortBindings: PROC [binds: PortBindings] = { FOR b: NAT IN [0..binds.size) DO bind: PortBinding _ binds[b]; IF bind.clientPort.driveType=aggregate THEN bind.statePoints _ NEW[Ports.DriveSequenceRec[statePoints]]; FOR f: NAT IN [0..bind.fields.size) DO field: Field _ bind.fields[f]; field.valueStatePoints _ AllocateLevelSequenceSeq[field.currentValue.size]; IF bind.clientPort.driveType=separate THEN field.driveStatePoints _ AllocateDriveSequenceSeq[field.currentDrive.size] ENDLOOP; ENDLOOP; }; IF statePoints=0 THEN RETURN; [] _ RefTab.Pairs[x: simulation.coreToRoseInstances, action: InstanceState]; [] _ RefTab.Pairs[x: simulation.coreToRoseWires, action: WireState]; simulation.statePoints _ NEW[PortSequenceRec[statePoints]]; FOR sp: NAT IN [0..statePoints) DO simulation.statePoints[sp] _ Ports.CreatePort[simulation.cellType]; ENDLOOP; AllocatePortBindings[simulation.publicBindings]; }; StatePoint: PUBLIC PROC [simulation: Simulation, point: NAT] = { InstanceState: RefTab.EachPairAction = { roseInstance: RoseCellInstance _ NARROW[val]; IF roseInstance.state#NIL THEN roseInstance.roseCellType.copy[from: roseInstance.state, to: roseInstance.statePoints[point]]; SavePortBindings[roseInstance.portBindings]; }; WireState: RefTab.EachPairAction = { roseWire: RoseWire _ NARROW[val]; IF roseWire.currentValue=NIL THEN { ls: Ports.LevelSequence _ NARROW[roseWire.statePoints]; ls[point] _ roseWire.wireLevel; } ELSE { sp: LevelSequenceSeq _ NARROW[roseWire.statePoints]; ls: Ports.LevelSequence _ sp[point]; FOR bit: NAT IN [0..roseWire.currentValue.size) DO ls[bit] _ roseWire.currentValue[bit]; ENDLOOP; }; }; SavePortBindings: PROC [binds: PortBindings] = { FOR b: NAT IN [0..binds.size) DO bind: PortBinding _ binds[b]; IF bind.clientPort.driveType=aggregate THEN bind.statePoints[point] _ bind.currentDrive; FOR f: NAT IN [0..bind.fields.size) DO field: Field _ bind.fields[f]; sourceValue: Ports.LevelSequence _ field.currentValue; destValue: Ports.LevelSequence _ field.valueStatePoints[point]; sourceDrive: Ports.DriveSequence _ field.currentDrive; destDrive: Ports.DriveSequence _ field.driveStatePoints[point]; FOR bit: NAT IN [0..field.currentValue.size) DO destValue[bit] _ sourceValue[bit]; IF bind.clientPort.driveType=separate THEN destDrive[bit] _ sourceDrive[bit]; ENDLOOP; ENDLOOP; ENDLOOP; }; [] _ RefTab.Pairs[x: simulation.coreToRoseInstances, action: InstanceState]; [] _ RefTab.Pairs[x: simulation.coreToRoseWires, action: WireState]; Ports.CopyPortValue[from: simulation.testPort, to: simulation.statePoints[point]]; SavePortBindings[simulation.publicBindings]; }; RestoreState: PUBLIC PROC [simulation: Simulation, point: NAT] = { InstanceState: RefTab.EachPairAction = { roseInstance: RoseCellInstance _ NARROW[val]; IF roseInstance.state#NIL THEN roseInstance.roseCellType.copy[from: roseInstance.statePoints[point], to: roseInstance.state]; RestorePortBindings[roseInstance.portBindings]; roseInstance.nextNeedEval _ simulation.instanceNeedEval; simulation.instanceNeedEval _ roseInstance; }; WireState: RefTab.EachPairAction = { roseWire: RoseWire _ NARROW[val]; IF roseWire.currentValue=NIL THEN { ls: Ports.LevelSequence _ NARROW[roseWire.statePoints]; roseWire.wireLevel _ ls[point]; roseWire.nextPerturbedWire _ simulation.perturbed; roseWire.previousPerturbedWire _ NIL; IF simulation.perturbed#NIL THEN simulation.perturbed.previousPerturbedWire _ roseWire; simulation.perturbed _ roseWire; RecomputeValue[simulation, roseWire, FALSE, NIL]; } ELSE { sp: LevelSequenceSeq _ NARROW[roseWire.statePoints]; ls: Ports.LevelSequence _ sp[point]; FOR bit: NAT IN [0..roseWire.currentValue.size) DO roseWire.currentValue[bit] _ ls[bit]; ENDLOOP; }; UpdateReaders[simulation, roseWire, NIL]; }; RestorePortBindings: PROC [binds: PortBindings] = { FOR b: NAT IN [0..binds.size) DO bind: PortBinding _ binds[b]; IF bind.clientPort.driveType=aggregate THEN bind.currentDrive _ bind.statePoints[point]; FOR f: NAT IN [0..bind.fields.size) DO field: Field _ bind.fields[f]; sourceValue: Ports.LevelSequence _ field.valueStatePoints[point]; destValue: Ports.LevelSequence _ field.currentValue; sourceDrive: Ports.DriveSequence _ field.driveStatePoints[point]; destDrive: Ports.DriveSequence _ field.currentDrive; FOR bit: NAT IN [0..field.currentValue.size) DO destValue[bit] _ sourceValue[bit]; IF bind.clientPort.driveType=separate THEN destDrive[bit] _ sourceDrive[bit]; ENDLOOP; ENDLOOP; ENDLOOP; }; Complain: UpdateProc = { ERROR Stop["State restoration failed, notify Rosemary wizard"]; }; simulation.instanceNeedEval _ NIL; [] _ RefTab.Pairs[x: simulation.coreToRoseInstances, action: InstanceState]; simulation.perturbed _ NIL; [] _ RefTab.Pairs[x: simulation.coreToRoseWires, action: WireState]; Ports.CopyPortValue[from: simulation.statePoints[point], to: simulation.testPort]; RestorePortBindings[simulation.publicBindings]; Settle[simulation, Complain]; }; <> RoseWireHashNarrow: PROC [key: REF ANY] RETURNS [flat: CoreFlat.FlatWireRec] = { WITH key SELECT FROM wireKey: CoreFlat.FlatWire => 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.