SetFixedWire:
PUBLIC
PROC [wire: Core.Wire, level: Level ← L]
RETURNS [sameWire: Core.Wire] = {
CoreProperties.PutWireProp[on: wire, prop: roseFixedWireProp, value: NEW[Level ← level]];
sameWire ← wire;
};
SetNamedFixedWire:
PUBLIC
PROC [cellType: Core.CellType, name: Rope.
ROPE, level: Level ← L]
RETURNS [sameWire: Core.Wire] = {
sameWire ← SetFixedWire[CoreOps.FindWire[cellType.public, name], level];
};
Instantiate:
PUBLIC
PROC [cellType: Core.CellType]
RETURNS [simulation: RoseSimulation] = {
FlattenCell: CoreFlat.BoundFlatCellProc = {
SELECT
TRUE
FROM
cell.class=CoreClasses.transistorCellClass => {
public: Core.Wire ← cell.public;
coreTransistor: CoreClasses.Transistor ← NARROW[cell.data];
roseTransistor: RoseTransistor ← NEW[RoseTransistorRec];
roseTransistor.gate ← LookUpRoseWire[public[gate], bindings];
roseTransistor.gate.gates ← CONS[roseTransistor, roseTransistor.gate.gates];
roseTransistor.ch1 ← LookUpRoseWire[public[ch1], bindings];
roseTransistor.ch1.channels ← CONS[roseTransistor, roseTransistor.ch1.channels];
roseTransistor.ch1.notOffChannels ← CONS[roseTransistor, roseTransistor.ch1.notOffChannels];
roseTransistor.ch2 ← LookUpRoseWire[public[ch2], bindings];
roseTransistor.ch2.channels ← CONS[roseTransistor, roseTransistor.ch2.channels];
roseTransistor.ch2.notOffChannels ← CONS[roseTransistor, roseTransistor.ch2.notOffChannels];
roseTransistor.transistorType ← coreTransistor.type;
roseTransistor.flatCellType ← flatCell;
};
cell.class=CoreClasses.recordCellClass => {
AllocateWire:
PROC [coreWire: Core.Wire] = {
flatWire: CoreFlat.FlatWire ← IF bindings=NIL THEN NIL ELSE NARROW[RefTab.Fetch[x: bindings, key: coreWire].val];
IF flatWire=
NIL
THEN {
wireKey.flatCell ← flatCell;
wireKey.wire ← coreWire;
IF RefTab.Fetch[x: simulation.coreToRoseWires, key: wireKey].val=
NIL
THEN {
wireFixedRef: REF Level ← NARROW[CoreProperties.GetWireProp[from: coreWire, prop: roseFixedWireProp]];
roseWire: RoseWire ← NEW[RoseWireRec];
roseWire.flatWire ← wireKey^;
IF wireFixedRef#
NIL
THEN {
roseWire.switchDrive ← roseWire.wireSize ← infinite;
roseWire.wireLevel ← wireFixedRef^
};
IF NOT RefTab.Insert[x: simulation.coreToRoseWires, key: roseWire, val: roseWire] THEN ERROR;
};
};
};
cellTypeRCT: CoreClasses.RecordCellType ← NARROW[cell.data];
CoreOps.VisitRootAtomics[cellTypeRCT.internal, AllocateWire];
CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, FlattenCell];
};
ENDCASE => CoreFlat.NextBoundCellType[cell, target, flatCell, instance, index, parent, flatParent, data, bindings, FlattenCell];
};
LookUpRoseWire:
PROC [wire: Core.Wire, bindings: RefTab.Ref]
RETURNS [roseWire: RoseWire ←
NIL] = {
leftUpper: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[x: bindings, key: wire].val];
roseWire ← NARROW[RefTab.Fetch[x: simulation.coreToRoseWires, key: leftUpper].val];
};
ComputeMaxVicinity: RefTab.EachPairAction = {
roseWire: RoseWire ← NARROW[val];
IF roseWire.wireSize#infinite AND NOT roseWire.mark THEN maxVicinity ← MAX[maxVicinity, CountVicinity[roseWire]];
};
CountVicinity:
PROC [wire: RoseWire, currentCount:
NAT ← 0]
RETURNS [newCount:
NAT] = {
wire.mark ← TRUE;
newCount ← currentCount + 1;
FOR rts: RoseTransistors ← wire.channels, rts.rest
UNTIL rts=
NIL
DO
tran: RoseTransistor ← rts.first;
otherWire: RoseWire ← tran.ch1;
IF otherWire=wire THEN otherWire ← tran.ch2;
IF otherWire.wireSize#infinite AND NOT otherWire.mark THEN newCount ← CountVicinity[otherWire, newCount];
ENDLOOP;
};
gate: NAT = CoreClasses.TransistorPort.gate.ORD;
ch1: NAT = CoreClasses.TransistorPort.ch1.ORD;
ch2: NAT = CoreClasses.TransistorPort.ch2.ORD;
wireKey: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec];
maxVicinity: NAT ← 0;
simulation ← NEW[RoseSimulationRec];
simulation.cellType ← cellType;
simulation.coreToRoseWires ← RefTab.Create[mod: 1019, equal: RoseWireEqual, hash: RoseWireHash];
FlattenCell[cell: cellType];
[] ← RefTab.Pairs[x: simulation.coreToRoseWires, action: ComputeMaxVicinity];
FOR strength: Drive
IN Drive
DO
simulation.vicinityByStrength[strength].wires ← NEW[RoseWireSeq[maxVicinity]];
ENDLOOP;
EstablishInvariants[simulation];
};
EstablishInvariants:
PROC [simulation: RoseSimulation] = {
Wire: RefTab.EachPairAction = {
roseWire: RoseWire ← NARROW[val];
roseWire.mark ← FALSE;
Perturb[simulation, roseWire];
roseWire.notOffChannels ← NIL;
FOR rts: RoseTransistors ← roseWire.channels, rts.rest
UNTIL rts=
NIL
DO
roseTransistor: RoseTransistor ← rts.first;
IF TranOn[roseTransistor, roseTransistor.gate.wireLevel]#off THEN roseWire.notOffChannels ← CONS[roseTransistor, roseWire.notOffChannels];
ENDLOOP;
};
[] ← RefTab.Pairs[x: simulation.coreToRoseWires, action: Wire];
};
Initialize:
PUBLIC
PROC [simulation: RoseSimulation] = {
SetWire: RefTab.EachPairAction = {
roseWire: RoseWire ← NARROW[val];
IF roseWire.wireSize#infinite THEN roseWire.wireLevel ← X;
};
[] ← RefTab.Pairs[x: simulation.coreToRoseWires, action: SetWire];
EstablishInvariants[simulation];
};
Settle:
PUBLIC
PROC [simulation: RoseSimulation] = {
simulation.settle ← simulation.settle+1;
UNTIL simulation.perturbed=
NIL
DO
simulation.step ← simulation.step+1;
UpdatePerturbed[simulation: simulation];
ENDLOOP;
};
UpdatePerturbed:
PROC [simulation: RoseSimulation] = {
PushWireByStrength:
PROC [wire: RoseWire, thisDrive: 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: Level]
RETURNS [strength: Drive] = {
strength ← IF wire.wireLevel=notLevel THEN none ELSE wire.wireSize;
};
wireSize: Drive ←
SELECT what
FROM
switch => wire.wireSize,
up => UpDownStrength[L],
down => UpDownStrength[H],
ENDCASE => ERROR;
wire.mark ← TRUE;
FOR rts: RoseTransistors ← wire.notOffChannels, rts.rest
UNTIL rts=
NIL
DO
tran: RoseTransistor ← rts.first;
tranCond: Conductance ← TranOn[tran, tran.gate.wireLevel];
otherWire: RoseWire ← tran.ch1;
IF otherWire=wire THEN otherWire ← tran.ch2;
IF otherWire.wireSize=infinite
THEN {
IF ((what=switch AND tranCond=on) OR (what=up AND otherWire.wireLevel#L) OR (what=down AND otherWire.wireLevel#H)) AND wireSize < tran.conductivity THEN wireSize ← tran.conductivity;
}
ELSE IF NOT otherWire.mark THEN FindVicinity[otherWire, what];
ENDLOOP;
FOR rps: RoseProbePrimitives ← wire.probes, rps.rest
UNTIL rps=
NIL
DO
probe: RoseProbePrimitive ← rps.first;
IF ((what=switch AND probe.drive>none) OR (what=up AND probe.level#L) OR (what=down AND probe.level#H)) AND wireSize < probe.drive THEN wireSize ← probe.drive;
ENDLOOP;
IF what#switch AND wireSize < wire.switchDrive THEN wireSize ← none;
PushWireByStrength[wire, wireSize];
SELECT what
FROM
switch => wire.switchDrive ← wireSize;
up => wire.upDrive ← wireSize;
down => wire.downDrive ← wireSize;
ENDCASE => ERROR;
};
PushStrength:
PROC [what: PushWhat] = {
FOR thisDrive: Drive
DECREASING
IN [none..infinite)
DO
firstFreeWire: CARDINAL;
UNTIL (firstFreeWire ← simulation.vicinityByStrength[thisDrive].firstFree)=0
DO
wire: RoseWire ← simulation.vicinityByStrength[thisDrive].wires[ firstFreeWire-1];
wire.mark ← FALSE;
simulation.vicinityByStrength[thisDrive].firstFree ← firstFreeWire-1;
IF thisDrive=none
OR thisDrive < (
SELECT what
FROM
switch => wire.switchDrive,
up => wire.upDrive,
down => wire.downDrive,
ENDCASE => ERROR) THEN LOOP;
FOR rts: RoseTransistors ← wire.notOffChannels, rts.rest
UNTIL rts=
NIL
DO
tran: RoseTransistor ← rts.first;
tranCond: Conductance ← TranOn[tran, tran.gate.wireLevel];
driveThrough: Drive ← MIN[thisDrive, tran.conductivity];
otherWire: RoseWire ← tran.ch1;
IF otherWire=wire THEN otherWire ← tran.ch2;
SELECT what
FROM
switch =>
IF tranCond=on
AND driveThrough > otherWire.switchDrive
THEN {
otherWire.switchDrive ← driveThrough;
PushWireByStrength[otherWire, driveThrough];
};
up =>
IF driveThrough >= otherWire.switchDrive
AND driveThrough > otherWire.upDrive
THEN {
otherWire.upDrive ← driveThrough;
PushWireByStrength[otherWire, driveThrough];
};
down =>
IF driveThrough >= otherWire.switchDrive
AND driveThrough > otherWire.downDrive
THEN {
otherWire.downDrive ← driveThrough;
PushWireByStrength[otherWire, driveThrough];
};
ENDCASE => ERROR;
ENDLOOP;
ENDLOOP;
ENDLOOP;
};
UpdateRecomputed:
PROC = {
FOR thisWire: RoseWire ← recomputed, thisWire.nextRecomputed
UNTIL thisWire=
NIL
DO
wireLevel: Level ←
SELECT
TRUE
FROM
thisWire.upDrive=none AND thisWire.downDrive>=force => L,
thisWire.downDrive=none AND thisWire.upDrive>=force => H,
ENDCASE => X;
IF thisWire.wireLevel#wireLevel
THEN {
FOR rts: RoseTransistors ← thisWire.gates, rts.rest
UNTIL rts=
NIL
DO
CheckAddOrRemove:
PROC [channel: RoseWire] = {
IF channel.channels#
NIL
THEN
SELECT
TRUE
FROM
wasNotOff
AND
NOT isNotOff => {
trail: RoseTransistors ← NIL;
FOR rts: RoseTransistors ← channel.notOffChannels, rts.rest
UNTIL rts=
NIL
DO
IF rts.first=tran
THEN {
IF trail=NIL THEN channel.notOffChannels ← rts.rest
ELSE trail.rest ← rts.rest;
EXIT;
};
trail ← rts;
REPEAT FINISHED => ERROR;
ENDLOOP;
};
NOT wasNotOff AND isNotOff => channel.notOffChannels ← CONS[tran, channel.notOffChannels];
ENDCASE;
};
tran: RoseTransistor ← rts.first;
wasNotOff: BOOL ← TranOn[tran, thisWire.wireLevel]#off;
isNotOff: BOOL ← TranOn[tran, wireLevel]#off;
Perturb[simulation, tran.ch1];
Perturb[simulation, tran.ch2];
CheckAddOrRemove[tran.ch1];
CheckAddOrRemove[tran.ch2];
ENDLOOP;
thisWire.wireLevel ← wireLevel;
};
ENDLOOP;
};
recomputed: RoseWire ← NIL;
UNTIL simulation.perturbed=
NIL
DO
FastFindVicinity:
PROC [wire: RoseWire] = {
wire.mark ← TRUE;
IF wire.wireLevel#sameValue
OR wire.probes#
NIL
THEN {
allSameValue ← FALSE;
singleInfiniteNoUnknownConductance ← FALSE;
};
FOR rts: RoseTransistors ← wire.notOffChannels, rts.rest
UNTIL rts=
NIL
DO
tran: RoseTransistor ← rts.first;
tranCond: Conductance ← TranOn[tran, tran.gate.wireLevel];
otherWire: RoseWire ← tran.ch1;
IF otherWire=wire THEN otherWire ← tran.ch2;
IF tranCond=unknown THEN singleInfiniteNoUnknownConductance ← FALSE;
IF otherWire.wireSize=infinite
THEN {
IF infiniteFound AND infiniteValue#otherWire.wireLevel THEN singleInfiniteNoUnknownConductance ← FALSE;
infiniteFound ← TRUE;
infiniteValue ← otherWire.wireLevel;
IF otherWire.wireLevel#sameValue THEN allSameValue ← FALSE;
}
ELSE IF NOT otherWire.mark THEN FastFindVicinity[otherWire];
ENDLOOP;
{
next: RoseWire ← wire.nextPerturbedWire;
previous: RoseWire ← wire.previousPerturbedWire;
IF next#NIL THEN next.previousPerturbedWire ← previous;
IF previous#NIL THEN previous.nextPerturbedWire ← next;
IF simulation.perturbed=wire THEN simulation.perturbed ← next;
wire.nextPerturbedWire ← NIL;
wire.previousPerturbedWire ← NIL;
wire.nextRecomputed ← recomputed;
recomputed ← wire;
wire.nextVicinityWire ← vicinityWire;
vicinityWire ← wire;
};
};
ForceUpDown:
PROC [up, down: Drive] = {
FOR thisWire: RoseWire ← vicinityWire, thisWire.nextVicinityWire
UNTIL thisWire=
NIL
DO
thisWire.mark ← FALSE;
thisWire.upDrive ← up;
thisWire.downDrive ← down;
ENDLOOP;
};
wire: RoseWire ← simulation.perturbed;
vicinityWire: RoseWire ← NIL;
infiniteFound: BOOL ← FALSE;
infiniteValue: Level ← X;
singleInfiniteNoUnknownConductance: BOOL ← TRUE;
allSameValue: BOOL ← TRUE;
sameValue: Level ← wire.wireLevel;
FastFindVicinity[wire];
SELECT
TRUE
FROM
infiniteFound
AND singleInfiniteNoUnknownConductance => {
SELECT infiniteValue
FROM
L => ForceUpDown[none, infinite];
H => ForceUpDown[infinite, none];
ENDCASE => ERROR;
};
allSameValue => {
strength: Drive ← IF infiniteFound THEN infinite ELSE charge;
SELECT sameValue
FROM
L => ForceUpDown[none, strength];
H => ForceUpDown[strength, none];
X => ForceUpDown[strength, strength];
ENDCASE => ERROR;
}
ENDCASE => {
FOR thisWire: RoseWire ← vicinityWire, thisWire.nextVicinityWire
UNTIL thisWire=
NIL
DO
thisWire.mark ← FALSE;
ENDLOOP;
FindVicinity[wire, switch];
PushStrength[switch];
FindVicinity[wire, up];
PushStrength[up];
FindVicinity[wire, down];
PushStrength[down];
};
ENDLOOP;
UpdateRecomputed[];
};
TranOn:
PROC [tran: RoseTransistor, gateValue: Level]
RETURNS [cond: Conductance] = {
cond ←
SELECT tran.transistorType
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;
};
Perturb:
PROC [simulation: RoseSimulation, wire: RoseWire] = {
IF wire.nextPerturbedWire=
NIL
AND wire.previousPerturbedWire=
NIL
AND simulation.perturbed#wire
AND wire.wireSize<infinite
THEN {
currentHead: RoseWire ← simulation.perturbed;
wire.nextPerturbedWire ← currentHead;
IF currentHead#NIL THEN currentHead.previousPerturbedWire ← wire;
simulation.perturbed ← wire;
};
};