<> <> <> <> DIRECTORY BitTwiddling, IO, PrincOps, PrincOpsUtils, RoseCreate, RoseEvents, RoseRun, RoseTypes; RoseRunImpl: CEDAR PROGRAM IMPORTS BitTwiddling, IO, PrincOpsUtils, RoseCreate, RoseEvents, RoseTypes EXPORTS RoseRun, RoseTypes = <> <> <> <> <> <> <> BEGIN OPEN BitTwiddling, RoseTypes; stop: PUBLIC BOOLEAN _ FALSE; 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: BOOL _ TRUE] = 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: BOOLEAN _ FALSE; 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]]]; <> 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 { ep: EffectivePort _ cell.realCellStuff.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 > 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[IO.PutFR[ "Inconsistency (between %g and %g)", [rope[RoseCreate.LongPortName[c: cell, epi: effectivePortIndex]]], [rope[IF another # nilSlot THEN RoseCreate.LongPortName[c: another.cell, epi: another.effectivePortIndex] ELSE RoseCreate.LongNodeName[node] ]] ]]; }; }; 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: BOOL _ FALSE] = { 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: BOOL _ FALSE] = 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: BOOL _ FALSE; 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: BOOLEAN _ FALSE] = 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.