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. 6RoseRunImpl.mesa Copyright c 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 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. IF outputsOnly AND NOT ep.output THEN LOOP; FOR pl: PieceList _ node.parentPieces, pl.rest WHILE pl # NIL DO NoteNews[news, pl.first.twardDesign, arg]; ENDLOOP; IF NOT Conforming[nt1, nt2] THEN ERROR --you shouldn't even be asking--; Κ/– "cedar" style˜– "Cedar" stylešœ™Jšœ Οmœ1™Kšœ˜Kšœ$˜$Kšœ!˜!š‘œžœ˜K˜ šžœž˜Kšœ žœ˜˜Kšžœžœžœ˜!šžœžœžœž˜'K˜Kšžœ˜—K˜K˜—˜ K˜Kš žœ žœžœžœžœ˜(šœ˜K˜Kšœ ˜ Kšœ˜—K˜5šžœ žœ žœ ž˜.K˜šžœ"ž˜)Kšœ1˜1Kšžœ˜—K˜Kšžœ˜—KšœU˜UK˜—Kšžœžœ˜—K˜—š‘ œžœ˜K˜ šžœž˜Kšœ žœ˜˜Kšžœžœžœ˜!šžœžœžœž˜'Kšœ˜Kšžœ˜—K˜K˜—˜ K˜šžœž˜&Kšœ(˜(Kšœ3˜3Kšœ žœ˜Kšžœžœ˜—K˜—Kšžœžœ˜—K˜—Kšžœ9˜@Kšžœžœžœžœ˜%Kšžœ žœžœ˜Kšœ3žœ˜7KšœNžœ˜RKšœ*˜*K˜ šžœ@žœžœž˜UKšœ˜K˜(Kšœ?˜?Kšœžœžœ˜Kšœ:žœ˜@K˜šžœžœ"ž˜BK˜'Kšœ1˜1Kšœ:˜:Kšœ7˜7šœžœž˜6Kšœ,˜,Kšœ)˜)Kšœ žœ˜Kšžœžœ˜—šžœž˜(Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšžœžœ˜—šžœž˜'Kšœ žœ,žœžœ˜CKšœ žœ˜Kšœ žœ˜Kšžœžœ˜—Kšœ-˜-šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜—šžœ$žœ˜,Kšœ2˜2Kšžœžœžœ˜!˜Kšœžœ ˜K˜Kšœ˜Kšœ˜K˜—šœ ˜ Kšœ ˜ Kšœ˜Kšœ˜K˜Kšœ˜—K˜—Kšžœ˜—K˜ Kšžœ˜—Kšœ+˜+K˜ K˜—K˜š‘œžœžœžœ˜EKšž˜šžœž˜ Kšœ žœ˜K˜!Kšœ ˜ Kšžœžœ˜—šžœžœžœ˜2Kšœ1˜1K˜K˜—Kšžœ˜—K˜š‘œžœžœžœ˜BKšž˜K˜Kšžœžœžœžœ ˜0Kšžœžœžœžœ˜5K˜Kšžœ˜—K˜š‘ œžœ˜'K˜Kšœžœ˜šžœ1žœžœž˜EKšžœžœžœ˜!Kšœžœ ˜Kšœ˜Kšžœ˜—Kšžœ žœžœžœ"˜˜KK˜—šžœ žœžœ˜!Kšœ˜Kšœq˜qK˜—š žœ žœ!žœžœ!žœ"žœ˜KšœH˜HK˜—K˜—šžœ˜Kšœ žœžœ˜KšœP˜PKšœ žœA˜Nšžœžœ˜Kšœ;˜;šžœ)žœ!žœ˜TKšœ+˜+Kšœ žœ˜—K˜—Kšžœ!žœžœ˜.šžœ!žœžœ žœ˜9šžœ žœ˜Kšœ;˜;šœ˜Kšžœžœž˜3Kšžœžœž˜3Kšœ˜—Kšœžœžœ˜BšžœžœΟcœ˜$˜ K˜Kšœ ˜ Kšœ ˜ Kš œ žœžœžœžœžœ˜6Kšœ ˜ Kšœ˜Kšœ˜—K˜—Kšžœžœ˜%K˜—K˜—šžœ!žœ˜)Kšœi˜iK˜—K˜—Kšœ˜Kšžœ˜—Kšœ˜Kšžœ˜—K˜•StartOfExpansion[]š‘œžœ6˜JK˜Kšœ/˜/šžœ*žœ žœ˜>KšœA˜Ašžœ8žœ˜@Kšžœ žœžœ˜Kšœd˜dKšœ˜—KšžœM˜Qšžœ8žœ˜@Kšžœ žœžœ˜Kšœd˜dKšœ˜—KšžœN˜RK˜—KšœM˜MKšœ1˜1šžœ.˜0Kšžœ@˜DKšžœ(˜,—Kšœ(˜(Kšœ7˜7K˜—K˜š‘œžœ$žœ žœ˜QKšœ.˜.—K˜š‘ œžœJ˜]K˜Kšœžœ˜šžœž˜&Kšœ žœ˜Kšœžœ˜Kšžœžœ˜—šžœ ž œžœ ž˜)Kš žœžœžœžœžœ˜]Kšžœ˜—Kšžœ%žœžœ˜3Kšžœ%žœžœ˜2šžœlžœ ž˜€KšœB˜BKšœG˜Gšžœž˜Kšœ(˜(˜ Kšžœžœ6žœžœ˜aK˜—Kšžœžœ˜—Kšžœ˜—Kšžœžœžœ˜šœ ˜ K˜K˜ Kšœ ˜ Kšœ!˜!Kšœ˜K˜K˜K˜—K˜—K˜š‘ œž˜šœ˜K˜Kšœ ˜ Kšœ˜Kšœžœ˜"Kšœ˜Kšœ˜Kšœ!˜!Kšœ˜—Kšž˜šžœ"ž˜,Kšœ žœ˜Kšœžœ˜Kšžœžœ˜—Kšžœžœu˜“šžœ žœ ž˜šžœkžœ ž˜‚KšœG˜GKšœm˜mKšžœžœ˜7Kšžœ˜—Kšžœ˜—K˜KšœK˜KKšœJ˜JKšžœ˜—K˜š‘ œžœ˜'Kšž˜K˜Kšœ$˜$Kšœ!˜!Kšžœ9˜@Kšœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœ˜—K˜š‘œžœ žœ˜