RosemaryImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Barth, March 25, 1986 10:24:50 am PST
Louis Monier January 10, 1986 2:48:21 pm PST
Bertrand Serlet March 18, 1986 2:58:17 pm PST
Last Edited by: Neil Gunther February 27, 1986 12:00:12 pm PST
Curry, March 11, 1986 12:06:50 pm PST
DIRECTORY Basics, BitHacks, Core, CoreClasses, CoreOps, CoreProperties, Ports, Process, Rope, Rosemary, RefTab, SymTab;
RosemaryImpl: CEDAR PROGRAM
IMPORTS Basics, BitHacks, CoreClasses, CoreOps, CoreProperties, Ports, Process, Rope, RefTab, 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;
RoseWireList: TYPE = LIST OF RoseWire;
roseBehaveProp: ATOM = CoreProperties.RegisterProperty[prop: $RoseBehave];
roseWireSizeProp: ATOM = CoreProperties.RegisterProperty[prop: $RoseWireSize];
roseFixedWireProp: ATOM = CoreProperties.RegisterProperty[prop: $RoseFixedWire];
roseTransistorSizeProp: ATOM = CoreProperties.RegisterProperty[prop: $RoseTransistorSize];
roseCutSetProp: ATOM = CoreProperties.RegisterProperty[prop: $RoseCutSet];
roseClassTable: SymTab.Ref ← SymTab.Create[];
WireBind: TYPE = REF WireBindRec;
WireBindRec: TYPE = RECORD [
path: PackedPath,
wire: Core.Wire ← NIL,
valid: BOOLTRUE];
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;
};
Stop: PUBLIC SIGNAL [msg: ROPE, data: REF ANYNIL] = CODE;
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] RETURNS [sameWire: Core.Wire] = {
CoreProperties.PutWireProp[on: wire, prop: roseFixedWireProp, value: NEW[Ports.Level ← level]];
sameWire ← wire;
};
SetWireSize: PUBLIC PROC [wire: Core.Wire, size: WireSize] RETURNS [sameWire: Core.Wire] = {
CoreProperties.PutWireProp[on: wire, prop: roseWireSizeProp, value: NEW[Ports.Drive ← 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] = {
roseInstance: RoseCellInstance ← NEW[RoseCellInstanceRec];
max: CARDINAL;
wireToRoseWire: RefTab.Ref ← RefTab.Create[];
simulation ← NEW[SimulationRec];
simulation.coreCellType ← cellType;
simulation.coreToRoseInstances[0] ← roseInstance;
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;
FOR hash: HashIndex IN HashIndex DO
FOR roseWire: RoseWire ← simulation.coreToRoseWires[hash], roseWire.nextBucket UNTIL roseWire=NIL DO
IF roseWire.wireDrive=infinite THEN UpdateReaders[simulation, roseWire, NIL];
ENDLOOP;
ENDLOOP;
simulation.testPort ← testPort;
AllocateStatePoints[simulation, statePoints];
EstablishInvariants[simulation];
};
AllocateCellTypeRoseWires: PROC [simulation: Simulation, port: Ports.Port, public: Core.Wire, wireToRoseWire: RefTab.Ref] 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 ← NEW[RoseWireRec];
hash: HashIndex ← PathHash[[0, ALL[FALSE]], public];
wireSizeRef: REF Ports.Drive ← NARROW[CoreProperties.GetWireProp[from: public, prop: roseWireSizeProp]];
wireFixedRef: REF Ports.Level ← NARROW[CoreProperties.GetWireProp[from: public, prop: roseFixedWireProp]];
IF wireSizeRef#NIL THEN roseWire.wireDrive ← wireSizeRef^;
IF wireFixedRef#NIL THEN {
roseWire.wireDrive ← infinite;
roseWire.switchDrive ← infinite;
roseWire.wireLevel ← wireFixedRef^
};
roseWire.connections ← NEW[FieldSeq[2]];
IF NOT RefTab.Insert[x: wireToRoseWire, key: public, val: roseWire] THEN ERROR;
IF port.type=l OR port.type=b THEN Perturb[simulation, roseWire]
ELSE {
maxComposite ← CoreOps.WireBits[public];
roseWire.currentValue ← AllocateLevelSequence[maxComposite];
};
IF port.type=b OR port.type=bs OR port.type=c OR port.type=lc THEN boolWires ← CONS[roseWire, boolWires];
roseWire.wire ← public;
roseWire.nextBucket ← simulation.coreToRoseWires[hash];
simulation.coreToRoseWires[hash] ← roseWire;
};
};
ComputeCellTypeBindings: PROC [port: Ports.Port, wire: Core.Wire, wireToRoseWire: RefTab.Ref, 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 ← ComputeCellTypeBindings[port[subPort], wire[subPort], wireToRoseWire, binds, newFirstFreeBinding, instance];
ENDLOOP;
}
ELSE {
thisRoseWire: RoseWire ← NARROW[RefTab.Fetch[x: wireToRoseWire, key: wire].val];
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;
};
};
InstantiateInstances: PUBLIC PROC [cellType: Core.CellType, testPort: Ports.Port, cutSet: ROPENIL, statePoints: NAT ← 0] RETURNS [simulation: Simulation] = {
FindRoseWires: PROC [ct: Core.CellType] = {
AllocateRoseWires: PROC [wire: Core.Wire] RETURNS [public: BOOLFALSE, allocated: BOOLFALSE] = {
wireData: WireData ← NARROW[RefTab.Fetch[x: wireDataTab, key: wire].val];
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 ← NEW[RoseWireRec];
hash: HashIndex ← PathHash[packedPath, wire];
wireSize: NAT ← CoreOps.WireBits[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 THEN roseWire.currentValue ← AllocateLevelSequence[wireSize]
ELSE {
wireSizeRef: REF Ports.Drive ← NARROW[CoreProperties.GetWireProp[from: wire, prop: roseWireSizeProp]];
wireFixedRef: REF Ports.Level ← NARROW[CoreProperties.GetWireProp[from: wire, prop: roseFixedWireProp]];
roseWire.channels ← AllocateTransistorPointers[wireData.channels];
roseWire.gates ← AllocateTransistorPointers[wireData.gates];
IF wireSizeRef#NIL THEN roseWire.wireDrive ← wireSizeRef^;
IF wireFixedRef#NIL THEN {
roseWire.wireDrive ← infinite;
roseWire.switchDrive ← infinite;
roseWire.wireLevel ← wireFixedRef^
};
Perturb[simulation, roseWire];
};
roseWire.path ← packedPath;
roseWire.wire ← wire;
roseWire.nextBucket ← simulation.coreToRoseWires[hash];
simulation.coreToRoseWires[hash] ← roseWire;
maxRoseWireSize ← MAX[maxRoseWireSize, wireSize];
IF wireData.boolPort THEN simulation.roseBoolWires ← CONS[roseWire, simulation.roseBoolWires];
wireData.allocated ← TRUE;
};
IF NOT (public ← NOT PathEqual[wireData.path, packedPath]) 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
subWireData: WireData ← NARROW[RefTab.Fetch[x: wireDataTab, key: wire[sub]].val];
IF (NOT subWireData.allocated) AND PathEqual[subWireData.path, packedPath] 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;
};
};
rct: CoreClasses.RecordCellType ← NARROW[ct.data];
pathBits: NAT ← BitHacks.NBits[rct.size];
FOR i:NAT IN [0..rct.internal.size) DO
ComputeInDegree[rct.internal[i]];
ENDLOOP;
FOR in: NAT IN [0..rct.size) DO
member, transistor: BOOL;
subType: Core.CellType;
[member, transistor, subType] ← CutSetMember[packedPath, rct[in], cutSet];
IF member THEN {
IF transistor THEN {
actual: Core.Wire ← rct[in].actual;
wireData: WireData ← NARROW[RefTab.Fetch[x: wireDataTab, key: actual[gate]].val];
wireData.gates ← wireData.gates + 1;
wireData.portLeaf ← TRUE;
wireData ← NARROW[RefTab.Fetch[x: wireDataTab, key: actual[ch1]].val];
wireData.channels ← wireData.channels + 1;
wireData.portLeaf ← TRUE;
wireData ← NARROW[RefTab.Fetch[x: wireDataTab, key: actual[ch2]].val];
wireData.portLeaf ← TRUE;
wireData.channels ← wireData.channels + 1;
}
ELSE {
visited: RefTab.Ref ← RefTab.Create[];
FOR i: NAT IN [0..rct[in].actual.size) DO
MarkPortLeavesCountConnections[actual: rct[in].actual[i], public: rct[in].type.public[i], checkPort: TRUE, visited: visited]
ENDLOOP;
};
}
ELSE {
rc: Core.CellType ← Recordify[subType];
BindPublicToActual: CoreOps.EachWirePairProc = {
val: REF ANY ← RefTab.Fetch[x: wireDataTab, key: actualWire].val;
IF val=NIL THEN ERROR;
[] ← RefTab.Store[x: wireDataTab, key: publicWire, val: val];
};
FOR i: NAT IN [0..rct[in].actual.size) DO
IF CoreOps.VisitBinding[actual: rct[in].actual[i], public: rc.public[i], eachWirePair: BindPublicToActual] THEN ERROR;
ENDLOOP;
FOR bit: NAT IN [0..pathBits) DO
packedPath.bits[packedPath.length+bit] ← BitHacks.XthBitOfN[pathBits-bit-1, in];
ENDLOOP;
packedPath.length ← packedPath.length + pathBits;
FindRoseWires[ct: rc];
packedPath.length ← packedPath.length - pathBits;
};
ENDLOOP;
FOR i: NAT IN [0..rct.internal.size) DO
[] ← AllocateRoseWires[rct.internal[i]];
ENDLOOP;
};
AllocateRoseInstances: PROC [ct: Core.CellType] = {
MarkInvalid: CoreOps.EachWireProc = {
bind: WireBind ← NARROW[RefTab.Fetch[x: wireBindTab, key: wire].val];
IF bind#NIL THEN bind.valid ← FALSE;
};
MarkValid: CoreOps.EachWireProc = {
bind: WireBind ← NARROW[RefTab.Fetch[x: wireBindTab, key: wire].val];
IF bind#NIL THEN bind.valid ← TRUE;
};
rct: CoreClasses.RecordCellType ← NARROW[ct.data];
pathBits: NAT ← BitHacks.NBits[rct.size];
FOR in: NAT IN [0..rct.size) DO
member, transistor: BOOL;
coreInstance: CoreClasses.CellInstance ← rct[in];
subType: Core.CellType;
[member, transistor, subType] ← CutSetMember[packedPath, coreInstance, cutSet];
IF member THEN {
IF transistor THEN {
InsertTransistor: PROC [transistors: RoseTransistors] = {
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];
actual: Core.Wire ← coreInstance.actual;
transistorSizeRef: REF Ports.Drive ← NARROW[CoreProperties.GetCellInstanceProp[from: coreInstance, prop: roseTransistorSizeProp]];
roseTransistor.gate ← LookUpRoseWire[actual[gate]];
InsertTransistor[roseTransistor.gate.gates];
roseTransistor.ch1 ← LookUpRoseWire[actual[ch1]];
InsertTransistor[roseTransistor.ch1.channels];
roseTransistor.ch2 ← LookUpRoseWire[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];
hash: HashIndex ← PathHash[packedPath, coreInstance];
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[instance: roseInstance, port: roseInstance.publicPort, wire: coreInstance.actual, binds: roseInstance.portBindings, firstFreeBinding: 0] THEN ERROR;
IF roseInstance.roseCellType.init#NIL THEN roseInstance.state ← roseInstance.roseCellType.init[cellType: coreInstance.type, p: roseInstance.publicPort];
roseInstance.path ← packedPath;
roseInstance.instance ← coreInstance;
roseInstance.nextBucket ← simulation.coreToRoseInstances[hash];
simulation.coreToRoseInstances[hash] ← roseInstance;
};
}
ELSE {
rc: Core.CellType ← Recordify[subType];
BindPublicToActual: CoreOps.EachWirePairProc = {
bind: WireBind ← NARROW[RefTab.Fetch[x: wireBindTab, key: actualWire].val];
IF bind=NIL THEN bind ← NEW[WireBindRec ← [
path: packedPath,
wire: actualWire]]
ELSE IF NOT bind.valid THEN bind.path ← packedPath;
[] ← RefTab.Store[x: wireBindTab, key: publicWire, val: bind];
};
FOR i: NAT IN [0..rct[in].actual.size) DO
IF CoreOps.VisitBinding[actual: rct[in].actual[i], public: rc.public[i], eachWirePair: BindPublicToActual] THEN ERROR;
ENDLOOP;
FOR bit: NAT IN [0..pathBits) DO
packedPath.bits[packedPath.length+bit] ← BitHacks.XthBitOfN[pathBits-bit-1, in];
ENDLOOP;
packedPath.length ← packedPath.length + pathBits;
AllocateRoseInstances[ct: rc];
packedPath.length ← packedPath.length - pathBits;
};
ENDLOOP;
IF CoreOps.VisitWire[rct.internal, MarkInvalid] THEN ERROR;
IF CoreOps.VisitWire[ct.public, MarkValid] THEN ERROR;
};
ComputeInDegree: PROC [wire: Core.Wire] = {
found: BOOL;
wireDataAny: REF;
wireData: WireData;
[found, wireDataAny] ← RefTab.Fetch[x: wireDataTab, key: wire];
IF found THEN wireData ← NARROW[wireDataAny]
ELSE {
wireData ← NEW[WireDataRec];
IF NOT RefTab.Insert[x: wireDataTab, key: wire, val: wireData] THEN ERROR;
};
IF wireData.indegree=0 THEN {
wireData.path ← packedPath;
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[wire[sub]];
ENDLOOP;
}
ELSE wireData.indegree ← wireData.indegree + 1;
};
MarkPortLeavesCountConnections: PROC [actual: Core.Wire, public: Core.Wire, checkPort: BOOL, visited: RefTab.Ref, type: Ports.PortType ← composite] = {
actualData: WireData ← NARROW[RefTab.Fetch[x: wireDataTab, key: actual].val];
IF NOT RefTab.Fetch[x: visited, key: actual].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[actual[sub], public[sub], checkPort, visited, type];
ENDLOOP;
IF NOT RefTab.Insert[x: visited, key: actual, val: $Visited] THEN ERROR;
};
IF type=b OR type=bs OR type=c OR type=lc THEN actualData.boolPort ← TRUE;
};
ComputeBindings: PROC [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[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[wire: wire, bound: RefTab.Create[]]]];
[] ← ComputeFields[wire: wire, portBinding: portBinding, valueStart: 0, bound: RefTab.Create[], firstFreeField: 0];
binds[newFirstFreeBinding] ← portBinding;
newFirstFreeBinding ← newFirstFreeBinding + 1;
};
};
CountFields: PROC [wire: Core.Wire, bound: RefTab.Ref] RETURNS [fieldCount: CARDINAL ← 0] = {
IF LookUpRoseWire[wire]=NIL THEN {
FOR subWire: NAT IN [0..wire.size) DO
fieldCount ← fieldCount + CountFields[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 [wire: Core.Wire, portBinding: PortBinding, valueStart: NAT, bound: RefTab.Ref, firstFreeField: CARDINAL] RETURNS [newFirstFreeField: CARDINAL, newValueStart: NAT] = {
roseWire: RoseWire ← LookUpRoseWire[wire];
newValueStart ← valueStart;
newFirstFreeField ← firstFreeField;
IF roseWire = NIL THEN {
FOR subWire: NAT IN [0..wire.size) DO
[newFirstFreeField, newValueStart] ← ComputeFields[wire[subWire], portBinding, newValueStart, bound, newFirstFreeField];
ENDLOOP;
}
ELSE {
IF NOT RefTab.Fetch[x: 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 RefTab.Insert[x: bound, key: wire, val: $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 [wire: Core.Wire] RETURNS [roseWire: RoseWire ← NIL] = {
bind: WireBind ← NARROW[RefTab.Fetch[x: wireBindTab, key: wire].val];
path: PackedPath;
IF bind=NIL THEN path ← packedPath
ELSE {
path ← bind.path;
wire ← bind.wire;
};
FOR roseWire: RoseWire ← simulation.coreToRoseWires[PathHash[path, wire]], roseWire.nextBucket UNTIL roseWire=NIL DO
IF PathEqual[roseWire.path, path] AND roseWire.wire=wire THEN RETURN[roseWire];
ENDLOOP;
};
WireData: TYPE = REF WireDataRec;
WireDataRec: TYPE = RECORD [
path: PackedPath,
indegree: CARDINAL ← 0,
connections: CARDINAL ← 0,
channels: CARDINAL ← 0,
gates: CARDINAL ← 0,
portLeaf: BOOLFALSE,
boolPort: BOOLFALSE,
allocated: BOOLFALSE];
gate: NAT = 0;
ch1: NAT = 1;
ch2: NAT = 2;
maxRoseWireSize: NAT ← 0;
maxVicinity: NAT ← 0;
packedPath: PackedPath ← [0, ALL[FALSE]];
wireDataTab: RefTab.Ref ← RefTab.Create[];
wireBindTab: RefTab.Ref ← RefTab.Create[];
publicRCT: Core.CellType ← Recordify[cellType];
simulation ← NEW[SimulationRec];
simulation.coreCellType ← cellType;
simulation.cutSet ← cutSet;
FOR i: NAT IN [0..publicRCT.public.size) DO
ComputeInDegree[publicRCT.public[i]];
ENDLOOP;
{
visited: RefTab.Ref ← RefTab.Create[];
FOR i: NAT IN [0..publicRCT.public.size) DO
MarkPortLeavesCountConnections[publicRCT.public[i], publicRCT.public[i], TRUE, visited];
ENDLOOP;
};
FindRoseWires[ct: publicRCT];
wireDataTab ← NIL;
simulation.publicBindings ← NEW[PortBindingSeq[Ports.PortLeaves[testPort]]];
IF simulation.publicBindings.size#ComputeBindings[port: testPort, wire: publicRCT.public, binds: simulation.publicBindings, firstFreeBinding: 0] THEN ERROR;
AllocateRoseInstances[ct: publicRCT];
simulation.scratchValue ← NEW[Ports.LevelSequenceRec[maxRoseWireSize]];
simulation.scratchDrive ← NEW[DriveRec[maxRoseWireSize]];
FOR hash: HashIndex IN HashIndex DO
FOR roseWire: RoseWire ← simulation.coreToRoseWires[hash], roseWire.nextBucket UNTIL roseWire=NIL DO
IF roseWire.wireDrive=infinite THEN UpdateReaders[simulation, roseWire, NIL]
ELSE IF NOT roseWire.mark THEN maxVicinity ← MAX[maxVicinity, CountVicinity[roseWire]];
ENDLOOP;
ENDLOOP;
FOR hash: HashIndex IN HashIndex DO
FOR roseWire: RoseWire ← simulation.coreToRoseWires[hash], roseWire.nextBucket UNTIL roseWire=NIL DO
roseWire.mark ← FALSE;
ENDLOOP;
ENDLOOP;
FOR strength: Ports.Drive IN Ports.Drive DO
simulation.vicinityByStrength[strength].wires ← NEW[RoseWireSeq[maxVicinity]];
ENDLOOP;
simulation.testPort ← testPort;
AllocateStatePoints[simulation, statePoints];
EstablishInvariants[simulation];
};
EstablishInvariants: PROC [simulation: Simulation] = {
CleanUp[simulation: simulation, bindings: simulation.publicBindings, forceUpdate: TRUE, updateProc: NIL];
FOR hash: HashIndex IN HashIndex DO
FOR roseInstance: RoseCellInstance ← simulation.coreToRoseInstances[hash], roseInstance.nextBucket UNTIL roseInstance=NIL DO
CleanUp[simulation: simulation, bindings: roseInstance.portBindings, forceUpdate: TRUE, updateProc: NIL];
ENDLOOP;
ENDLOOP;
FOR hash: HashIndex IN HashIndex DO
FOR roseWire: RoseWire ← simulation.coreToRoseWires[hash], roseWire.nextBucket UNTIL roseWire=NIL DO
IF roseWire.connections#NIL THEN RecomputeValue[simulation: simulation, wire: roseWire, forceReaderUpdate: TRUE, updateProc: NIL];
ENDLOOP;
ENDLOOP;
};
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];
};
Recordify: PUBLIC PROC [ct: Core.CellType] RETURNS [rc: Core.CellType] = {
FOR rc ← ct, CoreOps.Recast[rc] UNTIL rc.class.recast = NIL DO
rct.class.recast = NIL exactly when rct is a record or atomic.
NULL;
ENDLOOP;
};
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] = {
ERROR; -- not implemented
};
Relaxation
Settle: PUBLIC PROC [simulation: Simulation, updateProc: UpdateProc ← NIL] = {
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];
ENDLOOP;
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 ERROR;
}
ELSE FOR bit: CARDINAL IN [0..roseWire.currentValue.size) DO
IF roseWire.currentValue[bit]=X THEN ERROR;
ENDLOOP;
ENDLOOP;
};
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] ← none;
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] = {
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 ← SELECT wire.wireLevel FROM
L => FALSE,
X => readerValue.b,
H => TRUE,
ENDCASE => ERROR;
ls => FOR bit: NAT IN [0..wireValue.size) DO
readerValue.ls[bit+readerStart] ← wireValue[bit];
ENDLOOP;
bs => FOR bit: NAT IN [0..wireValue.size) DO
readerValue.bs[bit+readerStart] ← SELECT wireValue[bit] FROM
L => FALSE,
X => readerValue.bs[bit+readerStart],
H => TRUE,
ENDCASE => ERROR;
ENDLOOP;
c => {
asBits: WordAsBits ← ALL[FALSE];
FOR bit: NAT IN [0..wireValue.size) DO
asBits[bit+readerStart] ← SELECT wireValue[bit] FROM
L => FALSE,
X => LOOPHOLE[readerValue.c, WordAsBits][bit+readerStart],
H => TRUE,
ENDCASE => ERROR;
ENDLOOP;
readerValue.c ← LOOPHOLE[asBits];
};
lc => {
asBits: DWordAsBits ← ALL[FALSE];
FOR bit: NAT IN [0..wireValue.size) DO
thisBit: NAT ← bit+readerStart;
asBits[thisBit] ← SELECT wireValue[bit] FROM
L => FALSE,
X => IF thisBit < 16 THEN LOOPHOLE[Basics.HighHalf[readerValue.lc], WordAsBits][thisBit] ELSE LOOPHOLE[Basics.LowHalf[readerValue.lc], WordAsBits][thisBit - 16],
H => TRUE,
ENDCASE => ERROR;
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
GetCellTypeState: PUBLIC PROC [simulation: Simulation] RETURNS [stateAny: REF ANY] = {
stateAny ← simulation.coreToRoseInstances[0].state;
};
GetInstanceState: PUBLIC PROC [simulation: Simulation, instantiationPath: InstantiationPath, instance: CoreClasses.CellInstance] RETURNS [stateAny: REF ANYNIL] = {
packedPath: PackedPath ← ComputePackedPath[simulation, instantiationPath];
hash: HashIndex ← PathHash[packedPath, instance];
FOR roseInstance: RoseCellInstance ← simulation.coreToRoseInstances[hash], roseInstance.nextBucket UNTIL roseInstance=NIL DO
IF PathEqual[roseInstance.path, packedPath] AND roseInstance.instance=instance THEN RETURN[roseInstance.state];
ENDLOOP;
};
GetWireValue: PUBLIC PROC [simulation: Simulation, instantiationPath: InstantiationPath, wire: Core.Wire, container: Ports.LevelSequence] = {
packedPath: PackedPath ← ComputePackedPath[simulation, instantiationPath];
binds: ValueBindings ← NIL;
firstFreeBit: NAT ← 0;
FOR binds ← simulation.coreToValues, binds.rest UNTIL binds=NIL DO
IF PathEqual[packedPath, binds.first.path] AND wire=binds.first.wire THEN EXIT;
REPEAT
FINISHED => {
BindPublicToActual: CoreOps.EachWirePairProc = {
bind: WireBind ← NARROW[RefTab.Fetch[x: wireBindTab, key: actualWire].val];
IF bind=NIL THEN bind ← NEW[WireBindRec ← [
path: currentPath,
wire: actualWire]];
[] ← RefTab.Store[x: wireBindTab, key: publicWire, val: bind];
};
FindHereOrBelow: PROC [path: PackedPath, wire: Core.Wire] = {
bind: WireBind ← NARROW[RefTab.Fetch[x: wireBindTab, key: wire].val];
IF bind#NIL THEN {
path ← bind.path;
wire ← bind.wire;
};
FOR roseWire: RoseWire ← simulation.coreToRoseWires[PathHash[path, wire]], roseWire.nextBucket UNTIL roseWire=NIL DO
IF PathEqual[roseWire.path, path] AND roseWire.wire=wire THEN {
values ← CONS[[
roseWire: roseWire,
size: IF roseWire.currentValue=NIL THEN 1 ELSE roseWire.currentValue.size], values];
EXIT;
};
REPEAT
FINISHED => {
FOR subWire: NAT IN [0..wire.size) DO
FindHereOrBelow[path, wire[subWire]];
ENDLOOP;
};
ENDLOOP;
};
FindAbove: PROC [internal: Core.Wire] RETURNS [foundCore: BOOLFALSE, foundRose: BOOLFALSE, firstBit: NAT ← 0] = {
IF internal=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: PackedPath ← packedPath;
bind: WireBind ← NARROW[RefTab.Fetch[x: wireBindTab, key: internal].val];
IF bind#NIL THEN {
path ← bind.path;
internal ← bind.wire;
};
FOR subWire: NAT IN [0..thisWire) DO
firstBit ← firstBit + CoreOps.WireBits[internal[subWire]]
ENDLOOP;
FOR roseWire: RoseWire ← simulation.coreToRoseWires[PathHash[path, internal]], roseWire.nextBucket UNTIL roseWire=NIL DO
IF PathEqual[roseWire.path, path] AND roseWire.wire=internal THEN {
values ← CONS[[
roseWire: roseWire,
firstBit: firstBit,
size: CoreOps.WireBits[wire]], values];
foundRose ← TRUE;
EXIT;
};
ENDLOOP;
EXIT;
};
ENDLOOP;
};
values: Values ← NIL;
wireBindTab: RefTab.Ref ← RefTab.Create[];
currentPath: PackedPath ← [0, ALL[FALSE]];
coreInstance: CoreClasses.CellInstance;
ct: Core.CellType ← simulation.coreCellType;
rc: Core.CellType ← Recordify[ct];
rct: CoreClasses.RecordCellType ← NARROW[rc.data];
UNTIL currentPath.length=packedPath.length DO
boolWord: PACKED ARRAY [0..16) OF BOOLALL[FALSE];
pathBits: NAT ← BitHacks.NBits[rct.size];
FOR bit: NAT IN [0..pathBits) DO
thisBit: BOOL ← packedPath.bits[currentPath.length+bit];
boolWord[16-pathBits+bit] ← thisBit;
currentPath.bits[currentPath.length+bit] ← thisBit;
ENDLOOP;
coreInstance ← rct[LOOPHOLE[boolWord]];
IF CutSetMember[currentPath, coreInstance, simulation.cutSet].member THEN ERROR;
ct ← coreInstance.type;
rc ← Recordify[ct];
rct ← NARROW[rc.data];
IF CoreOps.VisitBinding[actual: coreInstance.actual, public: rc.public, eachWirePair: BindPublicToActual] THEN ERROR;
currentPath.length ← currentPath.length+pathBits;
ENDLOOP;
FindHereOrBelow[packedPath, wire];
IF values=NIL THEN IF NOT FindAbove[rct.internal].foundRose THEN ERROR;
binds ← simulation.coreToValues ← CONS[[
path: packedPath,
wire: wire,
values: values], simulation.coreToValues];
};
ENDLOOP;
FOR values: Values ← binds.first.values, values.rest UNTIL values=NIL DO
currentValue: Ports.LevelSequence ← values.first.roseWire.currentValue;
IF currentValue=NIL THEN {
container[firstFreeBit] ← values.first.roseWire.wireLevel;
firstFreeBit ← firstFreeBit + 1;
}
ELSE {
firstBit: NAT ← values.first.firstBit;
FOR bit: NAT IN [0..values.first.size) DO
container[firstFreeBit + bit] ← currentValue[firstBit+bit];
ENDLOOP;
firstFreeBit ← firstFreeBit + values.first.size;
};
ENDLOOP;
};
ComputePackedPath: PROC [simulation: Simulation, instantiationPath: InstantiationPath] RETURNS [packedPath: PackedPath] = {
ct: Core.CellType ← simulation.coreCellType;
packedPath.length ← 0;
FOR path: InstantiationPath ← instantiationPath, path.rest UNTIL path=NIL DO
rc: Core.CellType ← Recordify[ct];
rct: CoreClasses.RecordCellType ← NARROW[rc.data];
FOR in: NAT IN [0..rct.size) DO
IF rct[in]=path.first THEN {
pathBits: NAT ← BitHacks.NBits[rct.size];
FOR bit: NAT IN [0..pathBits) DO
packedPath.bits[packedPath.length+bit] ← BitHacks.XthBitOfN[pathBits-bit-1, in];
ENDLOOP;
packedPath.length ← packedPath.length + pathBits;
ct ← rct[in].type;
EXIT;
};
REPEAT
FINISHED => ERROR;
ENDLOOP;
ENDLOOP;
};
GetCellType: PUBLIC PROC [rootCellType: Core.CellType, path: PackedPath] RETURNS [cellType: Core.CellType ← NIL] = {
startBit: NAT ← 0;
cellType ← Recordify[rootCellType];
UNTIL startBit=path.length DO
rct: CoreClasses.RecordCellType ← NARROW[cellType.data];
pathBits: NAT ← BitHacks.NBits[rct.size];
instanceBits: PACKED ARRAY [0..16) OF BOOLALL[FALSE];
FOR bit: NAT IN [0..pathBits) DO
instanceBits[16-pathBits+bit] ← path.bits[startBit+bit];
ENDLOOP;
startBit ← startBit+pathBits;
cellType ← Recordify[rct[LOOPHOLE[instanceBits]].type];
ENDLOOP;
};
PathEqual: PROC [one: PackedPath, other: PackedPath] RETURNS [equal: BOOL] = {
equal ← one.length=other.length;
IF equal THEN FOR bit: NAT IN [0..one.length) DO
IF one.bits[bit]#other.bits[bit] THEN {
equal ← FALSE;
EXIT;
};
ENDLOOP;
};
PathHash: PROC [path: PackedPath, ref: REF ANY] RETURNS [hi: HashIndex] = TRUSTED {
pathAsLN: Basics.LongNumber ← Basics.SwapHalves[LOOPHOLE[path.bits]];
wideHI: CARDINAL;
pathAsLN ← Basics.DoubleShiftRight[pathAsLN, 32-path.length];
wideHI ← Basics.BITXOR[pathAsLN.lowbits, pathAsLN.highbits];
wideHI ← Basics.BITXOR[wideHI, Basics.LowHalf[LOOPHOLE[ref]]];
wideHI ← Basics.BITXOR[wideHI, Basics.HighHalf[LOOPHOLE[ref]]];
hi ← Basics.BITAND[wideHI, hashMask];
};
hashMask: NAT ← BitHacks.TwoToThe[BitHacks.NBits[LAST[HashIndex] + 1]] - 1;
CutSetMember: PROC [packedPath: PackedPath, instance: CoreClasses.CellInstance, cutSet: ROPE] RETURNS [member: BOOLFALSE, transistor: BOOLFALSE, ct: Core.CellType] = {
FixStupidRef: PROC [ref: REF ANY] RETURNS [rope: ROPE] = {
rope ← WITH ref SELECT FROM
r: REF TEXT => Rope.FromRefText[r],
r: ROPE => r,
ENDCASE => ERROR;
};
cutSets: LIST OF ROPENARROW[CoreProperties.GetCellInstanceProp[from: instance, prop: roseCutSetProp]];
ct ← instance.type;
FOR csl: LIST OF ROPE ← cutSets, csl.rest UNTIL csl=NIL DO
IF Rope.Equal[FixStupidRef[csl.first], cutSet] THEN {
member ← TRUE;
RETURN;
};
ENDLOOP;
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;
};
cutSets ← NARROW[CoreProperties.GetCellTypeProp[from: ct, prop: roseCutSetProp]];
FOR csl: LIST OF ROPE ← cutSets, csl.rest UNTIL csl=NIL DO
IF Rope.Equal[FixStupidRef[csl.first], cutSet] THEN {
member ← TRUE;
RETURN;
};
ENDLOOP;
IF ct.class#CoreClasses.identityCellClass THEN EXIT;
ct ← NARROW[ct.data];
ENDLOOP;
};
AllocateStatePoints: PUBLIC PROC [simulation: Simulation, statePoints: NAT] = {
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;
};
FOR hash: HashIndex IN HashIndex DO
FOR roseInstance: RoseCellInstance ← simulation.coreToRoseInstances[hash], roseInstance.nextBucket UNTIL roseInstance=NIL DO
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.type, roseInstance.publicPort];
ENDLOOP;
};
AllocatePortBindings[roseInstance.portBindings];
ENDLOOP;
ENDLOOP;
FOR hash: HashIndex IN HashIndex DO
FOR roseWire: RoseWire ← simulation.coreToRoseWires[hash], roseWire.nextBucket UNTIL roseWire=NIL DO
roseWire.statePoints ← IF roseWire.currentValue=NIL THEN NEW[Ports.LevelSequenceRec[statePoints]] ELSE AllocateLevelSequenceSeq[roseWire.currentValue.size];
ENDLOOP;
ENDLOOP;
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] = {
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;
};
FOR hash: HashIndex IN HashIndex DO
FOR roseInstance: RoseCellInstance ← simulation.coreToRoseInstances[hash], roseInstance.nextBucket UNTIL roseInstance=NIL DO
IF roseInstance.state#NIL THEN roseInstance.roseCellType.copy[from: roseInstance.state, to: roseInstance.statePoints[point]];
SavePortBindings[roseInstance.portBindings];
ENDLOOP;
ENDLOOP;
FOR hash: HashIndex IN HashIndex DO
FOR roseWire: RoseWire ← simulation.coreToRoseWires[hash], roseWire.nextBucket UNTIL roseWire=NIL DO
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;
};
ENDLOOP;
ENDLOOP;
Ports.CopyPortValue[from: simulation.testPort, to: simulation.statePoints[point]];
SavePortBindings[simulation.publicBindings];
};
RestoreState: PUBLIC PROC [simulation: Simulation, point: NAT] = {
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;
FOR hash: HashIndex IN HashIndex DO
FOR roseInstance: RoseCellInstance ← simulation.coreToRoseInstances[hash], roseInstance.nextBucket UNTIL roseInstance=NIL DO
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;
ENDLOOP;
ENDLOOP;
simulation.perturbed ← NIL;
FOR hash: HashIndex IN HashIndex DO
FOR roseWire: RoseWire ← simulation.coreToRoseWires[hash], roseWire.nextBucket UNTIL roseWire=NIL DO
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];
ENDLOOP;
ENDLOOP;
Ports.CopyPortValue[from: simulation.statePoints[point], to: simulation.testPort];
RestorePortBindings[simulation.publicBindings];
Settle[simulation, Complain];
};
END.