RosemaryImpl.mesa
Copyright © 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
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;
EUWireTrap: CoreFlat.FlatWireRec; -- Hack
EUGndWireTrap: CoreFlat.FlatWireRec; -- Hack
hackWireData: REF ANY; -- Hack
hackChannels: CARDINAL ← 0; -- Hack
maxHackChannels: CARDINAL ← 0; -- Hack
TrapEnable: BOOLFALSE; -- Hack
HackStop: SIGNAL = CODE; -- Hack
sizeHackEnable: BOOLFALSE; -- 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: ROPENIL, data: REF ANYNIL, reason: ATOM ← $Client] = CODE;
Behaviour Registration
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: BOOLFALSE] 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;
};
Instantiation
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: BOOLFALSE] 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 {
IF EUWireTrap.wire=key THEN SIGNAL HackStop; -- Hack
wireData ← NEW[WireDataRec];
IF NOT RefTab.Insert[x: wireTable, key: key, val: wireData] THEN ERROR;
};
IF wireData.valid THEN wireData.multiInPointers ← TRUE
ELSE {
IF EUWireTrap.wire=key THEN SIGNAL HackStop; -- Hack
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;
};
IF EUWireTrap.wire=wire THEN TrapEnable ← TRUE; -- Hack
};
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];
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
};
};
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];
IF enableHack THEN IF CoreFlat.InstancePathEqual[flatCell.path, hackWireCellPath] THEN SIGNAL HackStop[]; -- Hack
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];
IF enableHack THEN IF CoreFlat.FlatCellTypeEqualRec[flatCell, hackCell] THEN SIGNAL HackStop[]; -- Hack
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: BOOLFALSE] RETURNS [public: BOOLFALSE, allocated: BOOLFALSE] = {
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: BOOLFALSE;
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;
};
};
};
IF EUWireTrap.wire=wire THEN SIGNAL HackStop; -- Hack
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: NATIF 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: BOOLFALSE,
multiInPointers: BOOLFALSE,
connections: CARDINAL ← 0,
channels: CARDINAL ← 0,
gates: CARDINAL ← 0,
portLeaf: BOOLFALSE,
boolPort: BOOLFALSE,
allocated: BOOLFALSE];
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];
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
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: BOOLFALSE] = {
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: ROPENARROW[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;
};
Relaxation
Initialize: PUBLIC PROC [simulation: Simulation, steady: BOOLTRUE, 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: BOOLFALSE;
someNotForce: BOOLFALSE;
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: BOOLFALSE;
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: BOOLTRUE, clockEval: BOOLFALSE, 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: BOOLFALSE;
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: BOOLTRUE, 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: BOOLFALSE;
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: BOOLFALSE;
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: BOOLFALSE;
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: BOOLTRUE] = {
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: BOOLFALSE;
infiniteValue: Ports.Level ← X;
singleInfiniteNoUnknownConductance: BOOLTRUE;
allSameValue: BOOLTRUE;
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<infinite THEN {
currentHead: RoseWire ← simulation.perturbed;
wire.nextPerturbedWire ← currentHead;
IF currentHead#NIL THEN currentHead.previousPerturbedWire ← wire;
simulation.perturbed ← wire;
};
};
State Access
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: BOOLFALSE, foundRose: BOOLFALSE, 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 ANYNIL] = {
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];
};
Hash Table Utilities
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]];
};
Garbage Collection
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 [] ~ {
Initialization of the finalization of Rosemary simulations
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.