RoseRunImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reversed.
Barth, August 1, 1985 2:31:39 pm PDT
Spreitzer, October 2, 1985 10:27:48 pm PDT
DIRECTORY Core, CoreFlatten, CoreProperties, IO, PrincOps, PrincOpsUtils, Rope, RoseBehavior, RoseBind, RoseBindPrivate, RoseControl, RoseEngine, RoseEvents, RosePrivates, RoseSimTypes, RoseWireTwiddling, RoseWireTypes, RoseWiring;
RoseRunImpl:
CEDAR
PROGRAM
IMPORTS CoreProperties, PrincOpsUtils, RoseEngine, RoseEvents, RoseSimTypes, RoseWireTwiddling
EXPORTS RoseBind, RoseControl, RoseEngine, RoseSimTypes
=
Simulator Assumptions
A cell's newIO doesn't change, except when the cell's ValsChanged or EvalSimple is called, or when this module changes it.
An effective port is transduced iff the node connected to it is switch-level and the cell type speaks simple.
Simulator Invariants
All simple effective ports are always linked according to their curStrength, which tries to track what the cell is saying, but may get behind.
For simple ports, the cell's newIO always contains the current value.
For transduced effective ports, the newIO and switchIO fields are always related by Transduce.
Simulator Theorems
You can't do a non-steady-state simulation when you have any x-phobic wires.
BEGIN OPEN RoseWireTypes, RoseSimTypes, RoseEngine;
BehaviorClassRec: PUBLIC TYPE = RoseBindPrivate.BehaviorClassRec;
SimulationRec: PUBLIC TYPE = RoseSimTypes.SimulationRec;
Error: PUBLIC ERROR [msg: ROPE, data: REF ANY ← NIL] = CODE;
Warning: PUBLIC SIGNAL [msg: ROPE, data: REF ANY ← NIL] = CODE;
Stop: PUBLIC SIGNAL [msg: ROPE, data: REF ANY ← NIL] = CODE;
stop: BOOL ← FALSE;
Run:
PROC [simulation: Simulation, steady:
BOOL ←
TRUE] = {
InitSimulator[simulation, steady];
WHILE StepSim[simulation] # noStep
DO
IF stop THEN SIGNAL Stop[msg: "Stopped", data: simulation];
ENDLOOP;
steady ← steady;
};
InitSimulator:
PUBLIC
PROC [sim: Simulation, steady:
BOOL] = {
sch: Scheduling = sim.sch;
bbTableSpace: PrincOps.BBTableSpace;
bbTable: PrincOps.BitBltTablePtr;
InitWire:
PROC [w: Wire] = {
wg: WireGroup ← GetWireGroup[w];
SELECT wg
FROM
belowLeaf => ERROR;
aboveLeaf => {
IF w.structure = atom THEN ERROR;
FOR i:
INT
IN [0 .. w.elements.size)
DO
InitWire[w.elements[i]];
ENDLOOP;
w ← w;
};
leaf => {
rw: RoseWire ← GetRoseWire[w];
IF rw.XPhobic AND NOT steady THEN ERROR;
rw.type.class.super.Initialize[
rw.type,
rw.valPtr,
steady];
rw.winnerStrength ← rw.holdStrength ← rw.capStrength;
FOR s: Strength
IN (none ..
LAST[Strength]]
DO
w ← w;
WHILE rw.byStrength[s].first # nilSlot
DO
ReStrengthLink[rw, rw.byStrength[s].first, none];
ENDLOOP;
w ← w;
ENDLOOP;
rw.nextPerturbed ← rw.nextAffected ← rw.nextDelayed ← rw.prevDelayed ← notInWireList;
};
ENDCASE => ERROR;
};
StartWire:
PROC [w: Wire] = {
wg: WireGroup ← GetWireGroup[w];
SELECT wg
FROM
belowLeaf => ERROR;
aboveLeaf => {
IF w.structure = atom THEN ERROR;
FOR i:
INT
IN [0 .. w.elements.size)
DO
StartWire[w.elements[i]];
ENDLOOP;
w ← w;
};
leaf => {
rw: RoseWire ← GetRoseWire[w];
SELECT rw.type.class.super.flavor
FROM
switch => PerturbWire[rw, nilModelSlot];
simple => UpdateCurrent[rw, bbTable, nilModelSlot];
drive => ERROR;
ENDCASE => ERROR;
};
ENDCASE => ERROR;
};
TRUSTED {bbTable ← PrincOpsUtils.AlignedBBTable[@bbTableSpace]};
IF FIRST[Strength] # none THEN ERROR;
IF sch.running THEN ERROR;
sch.schedFirst ← sch.schedLast ← sch.firstNeeded ← NIL;
sch.firstPerturbed ← sch.firstAffected ← sch.firstDelayed ← sch.lastDelayed ← NIL;
InitWire[sim.rootRecordType.internalWire];
sim ← sim;
FOR cil: CellInstanceList ← sim.rootRecordType.instances, cil.rest
WHILE cil #
NIL
DO
ci: CellInstance = cil.first;
rci: RoseCellInstance = GetRoseCell[ci];
rci.schedNext ← rci.nextNeeded ← rci.nextNoted ← notInCellList;
rci.affectedFlags ← ALL[FALSE];
rci.initQed ← rci.propQed ← rci.initUDed ← rci.propUDed ← FALSE;
ScheduleCell[rci];
FOR epi: EffectivePortIndex
IN [0 .. rci.effectivePorts.length)
DO
rw: RoseWire = rci.connectedWires[epi];
drivePtr: Ptr = rci.effectivePorts[epi].newDrive;
targType: RoseWireType = rci.effectivePorts[epi].implType;
modelType: RoseWireType = rci.effectivePorts[epi].type;
portPtr: Ptr =
SELECT targType.class.super.flavor
FROM
simple => rci.effectivePorts[epi].newSimple,
switch => rci.effectivePorts[epi].switch,
drive => ERROR,
ENDCASE => ERROR;
SELECT modelType.class.super.flavor
FROM
simple => NULL;
switch => LOOP;
drive => ERROR;
ENDCASE => ERROR;
SELECT targType.class.super.flavor
FROM
simple => IF rci.effectivePorts[epi].curStrength # none THEN ERROR;
switch => NULL;
drive => ERROR;
ENDCASE => ERROR;
RoseWireTwiddling.WriteDrive[drivePtr, none];
RoseWireTwiddling.CopyVal[
fromT: rw.type,
fromP: rw.valPtr,
toT: targType,
toP: portPtr,
bbTable: bbTable];
IF rci.effectivePorts[epi].transduced
THEN {
modelPtr: Ptr = rci.effectivePorts[epi].newSimple;
IF modelPtr = portPtr THEN ERROR;
targType.class.super.Transduce[
fromS: FIRST[Strength],
fromT: targType,
fromP: portPtr,
toT: modelType,
toP: modelPtr];
modelType.class.super.Transduce[
fromS: none,
fromT: modelType,
fromP: modelPtr,
toT: targType,
toP: portPtr];
};
ENDLOOP;
sim ← sim;
ENDLOOP;
StartWire[sim.rootRecordType.internalWire];
sim ← sim;
};
StepSim:
PUBLIC
PROC [sim: Simulation]
RETURNS [stepType: StepType] =
BEGIN
SELECT stepType ← Next[sim]
FROM
noStep => NULL;
switchStep => SwitchStepSim[sim];
otherStep => SimpleStepSim[sim];
ENDCASE => ERROR;
IF stepType # noStep
AND Next[sim] = noStep
THEN {
RoseEvents.Notify[event: $Settled, watched: sim];
CheckDelays[sim];
};
END;
Next:
PUBLIC
PROC [sim: Simulation]
RETURNS [stepType: StepType] =
BEGIN
sch: Scheduling = sim.sch;
IF sch.schedFirst # NIL THEN RETURN [otherStep];
IF sch.firstPerturbed # NIL THEN RETURN [switchStep];
stepType ← noStep;
END;
CheckDelays:
PROC [sim: Simulation] = {
sch: Scheduling = sim.sch;
wires: RoseWireList ← NIL;
FOR rw: RoseWire ← sch.firstDelayed, rw.nextDelayed
WHILE rw #
NIL
DO
IF rw = notInWireList THEN ERROR;
wires ← CONS[rw, wires];
PerturbWire[rw, nilModelSlot];
ENDLOOP;
IF wires # NIL THEN SIGNAL Warning["Wires want Xes", wires];
};
SimpleStepSim:
PROC [sim: Simulation] = {
sch: Scheduling = sim.sch;
bbTableSpace: PrincOps.BBTableSpace;
bbTable: PrincOps.BitBltTablePtr;
TRUSTED {bbTable ← PrincOpsUtils.AlignedBBTable[@bbTableSpace]};
IF sch.running
THEN
ERROR
ELSE sch.running ←
TRUE;
BEGIN ENABLE UNWIND => {sch.running ← FALSE};
cell: RoseCellInstance;
IF sch.schedFirst = notInCellList THEN ERROR;
IF stop THEN SIGNAL Stop[msg: "Stopped", data: sch];
cell ← PickFromSchedule[sch];
IF cell.type.behaviorClass.details.EvalSimple #
NIL
THEN
BEGIN
Perturb:
PROC [portPath: PortPath] = {
PerturbPP[cell.core.actualWire, portPath, sch, [cell, portPath], FALSE];
};
PreSimple[cell, bbTable];
cell.type.behaviorClass.details.EvalSimple[
argsAny: cell.args,
switchAny: cell.switchIO,
simpleAny: cell.newIO,
strengthAny: cell.newDrive,
stateAny: cell.state,
perturb: Perturb
!
UNWIND => {
ReallyCleanUpAfterModify[cell, sch, TRUE, FALSE, FALSE, bbTable];
Schedule[cell, sch];
}
];
ReallyCleanUpAfterModify[cell, sch, TRUE, FALSE, FALSE, bbTable];
RoseEvents.Notify[event: $Eval, watched: cell];
END;
END;
sch.running ← FALSE;
};
PerturbPP:
PROC [w: Wire, portPath: PortPath, sch: Scheduling, agitator: ModelSlot, evenIfInput:
BOOL] = {
wg: WireGroup = GetWireGroup[w];
SELECT wg
FROM
belowLeaf => ERROR;
leaf => ReallyPerturb[GetRoseWire[w], sch, sch.sim, agitator, evenIfInput];
aboveLeaf => PerturbPP[w.elements[portPath.first], portPath.rest, sch, agitator, evenIfInput];
ENDCASE => ERROR;
};
PickFromSchedule:
PROC [sch: Scheduling]
RETURNS [rci: RoseCellInstance] =
BEGIN
rci ← sch.schedFirst;
IF (sch.schedFirst ← rci.schedNext) = NIL THEN sch.schedLast ← NIL;
rci.schedNext ← notInCellList;
RoseEvents.Notify[event: $Schedule, watched: rci];
IF sch.schedFirst = NIL THEN RETURN;
RoseEvents.Notify[event: $Schedule, watched: sch.schedFirst];
END;
ScheduleCell:
PUBLIC
PROC [cell: RoseCellInstance] =
{Schedule[cell, cell.schIn]};
Schedule:
PROC [rci: RoseCellInstance, sch: Scheduling] =
BEGIN
IF rci.schedNext # notInCellList THEN RETURN;
rci.schedNext ← NIL;
IF sch.schedLast = NIL THEN sch.schedFirst ← rci ELSE sch.schedLast.schedNext ← rci;
sch.schedLast ← rci;
RoseEvents.Notify[event: $Schedule, watched: rci];
END;
PreSimple:
PROC [rci: RoseCellInstance, bbTable: PrincOps.BitBltTablePtr, reallyCopy:
BOOL ←
TRUE] =
BEGIN
IF reallyCopy
AND rci.hasTransducedPort
THEN {
simpleType: RoseWireType = rci.type.wireTypes[simple];
driveType: RoseWireType = rci.type.wireTypes[drive];
RoseWireTwiddling.CopyVal[
fromT: simpleType,
toT: simpleType,
fromP: RoseWireTwiddling.RefToPtr[rci.newIO, simpleType],
toP: RoseWireTwiddling.RefToPtr[rci.oldIO, simpleType],
bbTable: bbTable
];
RoseWireTwiddling.CopyVal[
fromT: driveType,
toT: driveType,
fromP: RoseWireTwiddling.RefToPtr[rci.newDrive, driveType],
toP: RoseWireTwiddling.RefToPtr[rci.oldDrive, driveType],
bbTable: bbTable
];
};
END;
ReallyCleanUpAfterModify:
PROC [rci: RoseCellInstance, sch: Scheduling, outputsOnly, blindly, mayRescheduleSelf:
BOOLEAN, bbTable: PrincOps.BitBltTablePtr] =
BEGIN
FOR effectivePortIndex: EffectivePortIndex
IN [0 .. rci.effectivePorts.length)
DO
ep: EffectivePort = rci.effectivePorts[effectivePortIndex];
newPtr: Ptr = ep.newSimple;
rw: RoseWire = rci.connectedWires[effectivePortIndex];
newStrength: Strength;
valDiff, strengthDiff: BOOLEAN ← FALSE;
simpleBits: NAT;
SELECT ep.type.class.super.flavor
FROM
simple => NULL;
switch => LOOP;
drive => ERROR;
ENDCASE => ERROR;
newStrength ← RoseWireTwiddling.ReadDrive[ep.newDrive];
IF (NOT ep.output) AND newStrength > none THEN ERROR Error["Someone lied about outputness of port"];
IF outputsOnly AND NOT ep.output THEN LOOP;
simpleBits ← ep.type.class.super.Bits[ep.type];
IF ep.transduced
THEN {
oldStrength: Strength = RoseWireTwiddling.ReadDrive[ep.oldDrive];
oldPtr: Ptr = ep.oldSimple;
IF blindly THEN valDiff ← strengthDiff ← TRUE
ELSE {
strengthDiff ← oldStrength # newStrength;
valDiff ← NOT RoseWireTwiddling.EqualVal[ep.type, ep.type, oldPtr, newPtr];
};
IF valDiff
OR strengthDiff
THEN {
implPtr: Ptr = ep.switch;
ep.type.class.super.Transduce[fromS: newStrength, fromT: ep.type, toT: ep.implType, fromP: newPtr, toP: implPtr];
};
IF (valDiff
AND newStrength >= rw.holdStrength)
OR (strengthDiff
AND (newStrength >= rw.holdStrength
OR oldStrength >= rw.holdStrength))
THEN {
ReallyPerturb[rw: rw, sch: sch, sim: sch.sim, agitator: [rci, ep.path]];
};
}
ELSE {
handled: BOOL ← FALSE;
strengthDiff ← newStrength # rci.effectivePorts[effectivePortIndex].curStrength;
valDiff ← NOT RoseWireTwiddling.EqualVal[ep.type, rw.type, newPtr, rw.valPtr];
IF strengthDiff
THEN {
ReStrengthLink[rw, [rci, effectivePortIndex], newStrength];
IF EmptyStrengthSet[rw, rw.winnerStrength]
OR newStrength > rw.winnerStrength
THEN {
UpdateCurrent[rw, bbTable, [rci, ep.path]];
handled ← TRUE};
};
IF newStrength > rw.winnerStrength THEN ERROR;
IF newStrength = rw.winnerStrength
AND
NOT handled
THEN {
IF valDiff
THEN {
ep: EffectivePort = rci.effectivePorts[effectivePortIndex];
another: Slot =
IF ep.strengthNext # head THEN ep.strengthNext ELSE
IF ep.strengthPrev # head THEN ep.strengthPrev ELSE
nilSlot;
alone: BOOL ← another = nilSlot AND newStrength > rw.holdStrength;
IF alone
THEN
--alone at the top-- {
Distribute[
baseType: ep.type,
base: newPtr,
fromWire: rw,
avoidCell: IF NOT mayRescheduleSelf THEN rci ELSE NIL,
sch: sch,
bbTable: bbTable,
agitator: [rci, ep.path]];
}
ELSE SIGNAL Warning["Inconsistency"];
};
};
IF newStrength < rw.winnerStrength
THEN {
RoseWireTwiddling.CopyVal[fromT: rw.type, fromP: rw.valPtr, toT: ep.type, toP: newPtr, bbTable: bbTable];
};
};
blindly ← blindly;
ENDLOOP;
blindly ← blindly;
END;
ReStrengthLink:
PROC [rw: RoseWire, slot: Slot, newStrength: Strength] = {
t: Slot;
eps: EffectivePortS ← slot.cell.effectivePorts;
IF eps[slot.effectivePortIndex].curStrength
IN Strength
THEN {
oldStrength: Strength ← eps[slot.effectivePortIndex].curStrength;
IF (t ← eps[slot.effectivePortIndex].strengthNext) # head
THEN {
IF t = slot THEN ERROR;
t.cell.effectivePorts[t.effectivePortIndex].strengthPrev ← eps[slot.effectivePortIndex].strengthPrev
}
ELSE rw.byStrength[oldStrength].last ← eps[slot.effectivePortIndex].strengthPrev;
IF (t ← eps[slot.effectivePortIndex].strengthPrev) # head
THEN {
IF t = slot THEN ERROR;
t.cell.effectivePorts[t.effectivePortIndex].strengthNext ← eps[slot.effectivePortIndex].strengthNext
}
ELSE rw.byStrength[oldStrength].first ← eps[slot.effectivePortIndex].strengthNext;
};
eps[slot.effectivePortIndex].strengthNext ← rw.byStrength[newStrength].first;
eps[slot.effectivePortIndex].strengthPrev ← head;
IF (t ← rw.byStrength[newStrength].first) # head
THEN t.cell.effectivePorts[t.effectivePortIndex].strengthPrev ← slot
ELSE rw.byStrength[newStrength].last ← slot;
rw.byStrength[newStrength].first ← slot;
eps[slot.effectivePortIndex].curStrength ← newStrength;
};
EmptyStrengthSet:
PROC [rw: RoseWire, strength: Strength]
RETURNS [empty:
BOOL] =
{empty ← rw.byStrength[strength] = emptyHead};
UpdateCurrent:
PROC [rw: RoseWire, bbTable: PrincOps.BitBltTablePtr, agitator: ModelSlot] = {
aPtr: Ptr ← nilPtr;
aType: RoseWireType ← NIL;
SELECT rw.type.class.super.flavor
FROM
simple => NULL;
switch, drive => ERROR;
ENDCASE => ERROR;
FOR s: Strength
DECREASING
IN Strength
DO
IF (NOT EmptyStrengthSet[rw, s]) OR (s = rw.holdStrength) THEN {rw.winnerStrength ← s; EXIT};
ENDLOOP;
IF rw.winnerStrength = rw.holdStrength THEN RETURN;
IF rw.winnerStrength < rw.holdStrength THEN ERROR;
FOR s: Slot ← rw.byStrength[rw.winnerStrength].first, s.cell.effectivePorts[s.effectivePortIndex].strengthNext
WHILE s # head
DO
ePtr: Ptr = s.cell.effectivePorts[s.effectivePortIndex].newSimple;
eType: RoseWireType = s.cell.effectivePorts[s.effectivePortIndex].type;
SELECT aPtr
FROM
=nilPtr => {aPtr ← ePtr; aType ← eType};
#nilPtr => {
IF NOT RoseWireTwiddling.EqualVal[aType, eType, aPtr, ePtr] THEN SIGNAL Warning["Inconsistency"];
};
ENDCASE => ERROR;
ENDLOOP;
IF aPtr = nilPtr THEN ERROR;
Distribute[
baseType: aType,
base: aPtr,
fromWire: rw,
avoidStrength: rw.winnerStrength,
sch: rw.schIn,
bbTable: bbTable,
agitator: agitator
];
};
Distribute:
PROC
[
baseType: RoseWireType,
base: Ptr,
fromWire: RoseWire,
avoidCell: RoseCellInstance ← NIL,
avoidStrength: Drive ← none,
sch: Scheduling,
bbTable: PrincOps.BitBltTablePtr,
agitator: ModelSlot] =
BEGIN
SELECT fromWire.type.class.super.flavor
FROM
simple => NULL;
switch, drive => ERROR;
ENDCASE => ERROR;
IF base # fromWire.valPtr THEN RoseWireTwiddling.CopyVal[fromT: baseType, fromP: base, toT: fromWire.type, toP: fromWire.valPtr, bbTable: bbTable];
FOR s: Strength
IN Strength
DO
FOR dest: Slot ← fromWire.byStrength[s].first, dest.cell.effectivePorts[dest.effectivePortIndex].strengthNext
WHILE dest # head
DO
dep: EffectivePort ← dest.cell.effectivePorts[dest.effectivePortIndex];
RoseWireTwiddling.CopyVal[fromT: baseType, fromP: base, toT: dep.type, toP: dep.newSimple, bbTable: bbTable];
IF dest.cell # avoidCell THEN Schedule[dest.cell, sch];
ENDLOOP;
ENDLOOP;
reportSlot^ ← agitator;
RoseEvents.Notify[event: $ChangeEarly, watched: fromWire, arg: reportSlot];
RoseEvents.Notify[event: $ChangeLate, watched: fromWire, arg: reportSlot];
END;
SwitchStepSim:
PROC [sim: Simulation] =
BEGIN
sch: Scheduling = sim.sch;
bbTableSpace: PrincOps.BBTableSpace;
bbTable: PrincOps.BitBltTablePtr;
TRUSTED {bbTable ← PrincOpsUtils.AlignedBBTable[@bbTableSpace]};
StrFindVicinity[sch, FALSE];
StrInitQ[sch];
StrPropQWork[sch];
StrInitUD[sch];
StrPropUDWork[sch];
StrFinalUD[sch, bbTable];
END;
StrFindVicinity:
PROC [sch: Scheduling, evenIfInput:
BOOL] =
BEGIN
this: RoseWire;
WHILE sch.firstPerturbed #
NIL
DO
IF sch.firstPerturbed = notInWireList THEN ERROR;
this ← sch.firstPerturbed;
sch.firstPerturbed ← this.nextPerturbed;
this.nextPerturbed ← notInWireList;
ReallyFindVicinity[sch, this, this.isInput, nilModelSlot];
ENDLOOP;
END;
ReallyFindVicinity:
PROC [sch: Scheduling, rw: RoseWire, evenIfInput:
BOOL, from: ModelSlot] =
BEGIN
IF rw.found THEN RETURN;
IF rw.isInput AND NOT evenIfInput THEN RETURN;
rw.found ← TRUE;
IF sch.firstAffected = notInWireList THEN ERROR;
rw.nextAffected ← sch.firstAffected;
sch.firstAffected ← rw;
reportSlot^ ← from;
NoteNews[$Found, rw, reportSlot];
FOR sl: SlotList ← rw.switchConnections, sl.rest
WHILE sl #
NIL
DO
s: Slot = sl.first;
rci: RoseCellInstance = s.cell;
RecursivelyFindVicinity:
PROC [portPath: PortPath] = {
FindPPVicinity[sch, rci.core.actualWire, portPath, evenIfInput, [s.cell, portPath]];
};
IF rci.type.behaviorClass.details.EnumerateVicinity #
NIL
THEN rci.type.behaviorClass.details.EnumerateVicinity[
argsAny: rci.args,
stateAny: rci.state,
portPath: rci.effectivePorts[s.effectivePortIndex].path,
evenIfInput: evenIfInput,
consume: RecursivelyFindVicinity
];
rci.affectedFlags[Specialty[s]] ← TRUE;
ENDLOOP;
END;
FindPPVicinity:
PROC [sch: Scheduling, w: Wire, portPath: PortPath, evenIfInput:
BOOL, from: ModelSlot] = {
wg: WireGroup = GetWireGroup[w];
SELECT wg
FROM
belowLeaf => ERROR;
leaf => ReallyFindVicinity[sch, GetRoseWire[w], evenIfInput, from];
aboveLeaf => {
FindPPVicinity[sch, w.elements[portPath.first], portPath.rest, evenIfInput, from];
};
ENDCASE => ERROR;
};
StrInitQ:
PROC [sch: Scheduling] =
BEGIN
FOR n: RoseWire ← sch.firstAffected, n.nextAffected
WHILE n #
NIL
DO
IF n = notInWireList THEN ERROR;
IF n.type.class.super.InitQ # NIL THEN n.type.class.super.InitQ[n.type, n.valPtr, n.holdStrength];
NoteNews[news: $NewNodeQ, rw: n, arg: NIL];
Need1[sch, n, InitQ];
ENDLOOP;
END;
InitQ:
PROC [cell: RoseCellInstance] = {
IF
NOT cell.initQed
THEN {
cell.initQed ← TRUE;
CallEval[cell, cell.type.behaviorClass.details.InitQ];
};
};
CallEval:
PROC [rci: RoseCellInstance, Proc: RoseBehavior.EvalProc] =
INLINE {
IF Proc #
NIL
THEN Proc[
argsAny: rci.args,
switchAny: rci.switchIO,
simpleAny: rci.newIO,
strengthAny: rci.newDrive,
stateAny: rci.state,
perturb: NIL];
};
CellProc: TYPE = PROC [RoseCellInstance];
Need1:
PROC [sch: Scheduling, n: RoseWire, also: CellProc] =
BEGIN
FOR sl: SlotList ← n.switchConnections, sl.rest
WHILE sl #
NIL
DO
IF sl.first.cell.nextNeeded = notInCellList
THEN
BEGIN
IF sch.firstNeeded = notInCellList THEN ERROR;
sl.first.cell.nextNeeded ← sch.firstNeeded;
sch.firstNeeded ← sl.first.cell;
IF also # NIL THEN also[sl.first.cell];
END;
ENDLOOP;
END;
StrPropQWork:
PROC [sch: Scheduling] =
BEGIN
WHILE sch.firstNeeded #
NIL
DO
needed: RoseCellInstance ← sch.firstNeeded;
IF needed = notInCellList THEN ERROR;
sch.firstNeeded ← needed.nextNeeded;
needed.nextNeeded ← notInCellList;
needed.initQed ← FALSE;
IF NOT (needed.type.behaviorClass.details.PropQ # NIL OR needed.hasTransducedPort) THEN LOOP;
IF needed.type.behaviorClass.details.PropQ #
NIL
THEN {
FOR epi: EffectivePortIndex
IN [0 .. needed.effectivePorts.length)
DO
ep: EffectivePort ← needed.effectivePorts[epi];
IF
ep.implType.class.super.flavor = switch AND NOT ep.transduced
THEN RoseWireTwiddling.CopyQ[
fromT: needed.connectedWires[epi].type,
fromP: needed.connectedWires[epi].valPtr,
toT: ep.implType,
toP: ep.switch
];
ENDLOOP;
CallEval[needed, needed.type.behaviorClass.details.PropQ];
};
FOR epi: EffectivePortIndex
IN [0 .. needed.effectivePorts.length)
DO
n: RoseWire ← needed.connectedWires[epi];
change: BOOL;
IF n.type.class.super.flavor # switch THEN LOOP;
IF n.nextAffected = notInWireList THEN ERROR;
change ← RoseWireTwiddling.MaxinQ[
fromT: needed.effectivePorts[epi].implType,
fromP: needed.effectivePorts[epi].switch,
toT: n.type,
toP: n.valPtr];
IF change
THEN {
reportSlot^ ← [needed, needed.effectivePorts[epi].path];
NoteNews[news: $NewNodeQ, rw: n, arg: reportSlot];
Need2[sch, n, needed];
};
ENDLOOP;
sch ← sch;
ENDLOOP;
sch ← sch;
END;
Need2:
PROC [sch: Scheduling, n: RoseWire, except: RoseCellInstance] =
BEGIN
FOR sl: SlotList ← n.switchConnections, sl.rest
WHILE sl #
NIL
DO
IF sl.first.cell.nextNeeded = notInCellList
AND sl.first.cell # except
THEN {
IF sch.firstNeeded = notInCellList THEN ERROR;
sl.first.cell.nextNeeded ← sch.firstNeeded;
sch.firstNeeded ← sl.first.cell;
};
ENDLOOP;
sch ← sch;
END;
StrInitUD:
PROC [sch: Scheduling] =
BEGIN
FOR n: RoseWire ← sch.firstAffected, n.nextAffected
WHILE n #
NIL
DO
IF n = notInWireList THEN ERROR;
IF n.type.class.super.InitUD # NIL THEN n.isInput ← n.type.class.super.InitUD[n.type, n.valPtr, n.holdStrength];
NoteNews[news: $NewNodeUD, rw: n, arg: NIL];
Need1[sch, n, InitUD];
ENDLOOP;
END;
InitUD:
PROC [cell: RoseCellInstance] = {
IF
NOT cell.initUDed
THEN {
cell.initUDed ← TRUE;
CallEval[cell, cell.type.behaviorClass.details.InitUD];
};
};
StrPropUDWork:
PROC [sch: Scheduling] =
BEGIN
WHILE sch.firstNeeded #
NIL
DO
needed: RoseCellInstance ← sch.firstNeeded;
IF needed = notInCellList THEN ERROR;
sch.firstNeeded ← needed.nextNeeded;
needed.nextNeeded ← notInCellList;
needed.initUDed ← FALSE;
IF (needed.type.behaviorClass.details.PropUD = NIL) AND (NOT needed.hasTransducedPort) THEN LOOP;
IF needed.type.behaviorClass.details.PropUD #
NIL
THEN {
FOR epi: EffectivePortIndex
IN [0 .. needed.effectivePorts.length)
DO
ep: EffectivePort ← needed.effectivePorts[epi];
IF
ep.implType.class.super.flavor = switch AND NOT ep.transduced
THEN RoseWireTwiddling.CopyUD[
fromT: needed.connectedWires[epi].type,
fromP: needed.connectedWires[epi].valPtr,
toT: ep.implType,
toP: ep.switch];
ENDLOOP;
CallEval[needed, needed.type.behaviorClass.details.PropUD];
};
FOR epi: EffectivePortIndex
IN [0 .. needed.effectivePorts.length)
DO
n: RoseWire ← needed.connectedWires[epi];
change: BOOL;
IF n.type.class.super.flavor # switch THEN LOOP;
IF n.nextAffected = notInWireList THEN ERROR;
change ← RoseWireTwiddling.MaxinUD[
fromT: needed.effectivePorts[epi].implType,
fromP: needed.effectivePorts[epi].switch,
toT: n.type,
toP: n.valPtr];
IF change
THEN {
reportSlot^ ← [needed, needed.effectivePorts[epi].path];
NoteNews[news: $NewNodeUD, rw: n, arg: reportSlot];
Need2[sch, n, needed];
};
ENDLOOP;
sch ← sch;
ENDLOOP;
sch ← sch;
END;
StrFinalUD:
PROC [sch: Scheduling, bbTable: PrincOps.BitBltTablePtr] =
BEGIN
firstNoted, next: RoseCellInstance ← NIL;
FOR n: RoseWire ← sch.firstAffected, n.nextAffected
WHILE n #
NIL
DO
delay: BOOL ← FALSE;
IF n = notInWireList THEN ERROR;
n.found ← FALSE;
IF n.type.class.super.ComputeLevel # NIL THEN delay ← n.type.class.super.ComputeLevel[n.type, n.valPtr, n.XPhobic];
SetDelayedness[n, delay];
IF NOT delay THEN DistributeSwitch[n, bbTable, FALSE];
FOR sl: SlotList ← n.switchConnections, sl.rest
WHILE sl #
NIL
DO
IF sl.first.cell.nextNoted = notInCellList
THEN
{sl.first.cell.nextNoted ← firstNoted; firstNoted ← sl.first.cell};
ENDLOOP;
ENDLOOP;
sch.firstAffected ← NIL;
FOR firstNoted ← firstNoted, next
WHILE firstNoted #
NIL
DO
IF firstNoted = notInCellList THEN ERROR;
next ← firstNoted.nextNoted;
firstNoted.nextNoted ← notInCellList;
CallEval[firstNoted, firstNoted.type.behaviorClass.details.FinalUD];
IF firstNoted.affectedFlags[transducedToSwitch] THEN ScheduleCell[firstNoted];
ValsChanged[firstNoted, sch, bbTable];
firstNoted.affectedFlags ← ALL[FALSE];
ENDLOOP;
sch ← sch;
END;
SetDelayedness:
PROC [n: RoseWire, delay:
BOOL] = {
sch: Scheduling = n.schIn;
IF delay = (n.nextDelayed # notInWireList) THEN RETURN;
IF delay
THEN {
IF sch.firstDelayed = notInWireList THEN ERROR;
n.nextDelayed ← sch.firstDelayed;
n.prevDelayed ← NIL;
IF n.nextDelayed = NIL THEN sch.lastDelayed ← n ELSE n.nextDelayed.prevDelayed ← n;
sch.firstDelayed ← n;
}
ELSE {
IF n.nextDelayed = NIL THEN sch.lastDelayed ← n.prevDelayed ELSE n.nextDelayed.prevDelayed ← n.prevDelayed;
IF n.prevDelayed = NIL THEN sch.firstDelayed ← n.nextDelayed ELSE n.prevDelayed.nextDelayed ← n.nextDelayed;
n.nextDelayed ← n.prevDelayed ← notInWireList;
};
};
DistributeSwitch:
PROC [node: RoseWire, bbTable: PrincOps.BitBltTablePtr, perturb:
BOOL] = {
IF node.type.class.super.flavor # switch THEN ERROR;
IF perturb THEN PerturbWire[node, nilModelSlot, TRUE];
FOR sl: SlotList ← node.switchConnections, sl.rest
WHILE sl #
NIL
DO
cell: RoseCellInstance ← sl.first.cell;
epi: EffectivePortIndex ← sl.first.effectivePortIndex;
ep: EffectivePort ← cell.effectivePorts[epi];
implPtr: Ptr ← ep.switch;
IF ep.implType.class.super.flavor # simple
THEN RoseWireTwiddling.CopyLevel[
fromT: cell.connectedWires[epi].type,
fromP: cell.connectedWires[epi].valPtr,
toT: ep.implType,
toP: implPtr];
IF ep.transduced
THEN {
modelPtr: Ptr ← ep.newSimple;
ep.implType.class.super.Transduce[
fromS: FIRST[Strength],
fromT: ep.implType,
fromP: implPtr,
toT: ep.type,
toP: modelPtr];
};
ENDLOOP;
RoseEvents.Notify[event: $ChangeEarly, watched: node];
RoseEvents.Notify[event: $ChangeLate, watched: node];
};
ValsChanged:
PROC [cell: RoseCellInstance, sch: Scheduling, bbTable: PrincOps.BitBltTablePtr] =
BEGIN
IF cell.type.behaviorClass.details.ValsChanged #
NIL
THEN {
Perturb:
PROC [portPath: PortPath] = {
PerturbPP[cell.core.actualWire, portPath, sch, [cell, portPath], FALSE];
};
PreSimple[cell, bbTable];
cell.type.behaviorClass.details.ValsChanged[
argsAny: cell.args,
switchAny: cell.switchIO,
simpleAny: cell.newIO,
strengthAny: cell.newDrive,
stateAny: cell.state,
perturb: Perturb
!UNWIND => ReallyCleanUpAfterModify[rci: cell, sch: sch, outputsOnly: TRUE, blindly: FALSE, mayRescheduleSelf: TRUE, bbTable: bbTable]];
ReallyCleanUpAfterModify[rci: cell, sch: sch, outputsOnly: TRUE, blindly: FALSE, mayRescheduleSelf: TRUE, bbTable: bbTable];
};
END;
PerturbWire:
PUBLIC
PROC [rw: RoseWire, agitator: ModelSlot, evenIfInput:
BOOL ←
FALSE] = {
sch: Scheduling = rw.schIn;
ReallyPerturb[rw, sch, sch.sim, agitator, evenIfInput];
};
ReallyPerturb:
PROC [rw: RoseWire, sch: Scheduling, sim: Simulation, agitator: ModelSlot, evenIfInput:
BOOL ←
FALSE] =
BEGIN
SELECT rw.type.class.super.flavor
FROM
switch => NULL;
simple, drive => ERROR;
ENDCASE => ERROR;
IF rw.isInput AND NOT evenIfInput THEN RETURN;
IF rw.nextPerturbed = notInWireList
THEN {
IF sch.firstPerturbed = notInWireList THEN ERROR;
rw.nextPerturbed ← sch.firstPerturbed;
sch.firstPerturbed ← rw;
reportSlot^ ← agitator;
NoteNews[news: $Perturbed, rw: rw, arg: reportSlot];
};
END;
reportSlot: REF ModelSlot ← NEW [ModelSlot ← nilModelSlot];
NoteNews:
PROC [news:
ATOM, rw: RoseWire, arg:
REF
ANY] = {
RoseEvents.Notify[event: news, watched: rw, arg: arg];
FOR pl: PieceList ← node.parentPieces, pl.rest WHILE pl # NIL DO
NoteNews[news, pl.first.twardDesign, arg];
ENDLOOP;
};
Specialty:
PROC [st: Slot]
RETURNS [sy: Speciality] = {
ep: EffectivePort ← st.cell.effectivePorts[st.effectivePortIndex];
IF ep.implType.class.super.flavor # switch THEN ERROR;
sy ← IF ep.transduced THEN transducedToSwitch ELSE modeledAsSwitch;
};
TransduceNeeded:
PROC [rwt1, rwt2: RoseWireType]
RETURNS [needed:
BOOL] = {
IF NOT Conforming[nt1, nt2] THEN ERROR --you shouldn't even be asking--;
needed ← rwt1.class.super.flavor # rwt2.class.super.flavor
};
GetRoseCell:
PROC [ci: CellInstance]
RETURNS [rci: RoseCellInstance] = {
rci ← NARROW[CoreProperties.GetProp[ci.properties, roseCellKey]];
};
GetRoseWire:
PROC [w: Wire]
RETURNS [rw: RoseWire] = {
rw ← NARROW[CoreProperties.GetProp[w.properties, roseWireKey]];
};
Start[];
END.