RosemaryImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Barth, June 16, 1986 5:06:41 pm PDT
Louis Monier May 22, 1986 10:43:02 am PDT
DIRECTORY Basics, Core, CoreClasses, CoreFlat, CoreIO, CoreOps, CoreProperties, HashTable, Ports, Process, Rope, Rosemary, SymTab;
RosemaryImpl: CEDAR PROGRAM
IMPORTS Basics, CoreClasses, CoreFlat, CoreIO, CoreOps, CoreProperties, HashTable, Ports, Process, Rope, SymTab
EXPORTS Rosemary
= BEGIN OPEN Rosemary;
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];
roseCutSetProp: ATOM = CoreProperties.RegisterProperty[prop: $RoseCutSet];
roseWireDataProp: ATOM = CoreIO.RegisterProperty[prop: CoreProperties.RegisterProperty[prop: $RoseWireData], write: RoseWireDataWrite, read: RoseWireDataRead];
RoseWireDataWrite: CoreIO.PropWriteProc = {
roseWireData: RoseWireData ← NARROW[value];
CoreIO.WriteID[h, Ports.levelNames[roseWireData.value]];
CoreIO.WriteID[h, Ports.driveNames[roseWireData.size]];
};
RoseWireDataRead: CoreIO.PropReadProc = {
roseWireData: RoseWireData ← NEW[RoseWireDataRec];
roseWireData.value ← Ports.FindLevel[CoreIO.ReadID[h]];
roseWireData.size ← Ports.FindDrive[CoreIO.ReadID[h]];
value ← roseWireData;
};
roseFixedWireProp: ATOM = CoreIO.RegisterProperty[prop: CoreProperties.RegisterProperty[prop: $RoseFixedWire], write: RoseFixedWireWrite, read: RoseFixedWireRead];
RoseFixedWireWrite: CoreIO.PropWriteProc = {
level: REF Ports.Level ← NARROW[value];
CoreIO.WriteID[h, Ports.levelNames[level^]];
};
RoseFixedWireRead: CoreIO.PropReadProc = {
level: REF Ports.Level ← NEW[Ports.Level];
level^ ← Ports.FindLevel[CoreIO.ReadID[h]];
value ← level;
};
roseTransistorSizeProp: ATOM = CoreIO.RegisterProperty[prop: CoreProperties.RegisterProperty[prop: $RoseTransistorSize], write: RoseTransistorSizeWrite, read: RoseTransistorSizeRead];
RoseTransistorSizeWrite: CoreIO.PropWriteProc = {
size: REF Ports.Drive ← NARROW[value];
CoreIO.WriteID[h, Ports.driveNames[size^]];
};
RoseTransistorSizeRead: CoreIO.PropReadProc = {
size: REF Ports.Drive ← NEW[Ports.Drive];
size^ ← Ports.FindDrive[CoreIO.ReadID[h]];
value ← size;
};
roseClassTable: SymTab.Ref ← SymTab.Create[];
Stop: PUBLIC SIGNAL [msg: ROPE, data: REF ANYNIL] = CODE;
Behaviour
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] RETURNS [sameRoseClassName: ROPE] = {
found: BOOL;
val: REF ANY;
[found, val] ← SymTab.Fetch[x: roseClassTable, key: roseClassName];
IF found THEN {
rct: RoseCellType ← NARROW[val];
rct.init ← init;
rct.evalSimple ← evalSimple;
}
ELSE [] ← SymTab.Store[x: roseClassTable, key: roseClassName, val: NEW[RoseCellTypeRec ← [init: init, evalSimple: evalSimple]]];
sameRoseClassName ← roseClassName;
};
Instantiation
AddCutSets: PUBLIC PROC [cellType: Core.CellType, cs1, cs2, cs3, cs4, cs5, cs6: ROPENIL] RETURNS [sameCellType: Core.CellType] = {
cutSetList: LIST OF ROPENARROW[CoreProperties.GetCellTypeProp[from: cellType, prop: roseCutSetProp]];
IF cs1#NIL THEN cutSetList ← CONS[cs1, cutSetList];
IF cs2#NIL THEN cutSetList ← CONS[cs2, cutSetList];
IF cs3#NIL THEN cutSetList ← CONS[cs3, cutSetList];
IF cs4#NIL THEN cutSetList ← CONS[cs4, cutSetList];
IF cs5#NIL THEN cutSetList ← CONS[cs5, cutSetList];
IF cs6#NIL THEN cutSetList ← CONS[cs6, cutSetList];
CoreProperties.PutCellTypeProp[on: cellType, prop: roseCutSetProp, value: cutSetList];
sameCellType ← cellType;
};
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] RETURNS [sameWire: Core.Wire] = {
CoreProperties.PutWireProp[on: wire, prop: roseWireDataProp, value: NEW[RoseWireDataRec ← [level, size]]];
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;
};
InstantiateCellType: PUBLIC PROC [cellType: Core.CellType, testPort: Ports.Port, statePoints: NAT ← 0] RETURNS [simulation: Simulation] = {
Wire: HashTable.EachPairAction = {
roseWire: RoseWire ← NARROW[value];
IF roseWire.wireDrive=infinite THEN UpdateReaders[simulation, roseWire, NIL];
};
ComputeCellTypeBindings: PROC [port: Ports.Port, wire: Core.Wire, wireToRoseWire: HashTable.Table, binds: PortBindings, firstFreeBinding: CARDINAL, instance: RoseCellInstance ← NIL] RETURNS [newFirstFreeBinding: CARDINAL] = {
wireKey.wire ← wire;
newFirstFreeBinding ← firstFreeBinding;
IF port.type=composite THEN {
FOR subPort: NAT IN [0..port.size) DO
newFirstFreeBinding ← ComputeCellTypeBindings[port[subPort], wire[subPort], wireToRoseWire, binds, newFirstFreeBinding, instance];
ENDLOOP;
}
ELSE {
thisRoseWire: RoseWire ← NARROW[HashTable.Fetch[table: wireToRoseWire, key: wireKey].value];
portBinding: PortBinding ← NEW[PortBindingRec ← [
instance: instance,
clientPort: port,
fields: NEW[FieldSeq[1]],
currentDrive: port.d]];
field: Field ← NEW[FieldRec ← [
portBinding: portBinding,
roseWire: thisRoseWire]];
portBinding.fields[0] ← field;
field.currentValue ← AllocateLevelSequence[IF thisRoseWire.currentValue=NIL THEN 1 ELSE thisRoseWire.currentValue.size];
binds[newFirstFreeBinding] ← portBinding;
newFirstFreeBinding ← newFirstFreeBinding + 1;
IF thisRoseWire.connections[0]=NIL THEN thisRoseWire.connections[0] ← field ELSE thisRoseWire.connections[1] ← field;
};
};
roseInstance: RoseCellInstance ← NEW[RoseCellInstanceRec];
max: CARDINAL;
wireToRoseWire: HashTable.Table;
wireKey: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec];
simulation ← NEW[SimulationRec];
simulation.coreToValues ← HashTable.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash];
simulation.coreCellType ← cellType;
wireToRoseWire ← simulation.coreToRoseWires ← HashTable.Create[equal: RoseWireEqual, hash: RoseWireHash];
simulation.coreToRoseInstances ← HashTable.Create[equal: RoseInstanceEqual, hash: RoseInstanceHash];
IF NOT HashTable.Insert[table: simulation.coreToRoseInstances, key: roseInstance, value: roseInstance] THEN ERROR;
simulation.instanceNeedEval ← roseInstance;
FOR strength: Ports.Drive IN Ports.Drive DO
simulation.vicinityByStrength[strength].wires ← NEW[RoseWireSeq[1]];
ENDLOOP;
roseInstance.publicPort ← Ports.CreatePort[cellType.public];
[max, simulation.roseBoolWires] ← AllocateCellTypeRoseWires[simulation, roseInstance.publicPort, cellType.public, wireToRoseWire];
simulation.scratchValue ← NEW[Ports.LevelSequenceRec[max]];
simulation.scratchDrive ← NEW[DriveRec[max]];
roseInstance.roseCellType ← FindRoseCellType[cellType];
IF roseInstance.roseCellType.init#NIL THEN roseInstance.state ← roseInstance.roseCellType.init[cellType: cellType, p: roseInstance.publicPort];
roseInstance.portBindings ← NEW[PortBindingSeq[Ports.PortLeaves[ roseInstance.publicPort]]];
IF roseInstance.portBindings.size#ComputeCellTypeBindings[instance: roseInstance, port: roseInstance.publicPort, wire: cellType.public, wireToRoseWire: wireToRoseWire, binds: roseInstance.portBindings, firstFreeBinding: 0] THEN ERROR;
simulation.publicBindings ← NEW[PortBindingSeq[Ports.PortLeaves[testPort]]];
IF simulation.publicBindings.size#ComputeCellTypeBindings[port: testPort, wire: cellType.public, wireToRoseWire: wireToRoseWire, binds: simulation.publicBindings, firstFreeBinding: 0] THEN ERROR;
[] ← HashTable.Pairs[table: simulation.coreToRoseWires, action: Wire];
simulation.testPort ← testPort;
AllocateStatePoints[simulation, statePoints];
EstablishInvariants[simulation];
};
AllocateCellTypeRoseWires: PROC [simulation: Simulation, port: Ports.Port, public: Core.Wire, wireToRoseWire: HashTable.Table] RETURNS [maxComposite: CARDINAL ← 0, boolWires: RoseWireList ← NIL] = {
IF port.type=composite THEN {
subBools: RoseWireList;
subMax: CARDINAL;
FOR sub: NAT IN [0..port.size) DO
[subMax, subBools] ← AllocateCellTypeRoseWires[simulation, port[sub], public[sub], wireToRoseWire];
maxComposite ← MAX[subMax, maxComposite];
FOR bools: RoseWireList ← subBools, bools.rest UNTIL bools=NIL DO
boolWires ← CONS[bools.first, boolWires];
ENDLOOP;
ENDLOOP;
}
ELSE {
roseWire: RoseWire;
wireSize: NAT;
fixed: BOOL;
[fixed, wireSize, roseWire] ← InitWire[public];
roseWire.connections ← NEW[FieldSeq[2]];
IF NOT HashTable.Insert[table: wireToRoseWire, key: roseWire, value: roseWire] THEN ERROR;
IF wireSize>1 THEN maxComposite ← wireSize;
IF port.type=b OR port.type=bs OR port.type=c OR port.type=lc THEN boolWires ← CONS[roseWire, boolWires];
};
};
InitWire: PROC [coreWire: Core.Wire] RETURNS [fixed: BOOL, wireSize: NAT, roseWire: RoseWire] = {
FetchValue: PROC [wire: Core.Wire] RETURNS [wireDrive: Ports.Drive ← charge, wireLevel: Ports.Level ← L] = {
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;
};
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.VisitAtomicWires[coreWire, GetValue];
}
ELSE {
[roseWire.wireDrive, roseWire.wireLevel] ← FetchValue[coreWire];
roseWire.switchDrive ← roseWire.wireDrive;
};
roseWire.wire.wire ← coreWire;
};
InstantiateInstances: PUBLIC PROC [cellType: Core.CellType, testPort: Ports.Port, cutSets: LIST OF ROPENIL, statePoints: NAT ← 0] RETURNS [simulation: Simulation] = {
ComputeInDegree: PROC [bindings: HashTable.Table, path: CoreFlat.PackedPath, wire: Core.Wire] = {
bind: CoreFlat.WireBind ← NARROW[HashTable.Fetch[table: bindings, key: wire].value];
wireData: WireData ← NARROW[bind.data];
IF wireData=NIL THEN {
wireData ← NEW[WireDataRec];
bind.data ← wireData;
};
IF wireData.indegree=0 THEN {
wireData.indegree ← 1;
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[bindings, path, wire[sub]];
ENDLOOP;
}
ELSE wireData.indegree ← wireData.indegree + 1;
};
MarkPortLeavesCountConnections: PROC [bindings: HashTable.Table, actual: Core.Wire, public: Core.Wire, checkPort: BOOL, visited: HashTable.Table, type: Ports.PortType ← composite] = {
actualBind: CoreFlat.WireBind ← NARROW[HashTable.Fetch[table: bindings, key: actual].value];
actualData: WireData ← NARROW[actualBind.data];
IF NOT HashTable.Fetch[table: visited, key: public].found THEN {
actualData.connections ← actualData.connections + 1;
IF checkPort THEN {
type ← Ports.WirePortType[public];
IF type # composite THEN {
actualData.portLeaf ← TRUE;
checkPort ← FALSE;
};
};
FOR sub: NAT IN [0..actual.size) DO
MarkPortLeavesCountConnections[bindings, actual[sub], public[sub], checkPort, visited, type];
ENDLOOP;
IF NOT HashTable.Insert[table: visited, key: public, value: $Visited] THEN ERROR;
};
IF type=b OR type=bs OR type=c OR type=lc THEN actualData.boolPort ← TRUE;
};
ComputeBindings: PROC [bindings: HashTable.Table, path: CoreFlat.PackedPath, port: Ports.Port, wire: Core.Wire, binds: PortBindings, firstFreeBinding: CARDINAL, instance: RoseCellInstance ← NIL] RETURNS [newFirstFreeBinding: CARDINAL] = {
newFirstFreeBinding ← firstFreeBinding;
IF port.type=composite THEN {
FOR subPort: NAT IN [0..port.size) DO
newFirstFreeBinding ← ComputeBindings[bindings, path, port[subPort], wire[subPort], binds, newFirstFreeBinding, instance];
ENDLOOP;
}
ELSE {
portBinding: PortBinding ← NEW[PortBindingRec ← [
clientPort: port,
currentDrive: port.d,
instance: instance]];
portBinding.fields ← NEW[FieldSeq[CountFields[bindings: bindings, path: path, wire: wire, bound: HashTable.Create[]]]];
[] ← ComputeFields[bindings: bindings, path: path, wire: wire, portBinding: portBinding, valueStart: 0, bound: HashTable.Create[], firstFreeField: 0];
binds[newFirstFreeBinding] ← portBinding;
newFirstFreeBinding ← newFirstFreeBinding + 1;
};
};
CountFields: PROC [bindings: HashTable.Table, path: CoreFlat.PackedPath, wire: Core.Wire, bound: HashTable.Table] RETURNS [fieldCount: CARDINAL ← 0] = {
IF LookUpRoseWire[bindings, path, wire]=NIL THEN {
FOR subWire: NAT IN [0..wire.size) DO
fieldCount ← fieldCount + CountFields[bindings, path, wire[subWire], bound];
ENDLOOP;
}
ELSE {
IF NOT HashTable.Fetch[table: bound, key: wire].found THEN {
fieldCount ← 1;
IF NOT HashTable.Insert[table: bound, key: wire, value: $Bound] THEN ERROR;
};
};
};
ComputeFields: PROC [bindings: HashTable.Table, path: CoreFlat.PackedPath, wire: Core.Wire, portBinding: PortBinding, valueStart: NAT, bound: HashTable.Table, firstFreeField: CARDINAL] RETURNS [newFirstFreeField: CARDINAL, newValueStart: NAT] = {
roseWire: RoseWire ← LookUpRoseWire[bindings, path, wire];
newValueStart ← valueStart;
newFirstFreeField ← firstFreeField;
IF roseWire = NIL THEN {
FOR subWire: NAT IN [0..wire.size) DO
[newFirstFreeField, newValueStart] ← ComputeFields[bindings, path, wire[subWire], portBinding, newValueStart, bound, newFirstFreeField];
ENDLOOP;
}
ELSE {
IF NOT HashTable.Fetch[table: bound, key: wire].found THEN {
field: Field ← NEW[FieldRec ← [
portBinding: portBinding,
portStartBit: valueStart,
roseWire: roseWire,
currentValue: AllocateLevelSequence[IF roseWire.currentValue=NIL THEN 1 ELSE roseWire.currentValue.size]]];
FOR bit: NAT IN [0..field.currentValue.size) DO
field.currentValue[bit] ← L;
ENDLOOP;
portBinding.fields[firstFreeField] ← field;
newFirstFreeField ← newFirstFreeField + 1;
newValueStart ← newValueStart + field.currentValue.size;
FOR f: NAT IN [0..roseWire.connections.size) DO
IF roseWire.connections[f]=NIL THEN {
roseWire.connections[f] ← field;
EXIT;
};
REPEAT
FINISHED => ERROR;
ENDLOOP;
IF NOT HashTable.Insert[table: bound, key: wire, value: $Bound] THEN ERROR;
};
};
};
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;
};
LookUpRoseWire: PROC [bindings: HashTable.Table, path: CoreFlat.PackedPath, wire: Core.Wire] RETURNS [roseWire: RoseWire] = {
roseWire ← FindRoseWire[simulation, bindings, wire, wireKey];
};
InsertRootPublics: CoreFlat.EachCellTypeProc = {
public: Core.Wire ← cellType.public;
visited: HashTable.Table ← HashTable.Create[];
FOR i: NAT IN [0..public.size) DO
ComputeInDegree[bindings, path, public[i]];
ENDLOOP;
FOR i: NAT IN [0..public.size) DO
MarkPortLeavesCountConnections[bindings, public[i], public[i], TRUE, visited];
ENDLOOP;
};
InsertInternals: CoreFlat.EachCellTypeProc = {
cellTypeRCT: CoreClasses.RecordCellType ← NARROW[cellType.data];
internal: Core.Wire ← cellTypeRCT.internal;
FOR i:NAT IN [0..internal.size) DO
ComputeInDegree[bindings, path, internal[i]];
ENDLOOP;
};
GatherWireData: CoreFlat.EachInstanceProc = {
LookupBind: PROC [wire: Core.Wire] RETURNS [wireData: WireData] = {
bind: CoreFlat.WireBind ← NARROW[HashTable.Fetch[table: bindings, key: wire].value];
wireData ← NARROW[bind.data];
wireData.portLeaf ← TRUE;
};
member, transistor: BOOL;
subType: Core.CellType;
[member, transistor, subType] ← CutSetMember[path, instance, cutSets];
flatten ← NOT member;
IF member THEN {
actual: Core.Wire ← instance.actual;
IF transistor THEN {
wireData: WireData ← LookupBind[actual[gate]];
wireData.gates ← wireData.gates + 1;
wireData ← LookupBind[actual[ch1]];
wireData.channels ← wireData.channels + 1;
wireData ← LookupBind[actual[ch2]];
wireData.channels ← wireData.channels + 1;
}
ELSE {
visited: HashTable.Table ← HashTable.Create[];
FOR i: NAT IN [0..actual.size) DO
MarkPortLeavesCountConnections[bindings: bindings, actual: actual[i], public: instance.type.public[i], checkPort: TRUE, visited: visited]
ENDLOOP;
};
}
};
AllocateWires: CoreFlat.EachCellTypeProc = {
AllocateRoseWires: PROC [wire: Core.Wire] RETURNS [public: BOOLFALSE, allocated: BOOLFALSE] = {
AllocateWire: PROC [wire: Core.Wire, wireData: WireData] = {
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;
};
};
roseWire: RoseWire;
wireSize: NAT;
fixed: BOOL;
[fixed, wireSize, roseWire] ← InitWire[wire];
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.gates ← AllocateTransistorPointers[wireData.gates];
};
roseWire.wire.path ← path;
IF NOT HashTable.Insert[table: simulation.coreToRoseWires, key: roseWire, value: roseWire] THEN ERROR;
maxRoseWireSize ← MAX[maxRoseWireSize, wireSize];
IF wireData.boolPort THEN simulation.roseBoolWires ← CONS[roseWire, simulation.roseBoolWires];
wireData.allocated ← TRUE;
};
bind: CoreFlat.WireBind ← NARROW[HashTable.Fetch[table: bindings, key: wire].value];
wireData: WireData ← NARROW[bind.data];
IF NOT (public ← NOT CoreFlat.PathEqual[bind.path, path]) THEN {
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]];
allocated ← allocated OR subAllocated;
somePublic ← somePublic OR subPublic;
ENDLOOP;
IF allocated OR somePublic THEN {
FOR sub: NAT IN [0..wire.size) DO
subBind: CoreFlat.WireBind ← NARROW[HashTable.Fetch[table: bindings, key: wire[sub]].value];
subWireData: WireData ← NARROW[subBind.data];
IF (NOT subWireData.allocated) AND CoreFlat.PathEqual[subBind.path, path] THEN AllocateWire[wire[sub], subWireData];
ENDLOOP;
wireData.allocated ← TRUE;
}
ELSE {
IF wireData.indegree>1 OR wireData.portLeaf THEN {
AllocateWire[wire, wireData];
allocated ← TRUE;
};
};
};
wireData.indegree ← 0;
};
};
cellTypeRCT: CoreClasses.RecordCellType ← NARROW[cellType.data];
internal: Core.Wire ← cellTypeRCT.internal;
FOR i: NAT IN [0..internal.size) DO
[] ← AllocateRoseWires[internal[i]];
ENDLOOP;
};
CreateRootBindings: CoreFlat.EachCellTypeProc = {
IF simulation.publicBindings.size#ComputeBindings[bindings: bindings, path: path, port: testPort, wire: cellType.public, binds: simulation.publicBindings, firstFreeBinding: 0] THEN ERROR;
};
AllocateInstances: CoreFlat.EachInstanceProc = {
member, transistor: BOOL;
subType: Core.CellType;
[member, transistor, subType] ← CutSetMember[path, instance, cutSets];
flatten ← NOT member;
IF member THEN {
actual: Core.Wire ← instance.actual;
IF transistor THEN {
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;
};
coreTransistor: CoreClasses.Transistor ← NARROW[subType.data];
roseTransistor: RoseTransistor ← NEW[RoseTransistorRec];
transistorSizeRef: REF Ports.Drive ← NARROW[CoreProperties.GetCellInstanceProp[from: instance, prop: roseTransistorSizeProp]];
roseTransistor.gate ← LookUpRoseWire[bindings, path, actual[gate]];
InsertTransistor[roseTransistor.gate.gates];
roseTransistor.ch1 ← LookUpRoseWire[bindings, path, actual[ch1]];
InsertTransistor[roseTransistor.ch1.channels];
roseTransistor.ch2 ← LookUpRoseWire[bindings, path, actual[ch2]];
InsertTransistor[roseTransistor.ch2.channels];
IF transistorSizeRef=NIL THEN transistorSizeRef ← NARROW[CoreProperties.GetCellTypeProp[from: subType, prop: roseTransistorSizeProp]];
IF transistorSizeRef#NIL THEN roseTransistor.conductivity ← transistorSizeRef^;
roseTransistor.type ← coreTransistor.type;
}
ELSE {
roseInstance: RoseCellInstance ← NEW[RoseCellInstanceRec];
roseInstance.nextNeedEval ← simulation.instanceNeedEval;
simulation.instanceNeedEval ← roseInstance;
roseInstance.roseCellType ← FindRoseCellType[subType];
roseInstance.publicPort ← Ports.CreatePort[wire: subType.public];
roseInstance.portBindings ← NEW[PortBindingSeq[Ports.PortLeaves[ roseInstance.publicPort]]];
IF roseInstance.portBindings.size#ComputeBindings[bindings: bindings, path: path, port: roseInstance.publicPort, wire: actual, binds: roseInstance.portBindings, firstFreeBinding: 0, instance: roseInstance] THEN ERROR;
IF roseInstance.roseCellType.init#NIL THEN roseInstance.state ← roseInstance.roseCellType.init[cellType: subType, p: roseInstance.publicPort];
roseInstance.instance.path ← path;
roseInstance.instance.instance ← instance;
IF NOT HashTable.Insert[table: simulation.coreToRoseInstances, key: roseInstance, value: roseInstance] THEN ERROR;
};
};
};
ComputeMaxVicinity: HashTable.EachPairAction = {
roseWire: RoseWire ← NARROW[value];
IF roseWire.wireDrive=infinite THEN UpdateReaders[simulation, roseWire, NIL]
ELSE IF NOT roseWire.mark THEN maxVicinity ← MAX[maxVicinity, CountVicinity[roseWire]];
};
WireData: TYPE = REF WireDataRec;
WireDataRec: TYPE = RECORD [
indegree: CARDINAL ← 0,
connections: CARDINAL ← 0,
channels: CARDINAL ← 0,
gates: CARDINAL ← 0,
portLeaf: BOOLFALSE,
boolPort: BOOLFALSE,
allocated: BOOLFALSE];
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];
simulation ← NEW[SimulationRec];
simulation.coreCellType ← cellType;
simulation.testPort ← testPort;
simulation.publicBindings ← NEW[PortBindingSeq[Ports.PortLeaves[testPort]]];
simulation.coreToRoseWires ← HashTable.Create[mod: 1024, equal: RoseWireEqual, hash: RoseWireHash];
simulation.coreToRoseInstances ← HashTable.Create[equal: RoseInstanceEqual, hash: RoseInstanceHash];
simulation.coreToValues ← HashTable.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash];
CoreFlat.EnumerateLeaves[root: cellType, rootCellType: InsertRootPublics, beforeInstances: InsertInternals, eachInstance: GatherWireData, afterInstances: AllocateWires];
CoreFlat.EnumerateLeaves[root: cellType, rootCellType: CreateRootBindings, eachInstance: AllocateInstances];
simulation.scratchValue ← NEW[Ports.LevelSequenceRec[maxRoseWireSize]];
simulation.scratchDrive ← NEW[DriveRec[maxRoseWireSize]];
[] ← HashTable.Pairs[table: 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];
};
EstablishInvariants: PROC [simulation: Simulation] = {
Instance: HashTable.EachPairAction = {
roseInstance: RoseCellInstance ← NARROW[value];
CleanUp[simulation: simulation, bindings: roseInstance.portBindings, forceUpdate: TRUE, updateProc: NIL];
};
Wire: HashTable.EachPairAction = {
roseWire: RoseWire ← NARROW[value];
roseWire.mark ← FALSE;
IF roseWire.connections#NIL THEN RecomputeValue[simulation: simulation, wire: roseWire, forceReaderUpdate: TRUE, updateProc: NIL];
Perturb[simulation, roseWire];
};
CleanUp[simulation: simulation, bindings: simulation.publicBindings, forceUpdate: TRUE, updateProc: NIL];
[] ← HashTable.Pairs[table: simulation.coreToRoseInstances, action: Instance];
[] ← HashTable.Pairs[table: simulation.coreToRoseWires, action: Wire];
};
FindRoseCellType: PROC [cellType: Core.CellType] RETURNS [roseCellType: RoseCellType] = {
roseClassName: ROPENARROW[CoreProperties.GetCellTypeProp[from: cellType, prop: roseBehaveProp]];
found: BOOL;
val: REF ANY;
IF roseClassName=NIL THEN roseClassName ← NARROW[CoreProperties.GetCellClassProp[from: cellType.class, prop: roseBehaveProp]];
[found, val] ← SymTab.Fetch[roseClassTable, roseClassName];
roseCellType ← NARROW[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;
};
Initialize: PUBLIC PROC [simulation: Simulation, steady: BOOLTRUE] = {
SetX: HashTable.EachPairAction = {
roseWire: RoseWire ← NARROW[value];
IF roseWire.wireDrive=infinite THEN RETURN;
IF roseWire.currentValue=NIL THEN roseWire.wireLevel ← X
ELSE FOR bit: NAT IN [0..roseWire.currentValue.size) DO
roseWire.currentValue[bit] ← X;
ENDLOOP;
};
IF steady THEN ERROR; -- not implemented
[] ← HashTable.Pairs[table: simulation.coreToRoseWires, action: SetX];
EstablishInvariants[simulation];
};
Relaxation
Settle: PUBLIC PROC [simulation: Simulation, updateProc: UpdateProc ← NIL] = {
priority: Process.Priority ← Process.GetPriority[];
Process.SetPriority[Process.priorityBackground];
{
ENABLE UNWIND => Process.SetPriority[priority];
CleanUp[simulation: simulation, bindings: simulation.publicBindings, updateProc: updateProc];
UNTIL simulation.instanceNeedEval=NIL AND simulation.perturbed=NIL DO
UNTIL simulation.instanceNeedEval=NIL DO
instance: RoseCellInstance ← simulation.instanceNeedEval;
simulation.instanceNeedEval ← instance.nextNeedEval;
instance.nextNeedEval ← NIL;
instance.roseCellType.evalSimple[p: instance.publicPort, stateAny: instance.state];
CleanUp[simulation: simulation, bindings: instance.portBindings, updateProc: updateProc];
Process.CheckForAbort[];
ENDLOOP;
UpdatePerturbed[simulation: simulation, updateProc: updateProc];
Process.CheckForAbort[];
ENDLOOP;
{
noMore: BOOLFALSE;
FOR roseWires: LIST OF RoseWire ← simulation.roseBoolWires, roseWires.rest UNTIL roseWires=NIL DO
roseWire: RoseWire ← roseWires.first;
IF roseWire.currentValue=NIL THEN {
IF roseWire.wireLevel=X THEN SIGNAL Stop["Wire with bool port settled to an X", $BoolWireHasX];
}
ELSE FOR bit: CARDINAL IN [0..roseWire.currentValue.size) DO
IF roseWire.currentValue[bit]=X THEN SIGNAL Stop["Wire with bool port settled to an X", $BoolWireHasX];
IF noMore THEN EXIT;
ENDLOOP;
IF noMore THEN EXIT;
ENDLOOP;
};
};
Process.SetPriority[priority];
};
CleanUp: PROC [simulation: Simulation, bindings: PortBindings, forceUpdate: BOOLFALSE, 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.type FROM
l, b => {
field: Field ← bind.fields[0];
changeValue: BOOLFALSE;
clientLevel: Ports.Level ← IF client.type=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 changeDrive OR changeValue OR forceUpdate THEN RecomputeValue[simulation, field.roseWire, forceUpdate, updateProc];
};
ls, bs, c, lc => {
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;
FOR bit: NAT IN [0..fieldValue.size) DO
thisBit: NAT ← bit+fieldStart;
clientLevel: Ports.Level ← SELECT client.type 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,
ENDCASE => ERROR;
IF fieldValue[bit]#clientLevel THEN {
changeValue ← TRUE;
fieldValue[bit] ← clientLevel;
};
ENDLOOP;
UpdateReader[simulation, field];
IF changeDrive OR changeValue OR forceUpdate THEN RecomputeValue[simulation, field.roseWire, forceUpdate, 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 ← wire.wireLevel;
scratchDrive: Ports.Drive ← wire.wireDrive;
FOR writers: CARDINAL IN [0..wire.connections.size) DO
writer: Field ← wire.connections[writers];
writerLevel: Ports.Level ← writer.currentValue[0];
writerDrive: Ports.Drive ← writer.portBinding.currentDrive;
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: 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;
writerDrive: Ports.Drive ← writer.portBinding.currentDrive;
FOR bit: NAT IN [0..writerValue.size) DO
sd: Ports.Drive ← scratchDrive[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.type 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]]];
};
ENDCASE => ERROR;
};
UpdatePerturbed: PROC [simulation: Simulation, updateProc: UpdateProc] = {
Conductance: TYPE = {on, off, unknown};
TranOn: PROC [tran: RoseTransistor] RETURNS [cond: Conductance] = {
gateValue: Ports.Level ← tran.gate.wireLevel;
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;
};
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.channels;
wire.mark ← TRUE;
IF channels#NIL THEN FOR t: CARDINAL IN [0..channels.size) DO
tran: RoseTransistor ← channels[t];
tranCond: Conductance ← TranOn[tran];
otherWire: RoseWire ← tran.ch1;
IF otherWire=wire THEN otherWire ← tran.ch2;
IF tranCond=off THEN LOOP;
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 => {
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.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.channels;
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;
IF channels#NIL THEN FOR t: CARDINAL IN [0..channels.size) DO
tran: RoseTransistor ← channels[t];
tranCond: Conductance ← TranOn[tran];
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 tranCond#off AND driveThrough >= otherWire.switchDrive AND driveThrough > otherWire.upDrive THEN {
otherWire.upDrive ← driveThrough;
PushWireByStrength[otherWire, driveThrough];
};
down => IF tranCond#off AND driveThrough >= otherWire.switchDrive AND driveThrough > otherWire.downDrive THEN {
otherWire.downDrive ← driveThrough;
PushWireByStrength[otherWire, driveThrough];
};
ENDCASE => ERROR;
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
recomputed: RoseWire ← NIL;
UNTIL simulation.perturbed=NIL DO
wire: RoseWire ← simulation.perturbed;
FindVicinity[wire, switch];
PushStrength[switch];
FindVicinity[wire, up];
PushStrength[up];
FindVicinity[wire, down];
PushStrength[down];
ENDLOOP;
FOR recomputed ← recomputed, recomputed.nextRecomputed UNTIL recomputed=NIL DO
wireLevel: Ports.Level ← SELECT TRUE FROM
recomputed.upDrive=none => L,
recomputed.downDrive=none => H,
ENDCASE => X;
IF recomputed.wireLevel#wireLevel THEN {
gates: RoseTransistors ← recomputed.gates;
IF gates#NIL THEN FOR t: CARDINAL IN [0..gates.size) DO
tran: RoseTransistor ← gates[t];
Perturb[simulation, tran.ch1];
Perturb[simulation, tran.ch2];
ENDLOOP;
recomputed.wireLevel ← wireLevel;
UpdateReaders[simulation, recomputed, updateProc];
};
ENDLOOP;
};
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
GetWirePath: PUBLIC PROC [roseWire: RoseWire] RETURNS [coreWire: CoreFlat.FlatWireRec] = {
coreWire ← roseWire.wire;
};
GetCellTypeState: PUBLIC PROC [simulation: Simulation] RETURNS [stateAny: REF ANY] = {
Instance: HashTable.EachPairAction = {
roseInstance: RoseCellInstance ← NARROW[value];
IF cellInstance=NIL THEN cellInstance ← roseInstance ELSE ERROR};
cellInstance: RoseCellInstance ← NIL;
[] ← HashTable.Pairs[table: simulation.coreToRoseInstances, action: Instance];
stateAny ← cellInstance.state;
};
GetInstanceState: PUBLIC PROC [simulation: Simulation, instance: CoreFlat.FlatInstance] RETURNS [stateAny: REF ANYNIL] = {
roseInstance: RoseCellInstance ← NARROW[HashTable.Fetch[table: simulation.coreToRoseInstances, key: instance].value];
stateAny ← roseInstance.state;
};
WireValue: PUBLIC PROC [simulation: Simulation, wire: CoreFlat.FlatWire] RETURNS [value: Ports.LevelSequence] = {
firstFreeBit: NAT ← 0;
values: Values ← NARROW[HashTable.Fetch[table: simulation.coreToValues, key: wire].value];
IF values=NIL THEN {
FindHereOrBelow: PROC [wire: CoreFlat.FlatWireRec] = {
roseWire: RoseWire ← FindRoseWire[simulation, wireBindTab, wire.wire, wireKey];
IF roseWire=NIL THEN {
FOR subWire: NAT DECREASING IN [0..wire.wire.size) DO
FindHereOrBelow[[wire.path, wire.wire[subWire]]];
ENDLOOP;
}
ELSE values ← CONS[[
roseWire: roseWire,
size: IF roseWire.currentValue=NIL THEN 1 ELSE roseWire.currentValue.size], values];
};
FindAbove: PROC [internal: Core.Wire] RETURNS [foundCore: BOOLFALSE, foundRose: BOOLFALSE, firstBit: NAT ← 0] = {
IF internal=wire.wire THEN foundCore ← TRUE
ELSE FOR thisWire: NAT IN [0..internal.size) DO
[foundCore, foundRose, firstBit] ← FindAbove[internal[thisWire]];
IF foundCore AND NOT foundRose THEN {
path: CoreFlat.PackedPath ← wire.path;
bind: CoreFlat.WireBind ← NARROW[HashTable.Fetch[table: wireBindTab, key: internal].value];
roseWire: RoseWire;
IF bind#NIL THEN {
path ← bind.path;
internal ← bind.wire;
};
FOR subWire: NAT IN [0..thisWire) DO
firstBit ← firstBit + CoreOps.WireBits[internal[subWire]]
ENDLOOP;
roseWire ← FindRoseWire[simulation, wireBindTab, internal, wireKey];
IF roseWire#NIL THEN {
values ← CONS[[
roseWire: roseWire,
firstBit: firstBit,
size: CoreOps.WireBits[wire.wire]], values];
foundRose ← TRUE;
};
EXIT;
};
ENDLOOP;
};
wireBindTab: HashTable.Table;
wireKey: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec];
cellType: Core.CellType;
[wireBindTab, cellType] ← CoreFlat.BoundCellType[simulation.coreCellType, wire.path];
FindHereOrBelow[wire^];
IF values=NIL THEN IF NOT FindAbove[NARROW[cellType.data, CoreClasses.RecordCellType].internal].foundRose THEN ERROR;
wireKey^ ← wire^;
IF NOT HashTable.Insert[table: simulation.coreToValues, key: wireKey, value: values] THEN ERROR;
};
value ← NEW[Ports.LevelSequenceRec[CoreOps.WireBits[wire.wire]]];
FOR values ← values, values.rest UNTIL values=NIL DO
currentValue: Ports.LevelSequence ← values.first.roseWire.currentValue;
IF currentValue=NIL THEN {
value[firstFreeBit] ← values.first.roseWire.wireLevel;
firstFreeBit ← firstFreeBit + 1;
}
ELSE {
firstBit: NAT ← values.first.firstBit;
FOR bit: NAT IN [0..values.first.size) DO
value[firstFreeBit + bit] ← currentValue[firstBit+bit];
ENDLOOP;
firstFreeBit ← firstFreeBit + values.first.size;
};
ENDLOOP;
};
WireValueRope: PUBLIC PROC [simulation: Rosemary.Simulation, wirePathRope: ROPE, base: NAT ← 16] RETURNS [value: ROPENIL] = {
wireRoot: CoreFlat.WireRoot;
wire: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec];
[wire^, wireRoot] ← CoreFlat.FindWire[simulation.coreCellType, wirePathRope];
value ← Ports.LevelSequenceToRope[WireValue[simulation, wire], 0, base];
};
CutSetMember: PROC [packedPath: CoreFlat.PackedPath, instance: CoreClasses.CellInstance, cutSets: LIST OF ROPE] RETURNS [member: BOOLFALSE, transistor: BOOLFALSE, ct: Core.CellType] = {
OneInOther: PROC [one, other: LIST OF ROPE] RETURNS [yes: BOOLFALSE] = {
FOR this: LIST OF ROPE ← one, this.rest UNTIL this=NIL DO
FOR that: LIST OF ROPE ← other, that.rest UNTIL that=NIL DO
IF Rope.Equal[CoreOps.FixStupidRef[this.first], that.first] THEN {
member ← TRUE;
yes ← TRUE;
RETURN;
};
ENDLOOP;
ENDLOOP;
};
thisSet: LIST OF ROPENARROW[CoreProperties.GetCellInstanceProp[from: instance, prop: roseCutSetProp]];
ct ← instance.type;
IF OneInOther[cutSets, thisSet] THEN RETURN;
DO
IF ct.class.recast=NIL AND FindRoseCellType[ct]#NIL AND ct.class#CoreClasses.recordCellClass THEN {
member ← TRUE;
RETURN;
};
IF ct.class=CoreClasses.transistorCellClass THEN {
member ← TRUE;
transistor ← TRUE;
RETURN;
};
thisSet ← NARROW[CoreProperties.GetCellTypeProp[from: ct, prop: roseCutSetProp]];
IF OneInOther[cutSets, thisSet] THEN RETURN;
IF ct.class#CoreClasses.identityCellClass THEN EXIT;
ct ← NARROW[ct.data];
ENDLOOP;
};
AllocateStatePoints: PUBLIC PROC [simulation: Simulation, statePoints: NAT] = {
InstanceState: HashTable.EachPairAction = {
roseInstance: RoseCellInstance ← NARROW[value];
IF roseInstance.state#NIL THEN {
roseInstance.statePoints ← NEW[SRASeq[statePoints]];
FOR s: NAT IN [0..statePoints) DO
roseInstance.statePoints[s] ← roseInstance.roseCellType.init[ roseInstance.instance.instance.type, roseInstance.publicPort];
ENDLOOP;
};
AllocatePortBindings[roseInstance.portBindings];
};
WireState: HashTable.EachPairAction = {
roseWire: RoseWire ← NARROW[value];
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;
};
AllocatePortBindings: PROC [binds: PortBindings] = {
FOR b: NAT IN [0..binds.size) DO
bind: PortBinding ← binds[b];
bind.statePoints ← NEW[DriveRec[statePoints]];
FOR f: NAT IN [0..bind.fields.size) DO
field: Field ← bind.fields[f];
field.statePoints ← AllocateLevelSequenceSeq[field.currentValue.size];
ENDLOOP;
ENDLOOP;
};
IF statePoints=0 THEN RETURN;
[] ← HashTable.Pairs[table: simulation.coreToRoseInstances, action: InstanceState];
[] ← HashTable.Pairs[table: simulation.coreToRoseWires, action: WireState];
simulation.statePoints ← NEW[PortSequenceRec[statePoints]];
FOR sp: NAT IN [0..statePoints) DO
simulation.statePoints[sp] ← Ports.CreatePort[simulation.coreCellType.public];
ENDLOOP;
AllocatePortBindings[simulation.publicBindings];
};
StatePoint: PUBLIC PROC [simulation: Simulation, point: NAT] = {
InstanceState: HashTable.EachPairAction = {
roseInstance: RoseCellInstance ← NARROW[value];
IF roseInstance.state#NIL THEN roseInstance.roseCellType.copy[from: roseInstance.state, to: roseInstance.statePoints[point]];
SavePortBindings[roseInstance.portBindings];
};
WireState: HashTable.EachPairAction = {
roseWire: RoseWire ← NARROW[value];
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];
bind.statePoints[point] ← bind.currentDrive;
FOR f: NAT IN [0..bind.fields.size) DO
field: Field ← bind.fields[f];
source: Ports.LevelSequence ← field.currentValue;
dest: Ports.LevelSequence ← field.statePoints[point];
FOR bit: NAT IN [0..field.currentValue.size) DO
dest[bit] ← source[bit];
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
[] ← HashTable.Pairs[table: simulation.coreToRoseInstances, action: InstanceState];
[] ← HashTable.Pairs[table: simulation.coreToRoseWires, action: WireState];
Ports.CopyPortValue[from: simulation.testPort, to: simulation.statePoints[point]];
SavePortBindings[simulation.publicBindings];
};
RestoreState: PUBLIC PROC [simulation: Simulation, point: NAT] = {
InstanceState: HashTable.EachPairAction = {
roseInstance: RoseCellInstance ← NARROW[value];
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: HashTable.EachPairAction = {
roseWire: RoseWire ← NARROW[value];
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];
bind.currentDrive ← bind.statePoints[point];
FOR f: NAT IN [0..bind.fields.size) DO
field: Field ← bind.fields[f];
dest: Ports.LevelSequence ← field.currentValue;
source: Ports.LevelSequence ← field.statePoints[point];
FOR bit: NAT IN [0..field.currentValue.size) DO
dest[bit] ← source[bit];
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
Complain: UpdateProc = {
ERROR Stop["State restoration failed, notify Rosemary wizard"];
};
simulation.instanceNeedEval ← NIL;
[] ← HashTable.Pairs[table: simulation.coreToRoseInstances, action: InstanceState];
simulation.perturbed ← NIL;
[] ← HashTable.Pairs[table: simulation.coreToRoseWires, action: WireState];
Ports.CopyPortValue[from: simulation.statePoints[point], to: simulation.testPort];
RestorePortBindings[simulation.publicBindings];
Settle[simulation, Complain];
};
SettleToTest: PUBLIC PROC [simulation: Simulation, instance: CoreFlat.FlatInstance, test: Ports.Port] = {
SetDrive: Ports.EachPortPairProc = {
IF onePort.type#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 expect;
};
};
};
roseInstance: RoseCellInstance ← NARROW[HashTable.Fetch[table: simulation.coreToRoseInstances, key: instance].value];
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;
};
RawRoseWire: PUBLIC PROC [simulation: Simulation, flatWire: CoreFlat.FlatWire] RETURNS [roseWire: RoseWire] = {
roseWire ← NARROW[HashTable.Fetch[table: simulation.coreToRoseWires, key: flatWire].value];
};
FindRoseWire: PROC [simulation: Simulation, bindings: HashTable.Table, wire: Core.Wire, wireKey: CoreFlat.FlatWire] RETURNS [roseWire: RoseWire ← NIL] = {
bind: CoreFlat.WireBind ← NARROW[HashTable.Fetch[table: bindings, key: wire].value];
wireKey.path ← bind.path;
wireKey.wire ← bind.wire;
roseWire ← NARROW[HashTable.Fetch[table: simulation.coreToRoseWires, key: wireKey].value];
};
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.FlatInstanceRec] = {
WITH key SELECT FROM
instanceKey: CoreFlat.FlatInstance => flat ← instanceKey^;
instanceKey: RoseCellInstance => flat ← instanceKey.instance;
ENDCASE => ERROR;
};
RoseInstanceHash: PROC [key: REF ANY] RETURNS [hash: CARDINAL] = {
hash ← CoreFlat.FlatInstanceHashRec[RoseInstanceHashNarrow[key]];
};
RoseInstanceEqual: PROC [key1, key2: REF ANY] RETURNS [equal: BOOL] = {
equal ← CoreFlat.FlatInstanceEqualRec[RoseInstanceHashNarrow[key1], RoseInstanceHashNarrow[key2]];
};
END.