RoseRunImpl.mesa
Last Edited by: Spreitzer, July 2, 1985 8:52:17 pm PDT PDT
Last Edited by: Barth, April 25, 1984 9:54:24 am PST
Last Edited by: Gasbarro, July 17, 1984 4:24:09 pm PDT
DIRECTORY Basics, BitTwiddling, IO, List, OrderedSymbolTableRef, PrincOps, PrincOpsUtils, Rope, RoseCreate, RoseEvents, RoseRun, RoseTypes;
RoseRunImpl: CEDAR PROGRAM
IMPORTS BitTwiddling, IO, PrincOpsUtils, RoseCreate, RoseEvents, RoseTypes
EXPORTS RoseRun, RoseTypes =
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.
BEGIN OPEN BitTwiddling, RoseTypes;
stop: PUBLIC BOOLEANFALSE;
notInStrList: PUBLIC Structure ← NEW [StructureRep];
notInCellList: PUBLIC Cell ← NEW [CellRep];
notInNodeList: PUBLIC Node ← NEW [NodeRep];
reportSlot: REF Slot ← NEW [Slot];
Run: PUBLIC PROC [sim: Simulation] =
BEGIN
WHILE StepSim[sim] # noStep DO
IF stop THEN SIGNAL Stop[msg: "Stopped", data: sim];
ENDLOOP;
END;
Next: PUBLIC PROC [sim: Simulation] RETURNS [stepType: RoseRun.StepType] =
BEGIN
topStr: Structure ← sim.str;
IF topStr.schedFirst # NIL THEN RETURN [otherStep];
IF sim.str.firstPerturbed # NIL THEN RETURN [switchStep];
stepType ← noStep;
END;
StepSim: PUBLIC PROC [sim: Simulation] RETURNS [stepType: RoseRun.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, handleAborted: TRUE];
CheckDelays[sim];
};
END;
SimpleStepSim: PROC [sim: Simulation] = {
str: Structure ← sim.str;
IF str.running THEN ERROR ELSE str.running ← TRUE;
BEGIN ENABLE UNWIND => {str.running ← FALSE};
cell: Cell;
IF str.schedFirst = notInCellList THEN ERROR;
IF stop THEN SIGNAL Stop[msg: "Stopped", data: str];
cell ← PickFromSchedule[str];
IF cell.realCellStuff.evals.EvalSimple # NIL THEN
BEGIN
PerturbPort: PROC [portIndex: PortIndex] = {
FOR epi: EffectivePortIndex ← cell.realCellStuff.effectivePorts[portIndex].firstEffectivePortIndex, epi+1 WHILE epi < cell.realCellStuff.effectivePorts.length AND cell.realCellStuff.effectivePorts[epi].containingPort = portIndex DO
ReallyPerturb[cell.realCellStuff.implNodes[epi], str, cell.sim, [cell, epi], FALSE];
ENDLOOP;
};
PreSimple[cell];
cell.realCellStuff.evals.EvalSimple[
cell: cell,
perturb: PerturbPort
!UNWIND => {
ReallyCleanUpAfterModify[cell, str, TRUE, FALSE, FALSE];
Schedule[cell, str];
}
];
ReallyCleanUpAfterModify[cell, str, TRUE, FALSE, FALSE];
RoseEvents.Notify[event: $Eval, watched: cell, handleAborted: TRUE];
END;
END;
str.running ← FALSE;
};
PickFromSchedule: PROC [str: Structure] RETURNS [cell: Cell] =
BEGIN
cell ← str.schedFirst;
IF (str.schedFirst ← cell.realCellStuff.schedNext) = NIL THEN str.schedLast ← NIL;
cell.realCellStuff.schedNext ← notInCellList;
RoseEvents.Notify[event: $Schedule, watched: cell, handleAborted: TRUE];
IF str.schedFirst = NIL THEN RETURN;
RoseEvents.Notify[event: $Schedule, watched: str.schedFirst, handleAborted: TRUE];
END;
ScheduleCell: PUBLIC PROC [cell: Cell] =
{Schedule[cell, ContainingStr[cell]]};
Schedule: PROC [cell: Cell, str: Structure] =
BEGIN
IF cell.realCellStuff.schedNext # notInCellList THEN RETURN;
cell.realCellStuff.schedNext ← NIL;
IF str.schedLast = NIL THEN str.schedFirst ← cell ELSE str.schedLast.realCellStuff.schedNext ← cell;
str.schedLast ← cell;
RoseEvents.Notify[event: $Schedule, watched: cell, handleAborted: TRUE];
END;
PreSimple: PUBLIC PROC [cell: Cell, reallyCopy: BOOLTRUE] = TRUSTED
BEGIN
IF reallyCopy AND cell.realCellStuff.hasTransducedPort THEN {
n: WordPtr ← cell.realCellStuff.newIOAsWP;
o: WordPtr ← cell.realCellStuff.oldIOAsWP;
FOR i: CARDINAL IN [0 .. cell.type.simpleWordCount) DO
(o+i)^ ← (n+i)^;
ENDLOOP;
FOR portIndex: PortIndex IN [0 .. cell.type.ports.length) DO
cell.realCellStuff.oldDrive[portIndex] ← cell.realCellStuff.newDrive[portIndex];
ENDLOOP;
};
END;
ReallyCleanUpAfterModify: PROC [cell: Cell, str: Structure, outputsOnly, blindly, mayRescheduleSelf: BOOLEAN] =
BEGIN
bbTableSpace: PrincOps.BBTableSpace;
bbTable: PrincOps.BitBltTablePtr;
TRUSTED {bbTable ← PrincOpsUtils.AlignedBBTable[@bbTableSpace]};
FOR effectivePortIndex: EffectivePortIndex IN [0 .. cell.realCellStuff.effectivePorts.length) DO
ep: EffectivePort ← cell.realCellStuff.effectivePorts[effectivePortIndex];
node: Node;
newStrength: Strength;
valDiff, strengthDiff: BOOLEANFALSE;
newPtr: Ptr;
simpleBits: NAT;
IF NOT ep.type.simple THEN LOOP;
newStrength ← cell.realCellStuff.newDrive[ep.containingPort];
IF (NOT ep.output) AND newStrength > ignore THEN ERROR Error[IO.PutFR["%g lied about outputness of port %g", IO.rope[RoseCreate.LongCellName[cell]], IO.rope[ep.name]]];
IF outputsOnly AND NOT ep.output THEN LOOP;
node ← cell.realCellStuff.implNodes[effectivePortIndex];
newPtr ← WPField[cell.realCellStuff.newIOAsWP, ep.simple];
simpleBits ← ep.type.procs.Bits[ep.type].data;
IF TransduceNeeded[ep.type, ep.implType] THEN {
oldStrength: Strength ← cell.realCellStuff.oldDrive[ep.containingPort];
oldPtr: Ptr ← WPField[cell.realCellStuff.oldIOAsWP, ep.simple];
IF blindly THEN valDiff ← strengthDiff ← TRUE
ELSE {
strengthDiff ← oldStrength # newStrength;
valDiff ← NOT Equal[oldPtr, newPtr, simpleBits];
};
IF valDiff OR strengthDiff THEN {
implPtr: Ptr ← WPField[cell.realCellStuff.switchIOAsWP, ep.switch];
ep.type.procs.Transduce[fromS: newStrength, fromT: ep.type, toT: ep.implType, fromP: newPtr, toP: implPtr];
};
IF (valDiff AND newStrength >= node.strength) OR (strengthDiff AND (newStrength >= node.strength OR oldStrength >= node.strength)) THEN {
ReallyPerturb[node: node, str: str, sim: cell.sim, agitator: [cell, effectivePortIndex]];
};
}
ELSE {
strengthDiff ← newStrength # cell.realCellStuff.effectivePorts[effectivePortIndex].curStrength;
valDiff ← NOT Equal[newPtr, node.valPtr, node.bitCount];
IF strengthDiff THEN {
ReStrengthLink[node, [cell, effectivePortIndex], newStrength];
IF EmptyStrengthSet[node, node.currentStrength] OR newStrength > node.currentStrength THEN UpdateCurrent[node, bbTable, [cell, effectivePortIndex]];
};
IF newStrength > node.currentStrength THEN ERROR;
IF newStrength = node.currentStrength THEN {
IF valDiff THEN {
alone: BOOL ← ep.strengthNext = head AND ep.strengthPrev = head AND newStrength > node.strength;
IF alone THEN --alone at the top-- {
Distribute[
base: newPtr,
fromNode: node,
avoidCell: IF NOT mayRescheduleSelf THEN cell ELSE NIL,
str: str,
bitCount: node.bitCount,
bbTable: bbTable,
agitator: [cell, effectivePortIndex]];
}
ELSE SIGNAL Warning["Inconsistency"];
};
};
IF newStrength < node.currentStrength THEN {
Copy[from: node.valPtr, to: newPtr, bitCount: node.bitCount, bbTable: bbTable];
};
};
blindly ← blindly;
ENDLOOP;
blindly ← blindly;
END;
ReStrengthLink: PROC [node: Node, slot: Slot, newStrength: Strength] = {
t: Slot;
eps: EffectivePorts ← slot.cell.realCellStuff.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.realCellStuff.effectivePorts[t.effectivePortIndex].strengthPrev ← eps[slot.effectivePortIndex].strengthPrev
}
ELSE node.byStrength[oldStrength].last ← eps[slot.effectivePortIndex].strengthPrev;
IF (t ← eps[slot.effectivePortIndex].strengthPrev) # head THEN {
IF t = slot THEN ERROR;
t.cell.realCellStuff.effectivePorts[t.effectivePortIndex].strengthNext ← eps[slot.effectivePortIndex].strengthNext
}
ELSE node.byStrength[oldStrength].first ← eps[slot.effectivePortIndex].strengthNext;
};
eps[slot.effectivePortIndex].strengthNext ← node.byStrength[newStrength].first;
eps[slot.effectivePortIndex].strengthPrev ← head;
IF (t ← node.byStrength[newStrength].first) # head
THEN t.cell.realCellStuff.effectivePorts[t.effectivePortIndex].strengthPrev ← slot
ELSE node.byStrength[newStrength].last ← slot;
node.byStrength[newStrength].first ← slot;
eps[slot.effectivePortIndex].curStrength ← newStrength;
};
EmptyStrengthSet: PROC [node: Node, strength: Strength] RETURNS [empty: BOOL] =
{empty ← node.byStrength[strength] = emptyHead};
UpdateCurrent: PUBLIC PROC [node: Node, bbTable: PrincOps.BitBltTablePtr, agitator: Slot] = {
aPtr: Ptr ← nilPtr;
IF NOT node.significances[inImpl] THEN ERROR;
IF NOT node.type.simple THEN ERROR;
FOR s: Strength DECREASING IN Strength DO
IF (NOT EmptyStrengthSet[node, s]) OR (s = node.strength) THEN {node.currentStrength ← s; EXIT};
ENDLOOP;
IF node.currentStrength = node.strength THEN RETURN;
IF node.currentStrength < node.strength THEN ERROR;
FOR s: Slot ← node.byStrength[node.currentStrength].first, s.cell.realCellStuff.effectivePorts[s.effectivePortIndex].strengthNext WHILE s # nilSlot DO
SELECT aPtr FROM
=nilPtr => aPtr ← SlotToPtr[s, FALSE];
#nilPtr => {
IF NOT Equal[aPtr, SlotToPtr[s, FALSE], node.bitCount] THEN SIGNAL Warning["Inconsistency"];
};
ENDCASE => ERROR;
ENDLOOP;
IF aPtr = nilPtr THEN ERROR;
Distribute[
base: aPtr,
fromNode: node,
avoidStrength: node.currentStrength,
str: node.strIn,
bitCount: node.bitCount,
bbTable: bbTable,
agitator: agitator
];
};
Distribute: PROC
[
base: Ptr,
fromNode: Node,
avoidCell: Cell ← NIL,
avoidStrength: DriveLevel ← ignore,
str: Structure,
bitCount: NAT,
bbTable: PrincOps.BitBltTablePtr,
agitator: Slot] =
BEGIN
IF NOT fromNode.type.simple THEN ERROR;
IF base # fromNode.valPtr THEN Copy[from: base, to: fromNode.valPtr, bitCount: bitCount, bbTable: bbTable];
IF fromNode.type.procs.SetNode # NIL THEN fromNode.type.procs.SetNode[fromNode, base];
FOR s: Strength IN Strength DO
FOR dest: Slot ← fromNode.byStrength[s].first, dest.cell.realCellStuff.effectivePorts[dest.effectivePortIndex].strengthNext WHILE dest # head DO
Copy[from: base, to: SlotToPtr[dest, FALSE], bitCount: bitCount, bbTable: bbTable];
IF dest.cell # avoidCell THEN Schedule[dest.cell, str];
ENDLOOP;
ENDLOOP;
reportSlot^ ← agitator;
RoseEvents.Notify[event: $ChangeEarly, watched: fromNode, handleAborted: TRUE, arg: reportSlot];
FOR pl: PieceList ← fromNode.parentPieces, pl.rest WHILE pl # NIL DO
parent: Node ← pl.first.twardDesign;
IF NOT parent.significances[fromDesign] THEN ERROR;
IF NOT parent.type.simple THEN ERROR;
Copy[from: base, to: SubPtr[parent.type, parent.valPtr, pl.first.reln], bitCount: bitCount, bbTable: bbTable];
RoseEvents.Notify[event: $ChangeEarly, watched: parent, handleAborted: TRUE, arg: reportSlot];
RoseEvents.Notify[event: $ChangeLate, watched: parent, handleAborted: TRUE, arg: reportSlot];
ENDLOOP;
RoseEvents.Notify[event: $ChangeLate, watched: fromNode, handleAborted: TRUE, arg: reportSlot];
END;
SubPtr: PROC [parent: NodeType, p: Ptr, s: Selector] RETURNS [sp: Ptr] = {
sp ← OffsetPtr[p, parent.procs.SelectorOffset[parent, s]];
};
SwitchStepSim: PROC [sim: Simulation] =
BEGIN
str: Structure ← sim.str;
StrFindVicinity[str, FALSE];
StrInitQ[str];
StrPropQWork[str];
StrInitUD[str];
StrPropUDWork[str];
StrFinalUD[str];
END;
PerturbNode: PUBLIC PROC [node: Node, agitator: Slot, evenIfInput: BOOLFALSE] = {
str: Structure ← node.strIn;
SELECT node.significances[inImpl] FROM
TRUE => ReallyPerturb[node, str, str.sim, agitator, evenIfInput];
FALSE => FOR pl: PieceList ← node.childPieces, pl.rest WHILE pl # NIL DO
PerturbNode[pl.first.twardImpl, agitator, evenIfInput];
ENDLOOP;
ENDCASE => ERROR;
};
ReallyPerturb: PROC [node: Node, str: Structure, sim: Simulation, agitator: Slot, evenIfInput: BOOLFALSE] =
BEGIN
IF node.type.simple THEN ERROR;
IF NOT node.significances[inImpl] THEN ERROR;
IF node.isInput AND NOT evenIfInput THEN RETURN;
IF node.nextPerturbed = notInNodeList THEN {
IF str.firstPerturbed = notInNodeList THEN ERROR;
node.nextPerturbed ← str.firstPerturbed;
str.firstPerturbed ← node;
reportSlot^ ← agitator;
NoteNews[news: $Perturbed, node: node, arg: reportSlot];
};
END;
ReallyFindVicinity: PROC [str: Structure, n: Node, evenIfInput: BOOL, from: Slot] =
BEGIN
IF NOT n.significances[inImpl] THEN ERROR;
IF n.found THEN RETURN;
IF n.isInput AND NOT evenIfInput THEN RETURN;
n.found ← TRUE;
IF str.firstAffected = notInNodeList THEN ERROR;
n.nextAffected ← str.firstAffected;
str.firstAffected ← n;
reportSlot^ ← from;
NoteNews[$Found, n, reportSlot];
FOR sl: SlotList ← n.switchConnections, sl.rest WHILE sl # NIL DO
s: Slot ← sl.first;
rcs: RealCellStuff ← s.cell.realCellStuff;
RecursivelyFindVicinity: PROC [portIndex: PortIndex] = {
FOR epi: EffectivePortIndex ← rcs.effectivePorts[portIndex].firstEffectivePortIndex, epi+1 WHILE epi < rcs.effectivePorts.length AND rcs.effectivePorts[epi].containingPort = portIndex DO
ReallyFindVicinity[str, rcs.implNodes[epi], evenIfInput, [s.cell, epi]];
ENDLOOP;
};
IF rcs.evals.EnumerateVicinity # NIL THEN rcs.evals.EnumerateVicinity[
cell: s.cell,
portIndex: rcs.effectivePorts[s.effectivePortIndex].containingPort,
evenIfInput: evenIfInput,
consume: RecursivelyFindVicinity
];
rcs.affectedFlags[Specialty[s]] ← TRUE;
ENDLOOP;
END;
Specialty: PROC [st: Slot] RETURNS [sy: Speciality] = {
ep: EffectivePort ← st.cell.realCellStuff.effectivePorts[st.effectivePortIndex];
IF ep.implType.simple THEN ERROR;
sy ← IF TransduceNeeded[ep.type, ep.implType] THEN transducedToSwitch ELSE modeledAsSwitch;
};
StrFindVicinity: PROC [str: Structure, evenIfInput: BOOL] =
BEGIN
this: Node;
WHILE str.firstPerturbed # NIL DO
IF str.firstPerturbed = notInNodeList THEN ERROR;
this ← str.firstPerturbed;
str.firstPerturbed ← this.nextPerturbed;
this.nextPerturbed ← notInNodeList;
ReallyFindVicinity[str, this, this.isInput, nilSlot];
ENDLOOP;
END;
Need1: PROC [str: Structure, n: Node, also: CellProc] =
BEGIN
FOR sl: SlotList ← n.switchConnections, sl.rest WHILE sl # NIL DO
IF sl.first.cell.realCellStuff.nextNeeded = notInCellList THEN
BEGIN
IF str.firstNeeded = notInCellList THEN ERROR;
sl.first.cell.realCellStuff.nextNeeded ← str.firstNeeded;
str.firstNeeded ← sl.first.cell;
IF also # NIL THEN also[sl.first.cell];
END;
ENDLOOP;
END;
Need2: PROC [str: Structure, n: Node, except: Cell] =
BEGIN
FOR sl: SlotList ← n.switchConnections, sl.rest WHILE sl # NIL DO
IF sl.first.cell.realCellStuff.nextNeeded = notInCellList AND sl.first.cell # except THEN
BEGIN
IF str.firstNeeded = notInCellList THEN ERROR;
sl.first.cell.realCellStuff.nextNeeded ← str.firstNeeded;
str.firstNeeded ← sl.first.cell;
END;
ENDLOOP;
END;
InitQ: CellProc--PROC [cell: Cell]-- = {
IF NOT cell.realCellStuff.initQed THEN {
cell.realCellStuff.initQed ← TRUE;
IF cell.realCellStuff.evals.InitQ # NIL THEN cell.realCellStuff.evals.InitQ[cell]}};
StrInitQ: PROC [str: Structure] =
BEGIN
FOR n: Node ← str.firstAffected, n.nextAffected WHILE n # NIL DO
IF n = notInNodeList THEN ERROR;
IF n.type.procs.InitQ # NIL THEN n.type.procs.InitQ[n];
NoteNews[news: $NewNodeQ, node: n, arg: NIL];
Need1[str, n, InitQ];
ENDLOOP;
END;
StrPropQWork: PROC [str: Structure] =
BEGIN
WHILE str.firstNeeded # NIL DO
needed: Cell ← str.firstNeeded;
IF needed = notInCellList THEN ERROR;
str.firstNeeded ← needed.realCellStuff.nextNeeded;
needed.realCellStuff.nextNeeded ← notInCellList;
needed.realCellStuff.initQed ← FALSE;
IF (needed.realCellStuff.evals.PropQ = NIL) AND (NOT needed.realCellStuff.hasTransducedPort) THEN LOOP;
IF needed.realCellStuff.evals.PropQ # NIL THEN {
FOR epi: EffectivePortIndex IN [0 .. needed.realCellStuff.effectivePorts.length) DO
ep: EffectivePort ← needed.realCellStuff.effectivePorts[epi];
IF (NOT ep.implType.simple) AND (NOT TransduceNeeded[ep.type, ep.implType]) THEN ep.implType.procs.QFromNode[ needed.realCellStuff.implNodes[epi], SlotToPtr[[needed, epi], TRUE]];
ENDLOOP;
needed.realCellStuff.evals.PropQ[needed];
};
FOR epi: EffectivePortIndex IN [0 .. needed.realCellStuff.effectivePorts.length) DO
n: Node ← needed.realCellStuff.implNodes[epi];
IF n.type.simple THEN LOOP;
IF n.type.procs.NewQ = NIL THEN ERROR;
IF n.nextAffected = notInNodeList THEN ERROR;
IF n.type.procs.NewQ[n, SlotToPtr[[needed, epi], TRUE]] THEN {
reportSlot^ ← [needed, epi];
NoteNews[news: $NewNodeQ, node: n, arg: reportSlot];
Need2[str, n, needed];
};
ENDLOOP;
ENDLOOP;
END;
InitUD: CellProc--PROC [cell: Cell]-- = {
IF NOT cell.realCellStuff.initUDed THEN {
cell.realCellStuff.initUDed ← TRUE;
IF cell.realCellStuff.evals.InitUD # NIL THEN cell.realCellStuff.evals.InitUD[cell]}};
StrInitUD: PROC [str: Structure] =
BEGIN
FOR n: Node ← str.firstAffected, n.nextAffected WHILE n # NIL DO
IF n = notInNodeList THEN ERROR;
IF n.type.procs.InitUD # NIL THEN n.type.procs.InitUD[n];
NoteNews[news: $NewNodeUD, node: n, arg: NIL];
Need1[str, n, InitUD];
ENDLOOP;
END;
StrPropUDWork: PROC [str: Structure] =
BEGIN
WHILE str.firstNeeded # NIL DO
needed: Cell ← str.firstNeeded;
IF needed = notInCellList THEN ERROR;
str.firstNeeded ← needed.realCellStuff.nextNeeded;
needed.realCellStuff.nextNeeded ← notInCellList;
needed.realCellStuff.initUDed ← FALSE;
IF (needed.realCellStuff.evals.PropUD = NIL) AND (NOT needed.realCellStuff.hasTransducedPort) THEN LOOP;
IF needed.realCellStuff.evals.PropUD # NIL THEN {
FOR epi: EffectivePortIndex IN [0 .. needed.realCellStuff.effectivePorts.length) DO
ep: EffectivePort ← needed.realCellStuff.effectivePorts[epi];
IF (NOT ep.implType.simple) AND (NOT TransduceNeeded[ep.type, ep.implType]) THEN ep.implType.procs.UDFromNode[ needed.realCellStuff.implNodes[epi], SlotToPtr[[needed, epi], TRUE]];
ENDLOOP;
needed.realCellStuff.evals.PropUD[needed];
};
FOR epi: EffectivePortIndex IN [0 .. needed.realCellStuff.effectivePorts.length) DO
n: Node ← needed.realCellStuff.implNodes[epi];
IF n.type.simple THEN LOOP;
IF n.type.procs.NewUD = NIL THEN ERROR;
IF n.nextAffected = notInNodeList THEN ERROR;
IF n.type.procs.NewUD[n, SlotToPtr[[needed, epi], TRUE]] THEN {
reportSlot^ ← [needed, epi];
NoteNews[news: $NewNodeUD, node: n, arg: reportSlot];
Need2[str, n, needed];
};
ENDLOOP;
ENDLOOP;
END;
NoteNews: PROC [news: ATOM, node: Node, arg: REF ANY] = {
RoseEvents.Notify[event: news, watched: node, handleAborted: TRUE, arg: arg];
FOR pl: PieceList ← node.parentPieces, pl.rest WHILE pl # NIL DO
NoteNews[news, pl.first.twardDesign, arg];
ENDLOOP;
};
StrFinalUD: PROC [str: Structure] =
BEGIN
firstNoted, next: Cell ← NIL;
bbTableSpace: PrincOps.BBTableSpace;
bbTable: PrincOps.BitBltTablePtr;
TRUSTED {bbTable ← PrincOpsUtils.AlignedBBTable[@bbTableSpace]};
FOR n: Node ← str.firstAffected, n.nextAffected WHILE n # NIL DO
delay: BOOLFALSE;
IF n = notInNodeList THEN ERROR;
n.found ← FALSE;
IF n.type.procs.NewVal # NIL THEN delay ← n.type.procs.NewVal[n];
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.realCellStuff.nextNoted = notInCellList THEN
{sl.first.cell.realCellStuff.nextNoted ← firstNoted; firstNoted ← sl.first.cell};
ENDLOOP;
ENDLOOP;
str.firstAffected ← NIL;
FOR firstNoted ← firstNoted, next WHILE firstNoted # NIL DO
IF firstNoted = notInCellList THEN ERROR;
next ← firstNoted.realCellStuff.nextNoted;
firstNoted.realCellStuff.nextNoted ← notInCellList;
IF firstNoted.realCellStuff.evals.FinalUD # NIL THEN firstNoted.realCellStuff.evals.FinalUD[firstNoted];
IF firstNoted.realCellStuff.affectedFlags[transducedToSwitch] THEN ScheduleCell[firstNoted];
ValsChanged[firstNoted, str];
firstNoted.realCellStuff.affectedFlags ← ALL[FALSE];
ENDLOOP;
END;
Delayed: PUBLIC PROC [n: Node] RETURNS [delayed: BOOL] =
{delayed ← n.nextDelayed # notInNodeList};
SetDelayedness: PROC [n: Node, delay: BOOL] = {
str: Structure;
IF delay = (n.nextDelayed # notInNodeList) THEN RETURN;
str ← n.strIn;
IF delay THEN {
IF str.firstDelayed = notInNodeList THEN ERROR;
n.nextDelayed ← str.firstDelayed;
n.prevDelayed ← NIL;
IF n.nextDelayed = NIL THEN str.lastDelayed ← n ELSE n.nextDelayed.prevDelayed ← n;
str.firstDelayed ← n;
}
ELSE {
IF n.nextDelayed = NIL THEN str.lastDelayed ← n.prevDelayed ELSE n.nextDelayed.prevDelayed ← n.prevDelayed;
IF n.prevDelayed = NIL THEN str.firstDelayed ← n.nextDelayed ELSE n.prevDelayed.nextDelayed ← n.nextDelayed;
n.nextDelayed ← n.prevDelayed ← notInNodeList;
};
};
CheckDelays: PROC [sim: Simulation] = {
str: Structure ← sim.str;
names: RopeList ← NIL;
FOR n: Node ← str.firstDelayed, n.nextDelayed WHILE n # NIL DO
IF n = notInNodeList THEN ERROR;
names ← CONS[RoseCreate.LongNodeName[n, sim.root], names];
PerturbNode[n, nilSlot];
ENDLOOP;
IF names # NIL THEN SIGNAL Warning["Nodes want Xes", names];
};
DistributeSwitch: PROC [node: Node, bbTable: PrincOps.BitBltTablePtr, perturb: BOOL] = {
IF node.type.simple OR NOT node.significances[inImpl] THEN ERROR;
IF perturb THEN PerturbNode[node, nilSlot, TRUE];
FOR sl: SlotList ← node.switchConnections, sl.rest WHILE sl # NIL DO
cell: Cell ← sl.first.cell;
epi: EffectivePortIndex ← sl.first.effectivePortIndex;
ep: EffectivePort ← cell.realCellStuff.effectivePorts[epi];
implPtr: Ptr ← SlotToPtr[[cell, epi], TRUE];
IF NOT ep.implType.simple THEN ep.implType.procs.ValFromNode[cell.realCellStuff.implNodes[epi], implPtr];
IF TransduceNeeded[ep.type, ep.implType] THEN {
modelPtr: Ptr ← SlotToPtr[[cell, epi], FALSE];
ep.type.procs.Transduce[fromS: FIRST[Strength], fromT: ep.implType, toT: ep.type, fromP: implPtr, toP: modelPtr];
};
ENDLOOP;
RoseEvents.Notify[event: $ChangeEarly, watched: node, handleAborted: TRUE];
FOR pl: PieceList ← node.parentPieces, pl.rest WHILE pl # NIL DO
pn: Node ← pl.first.twardDesign;
Copy[node.valPtr, SubPtr[pn.type, pn.valPtr, pl.first.reln], node.bitCount, bbTable];
IF perturb THEN PerturbNode[pn, nilSlot, TRUE];
RoseEvents.Notify[event: $ChangeEarly, watched: pn, handleAborted: TRUE];
RoseEvents.Notify[event: $ChangeLate, watched: pn, handleAborted: TRUE];
ENDLOOP;
RoseEvents.Notify[event: $ChangeLate, watched: node, handleAborted: TRUE];
};
ValsChanged: PROC [cell: Cell, str: Structure] =
BEGIN
IF cell.realCellStuff.evals.ValsChanged # NIL THEN {
PerturbPort: PROC [portIndex: PortIndex] = {
FOR epi: EffectivePortIndex ← cell.realCellStuff.effectivePorts[portIndex].firstEffectivePortIndex, epi+1 WHILE epi < cell.realCellStuff.effectivePorts.length AND cell.realCellStuff.effectivePorts[epi].containingPort = portIndex DO
ReallyPerturb[cell.realCellStuff.implNodes[epi], str, cell.sim, [cell, epi], FALSE];
ENDLOOP;
};
PreSimple[cell];
cell.realCellStuff.evals.ValsChanged[
cell: cell,
perturb: PerturbPort
!UNWIND => ReallyCleanUpAfterModify[cell: cell, str: str, outputsOnly: TRUE, blindly: FALSE, mayRescheduleSelf: TRUE]];
ReallyCleanUpAfterModify[cell: cell, str: str, outputsOnly: TRUE, blindly: FALSE, mayRescheduleSelf: TRUE];
};
END;
ValueChanged: PUBLIC PROC [node: Node] =
BEGIN
bbTableSpace: PrincOps.BBTableSpace;
bbTable: PrincOps.BitBltTablePtr;
TRUSTED {bbTable ← PrincOpsUtils.AlignedBBTable[@bbTableSpace]};
SELECT node.significances[inImpl] FROM
TRUE => SELECT node.type.simple FROM
FALSE => {
DistributeSwitch[node, bbTable, TRUE];
};
TRUE => {
Distribute[
base: node.valPtr,
fromNode: node,
str: node.strIn,
bitCount: node.bitCount,
bbTable: bbTable,
agitator: nilSlot];
};
ENDCASE => ERROR;
FALSE => {
FOR pl: PieceList ← node.childPieces, pl.rest WHILE pl # NIL DO
cn: Node ← pl.first.twardImpl;
IF cn.type.simple # node.type.simple THEN ERROR;
Copy[SubPtr[node.type, node.valPtr, pl.first.reln], cn.valPtr, cn.bitCount, bbTable];
ValueChanged[cn];
ENDLOOP;
};
ENDCASE => ERROR;
END;
AllowToModify: PUBLIC PROC [cell: Cell, modifier: CellProc, blindly, mayRescheduleSelf: BOOLEANFALSE] =
BEGIN
str: Structure ← ContainingStr[cell];
PreSimple[cell, NOT blindly];
modifier[cell !UNWIND =>
BEGIN
ReallyCleanUpAfterModify[cell, str, FALSE, blindly, mayRescheduleSelf];
END];
ReallyCleanUpAfterModify[cell, str, FALSE, blindly, mayRescheduleSelf];
END;
Start: PROC = {
notInCellList.name ← "notInCellList";
notInNodeList.name ← "notInNodeList";
};
Start[];
END.