<> <> <> <> 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 = <> <> <> <> <> <> <> <> <> 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"]; <> 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]; <> <> <> }; 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] = { <> 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: PROC = { }; Start[]; END.