DIRECTORY Atom, BasicTime, Buttons, ChoiceButtons, Containers, Convert, Core, CoreClasses, CoreFlat, CoreOps, CoreProperties, IO, PlotGraph, Ports, Process, ProcessProps, ReadEvalPrint, RefTab, Rope, Rosemary, RosemaryUser, Rules, SymTab, TypeScript, ViewerClasses, ViewerEvents, ViewerIO, ViewerOps, ViewerTools; RosemaryUserViewerImpl: CEDAR MONITOR IMPORTS BasicTime, Buttons, ChoiceButtons, Containers, Convert, CoreClasses, CoreFlat, CoreOps, CoreProperties, IO, PlotGraph, Ports, Process, ProcessProps, ReadEvalPrint, RefTab, Rope, Rosemary, RosemaryUser, Rules, SymTab, TypeScript, ViewerEvents, ViewerIO, ViewerOps, ViewerTools EXPORTS RosemaryUser ~ BEGIN OPEN RosemaryUser; entryHeight: NAT = 15; -- how tall to make each line of items entryVSpace: NAT = 4; -- vertical leading space between lines entryHSpace: NAT = 4; -- horizontal leading space between buttons pointsPerInch: NAT = 72; -- horizontal space for text ropes borderOffset: NAT = 2; rosemaryHandle: ATOM _ $RosemaryUserRoseDisplay; -- CellType property holding RoseDisplay DisplayViewer: PUBLIC PROC [simulation: Rosemary.Simulation, cellType: Core.CellType, name: ROPE _ NIL, displayWires: CoreFlat.FlatWires _ NIL, graphWires: CoreFlat.FlatWires _ NIL] RETURNS [handle: RoseDisplay] = { viewer: ViewerClasses.Viewer_ Containers.Create[[ name: name, iconic: TRUE, column: left, scrollable: FALSE ]]; handle _ NEW[RoseDisplayRec]; handle.simulation _ simulation; handle.cellType _ cellType; MakeDisplayAndBrowse[displayWires: displayWires, graphWires: graphWires, height: entryVSpace, handle: handle, viewer: viewer, name: name]; }; MakeDisplayAndBrowse: PROC [displayWires: CoreFlat.FlatWires, graphWires: CoreFlat.FlatWires, height: CARDINAL, handle: RoseDisplay, viewer: ViewerClasses.Viewer, name: ROPE] ~ { AddButton: PROC [name: ROPE, proc: Buttons.ButtonProc] ~ { button: ViewerClasses.Viewer _ Buttons.Create[ info: [name: name, wx: xPos, wy: height, parent: viewer, border: TRUE], proc: proc, clientData: handle]; xPos _ xPos+button.ww+entryHSpace; }; AddPrompt: PROC [title: ROPE] RETURNS [v: ViewerClasses.Viewer]~ { v _ ChoiceButtons.BuildTextPrompt[ viewer: viewer, x: entryHSpace, y: height, title: title, textViewerWidth: 4*pointsPerInch].textViewer; height _ height + entryHeight + entryVSpace; xPos _ entryHSpace; -- force beginning of new line }; AddChoice: PROC [title: ROPE, proc: ChoiceButtons.SelectionNotifierProc, list: ChoiceButtons.ButtonList] ~ { button: ChoiceButtons.EnumTypeRef _ ChoiceButtons.BuildEnumTypeSelection[ viewer: viewer, x: xPos, y: height, title: title, buttonNames: list, default: list.first, borderOnButtons: TRUE, notifyClientProc: proc, clientdata: handle, style: flipThru]; xPos _ button.nextx; }; xPos: INT _ entryHSpace; -- current x position in viewer to put buttons correctly handle.wDir _ ProcessProps.GetProp[$WorkingDirectory]; { rep: ReadEvalPrint.Handle; title: ROPE = Rope.Cat[name, " Rosemary Script"]; [handle.tsin, handle.tsout] _ ViewerIO.CreateViewerStreams[name: title, viewer: TypeScript.Create[info: [name: title, iconic: TRUE, column: left]]]; rep _ ReadEvalPrint.CreateStreamEvaluator[clientProc: ExploreDesign, prompt: "%l> %l", in: handle.tsin, out: handle.tsout, topLevel: TRUE]; rep.clientData _ handle; ReadEvalPrint.MainLoop[h: rep, properties: NIL]; }; AddButton["Trace", TraceChanges]; AddChoice["Record:", RecordChoice, LIST["Evals", "MosSim steps", "Nothing"]]; AddChoice[" Plot:", PlotChoice, LIST["Evals", "MosSim steps (waves only)", "MosSim steps (all graphs)"]]; height _ height + entryHeight + entryVSpace; xPos _ entryHSpace; -- new line ViewerOps.SetOpenHeight[viewer, height]; -- this is where the viewer will open by default IF displayWires#NIL THEN AddButton["Update", UpdateDisplayButton]; height _ height + entryHeight + entryVSpace; xPos _ entryHSpace; -- new line handle.path _ AddPrompt["Instantiation Path:"]; handle.currentWire _ AddPrompt["Current Wire:"]; IF displayWires#NIL THEN { Column: TYPE = NAT [0..2); columnWidth: NAT = 3*pointsPerInch+pointsPerInch/4; column: Column _ 0; xPos: NAT _ entryHSpace; -- current x position in viewer count: INT _ 0; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; FOR dws: CoreFlat.FlatWires _ displayWires, dws.rest UNTIL dws=NIL DO count _ count + 1; ENDLOOP; IF count>100 THEN IO.PutF[handle.tsout, "You really don't want to display %g wires, maybe you should try again", IO.int[count]] ELSE FOR dws: CoreFlat.FlatWires _ displayWires, dws.rest UNTIL dws=NIL DO dn: ROPE _ CoreFlat.WirePathRope[handle.cellType, dws.first^]; prompt: ChoiceButtons.PromptDataRef; IF Rope.Equal[Rope.Substr[dn, 0, 7], "public."] THEN dn _ Rope.Substr[dn, 7]; prompt _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: xPos, y: height-borderOffset, title: dn, textViewerWidth: 2*pointsPerInch, clientdata: dws.first]; prompt.textViewer.ww _ (xPos+columnWidth)-(prompt.textViewer.wx+entryHSpace); ViewerTools.InhibitUserEdits[prompt.textViewer]; handle.displayWires _ CONS[prompt, handle.displayWires]; IF column=LAST[Column] THEN { column _ 0; height _ height + entryHeight + entryVSpace; xPos _ entryHSpace; } ELSE { column _ column+1; xPos _ xPos+columnWidth; }; ENDLOOP; IF column>0 THEN height _ height + entryHeight + entryVSpace; }; ViewerOps.OpenIcon[viewer]; handle.name _ name; FOR wires: CoreFlat.FlatWires _ graphWires, wires.rest UNTIL wires=NIL DO IF AddWireToPlot[handle, wires.first]#NIL THEN ERROR; ENDLOOP; }; RecordChoice: ChoiceButtons.SelectionNotifierProc = { h: RoseDisplay _ NARROW[clientdata]; SELECT TRUE FROM Rope.Equal[name, "Evals"] => {h.recordDeltas _ TRUE; h.recordSteps _ FALSE}; Rope.Equal[name, "MosSim steps"] => {h.recordDeltas _ TRUE; h.recordSteps _ TRUE}; Rope.Equal[name, "Nothing"] => {h.recordDeltas _ FALSE; h.recordSteps _ FALSE}; ENDCASE => ERROR; -- something is wrong in the code... }; PlotChoice: ChoiceButtons.SelectionNotifierProc = { h: RoseDisplay _ NARROW[clientdata]; SELECT TRUE FROM Rope.Equal[name, "Evals"] => h.plotStyle _ noSteps; Rope.Equal[name, "MosSim steps (waves only)"] => h.plotStyle _ waveSteps; Rope.Equal[name, "MosSim steps (all graphs)"] => h.plotStyle _ allSteps; ENDCASE => ERROR; -- something is wrong in the code... IF h.plot#NIL AND h.plot.data#NIL THEN PlotGraph.RefreshPlot[plot: h.plot, eraseFirst: TRUE]; }; TraceChanges: Buttons.ButtonProc = { h: RoseDisplay _ NARROW[clientData]; IF (h.traceChanges _ ~h.traceChanges) THEN { Buttons.SetDisplayStyle[NARROW[parent], $WhiteOnBlack]; } ELSE Buttons.SetDisplayStyle[NARROW[parent], $BlackOnWhite]; }; UpdateDisplayButton: Buttons.ButtonProc = { handle: RoseDisplay _ NARROW[clientData]; UpdateDisplay[handle]; }; LogSettle: PUBLIC PROC [handle: RoseDisplay, time: INT, memory: BOOL _ TRUE] = { UpdateWire: Rosemary.UpdateProc = { RecordDelta[handle, roseWire, time]; }; UpdateCell: Rosemary.UpdateCellProc = { RecordStateSample[handle, roseInstance, stateValue, time]; }; wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; Rosemary.Settle[simulation: handle.simulation, updateProc: UpdateWire, memory: memory, updateCellProc: UpdateCell]; DeltaFinished[handle, time]; IF handle.traceChanges THEN IO.PutRope[handle.tsout, "\n\n"]; }; UpdateDisplay: PUBLIC PROC [handle: RoseDisplay] = { FOR dwvs: LIST OF ChoiceButtons.PromptDataRef _ handle.displayWires, dwvs.rest UNTIL dwvs=NIL DO dw: CoreFlat.FlatWire _ NARROW[dwvs.first.clientdata]; new: ROPE; value: Ports.LevelSequence _ Rosemary.WireValue[handle.simulation, dw]; new _ Ports.LevelSequenceToRope[value]; IF Rope.Length[new] > 16 THEN new _ "Typescript"; IF NOT Rope.Equal[new, ViewerTools.GetContents[dwvs.first.textViewer]] THEN ViewerTools.SetContents[dwvs.first.textViewer, new]; ENDLOOP; }; RoseDisplayFor: PUBLIC PROC [cellType: Core.CellType] RETURNS [RoseDisplay] ~ { RETURN [NARROW [CoreProperties.GetCellTypeProp[cellType, rosemaryHandle]]]; }; testProcTable: SymTab.Ref _ SymTab.Create[]; RegisterTestProc: PUBLIC PROC [name: ROPE, proc: TestProc] = { [] _ SymTab.Store[x: testProcTable, key: name, val: NEW[TestProc _ proc]]; }; StartTest: PUBLIC PROC [tester: Tester] = { GrumbleStartTest: PROC = { IF NOT AlreadyStarted[tester] THEN DoStartTest[tester]; }; ProcessProps.AddPropList[LIST[NEW[Atom.DottedPairNode _ [key: $WorkingDirectory, val: tester.display.wDir]]], GrumbleStartTest] }; DoStartTest: PROC [h: Tester] = { Eval: PROC [memory: BOOL _ TRUE, clockEval: BOOL _ FALSE, checkPorts: BOOL _ TRUE] ~ { UpdateCell: Rosemary.UpdateCellProc = { IF h.abort THEN SIGNAL AbortSignal; RecordStateSample[h.display, roseInstance, stateValue, h.evalSinceStartCount+1]; }; UpdateWire: Rosemary.UpdateProc = { IF h.abort THEN SIGNAL AbortSignal; RecordDelta[h.display, roseWire, h.evalSinceStartCount+1]; }; DO inBuf: BOOL _ h.displayedStatePoint#h.currentStatePoint AND h.validStates>0; testPort: Ports.Port _ IF inBuf THEN h.testVectorBuffer[NextBuf[h, h.displayedStatePoint]] ELSE currentTestPort; Ports.CopyPortValue[from: testPort, to: h.intermediatePort]; Rosemary.Settle[h.display.simulation, UpdateWire, memory, clockEval, UpdateCell]; IF h.display.traceChanges THEN IO.PutRope[h.display.tsout, "\n\n"]; UpdateESSC[h, h.evalSinceStartCount+1]; DeltaFinished[h.display, h.evalSinceStartCount]; IF h.evalSinceStartCount>=h.historyTriggerCount AND NOT inBuf AND h.historySize>0 THEN { h.currentStatePoint _ NextBuf[h, h.currentStatePoint]; h.displayedStatePoint _ h.currentStatePoint; IF h.validStates < h.historySize THEN h.validStates _ h.validStates + 1; Rosemary.StatePoint[h.display.simulation, h.currentStatePoint]; Ports.CopyPortValue[from: currentTestPort, to: h.testVectorBuffer[h.currentStatePoint]]; }; IF NOT clockEval AND checkPorts THEN Ports.CheckPortValue[root: h.display.cellType.public, truth: testPort, question: h.intermediatePort ! Ports.CheckError => UpdateDisplay[h.display]]; IF EvalsFinished[h] THEN SIGNAL AbortSignal; IF inBuf THEN { h.displayedStatePoint _ NextBuf[h, h.displayedStatePoint]; IF h.displayedStatePoint=h.currentStatePoint THEN EXIT; } ELSE EXIT; ENDLOOP; }; InitCell: Rosemary.UpdateCellProc = { IF h.abort THEN SIGNAL AbortSignal; IF h.display.recordDeltas AND stateValue#NIL THEN { -- data _ copy of stateValue copy: Ports.LevelSequence _ NEW [Ports.LevelSequenceRec[stateValue.size]]; Ports.CopyLS[from: stateValue, to: copy]; roseInstance.data _ copy; } ELSE roseInstance.data _ NIL; -- or NIL to note this cell doesn't log its state }; wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; testProc: TestProc _ NARROW[SymTab.Fetch[x: testProcTable, key: h.currentTestProc].val, REF TestProc]^; currentTestPort: Ports.Port _ Ports.CreatePort[h.display.cellType, TRUE]; time: BasicTime.GMT _ BasicTime.nullGMT; IF testProc=NIL THEN ERROR; UpdateESSC[h, 0]; h.validStates _ 0; SetEvalUntil[h: h, interrupt: FALSE, abort: FALSE]; ViewerTools.SetContents[h.runState, "Initializing"]; time _ BasicTime.Now[]; Rosemary.Initialize[h.display.simulation, h.steadyInit, InitCell ! UNWIND => FinishedTest[h]]; InitializeDeltas[h.display]; Rosemary.PrintPeriod["Rosemary initialized in", time, BasicTime.Now[]]; ViewerTools.SetContents[h.runState, "Running"]; time _ BasicTime.Now[]; testProc[h.display.simulation, h.display.cellType, currentTestPort, Eval ! Rosemary.Stop => IF reason = $BoolWireHasX THEN {IO.PutF[h.display.tsout, "\nWire %g settled to an X and has boolean ports", IO.rope[CoreFlat.WirePathRope[h.display.cellType, NARROW[data, CoreFlat.FlatWire]^]]]; RESUME}; AbortSignal => CONTINUE; UNWIND => FinishedTest[h]]; Rosemary.PrintPeriod["Rosemary ran in", time, BasicTime.Now[]]; FinishedTest[h]; }; AlreadyStarted: ENTRY PROC [h: Tester] RETURNS [started: BOOL] = { started _ h.testStarted OR h.singleEval; h.testStarted _ TRUE; BROADCAST h.proceed; }; FinishedTest: ENTRY PROC [h: Tester] = { UpdateDisplay[h.display]; ViewerTools.SetContents[h.runState, "Idle"]; h.testStarted _ FALSE; BROADCAST h.proceed; }; DoSingleEval: ENTRY PROC [h: Tester] = { h.singleEval _ TRUE; IF h.testStarted THEN { h.interrupt _ TRUE; UNTIL h.waiting OR NOT h.testStarted DO WAIT h.proceed ENDLOOP; IF h.testStarted THEN { count: INT _ h.evalSinceStartCount; until: INT _ h.evalUntil; h.evalUntil _ count+1; h.interrupt _ FALSE; BROADCAST h.proceed; UNTIL h.evalSinceStartCount > count OR h.abort OR NOT h.testStarted DO WAIT h.proceed; ENDLOOP; h.interrupt _ TRUE; h.evalUntil _ until; }; } ELSE TRUSTED { h.evalUntil _ 1; h.testStarted _ TRUE; Process.Detach[FORK DoStartTest[h]]; UNTIL h.waiting OR h.abort DO WAIT h.proceed ENDLOOP; }; h.singleEval _ FALSE; }; DoNextState: ENTRY PROC [h: Tester] = { IF h.waiting AND NOT h.singleEval THEN { IF h.displayedStatePoint=h.currentStatePoint THEN IO.PutRope[h.display.tsout, "No next state"] ELSE { h.displayedStatePoint _ NextBuf[h, h.displayedStatePoint]; Rosemary.RestoreState[h.display.simulation, h.displayedStatePoint]; UpdateESSC[h, h.evalSinceStartCount+1]; UpdateDisplay[h.display]; }; }; }; DoPreviousState: ENTRY PROC [h: Tester] = { IF h.waiting AND NOT h.singleEval THEN { ndsp: NAT _ IF h.displayedStatePoint=0 THEN h.historySize-1 ELSE h.displayedStatePoint-1; SELECT TRUE FROM ndsp>=h.validStates => IO.PutRope[h.display.tsout, "No previous state, not enough evals since history trigger"]; ndsp=h.currentStatePoint => IO.PutRope[h.display.tsout, "No previous state, buffer depth exceeded"]; ENDCASE => { h.displayedStatePoint _ ndsp; Rosemary.RestoreState[h.display.simulation, h.displayedStatePoint]; UpdateESSC[h, h.evalSinceStartCount-1]; UpdateDisplay[h.display]; }; }; }; SetEvalUntil: PROC [h: Tester, interrupt: BOOL, abort: BOOL] = { GetCount: PROC [v: ViewerClasses.Viewer] RETURNS [count: INT] = { IF v=NIL THEN count _ 0 ELSE { vRope: ROPE _ ViewerTools.GetContents[v]; count _ LAST[INT]; IF vRope#NIL THEN count _ Convert.IntFromRope[vRope ! Convert.Error => CONTINUE]; }; }; SetUntil[h, GetCount[h.proceedUntil], GetCount[h.historyTrigger], interrupt, abort]; }; SetUntil: ENTRY PROC [h: Tester, count: INT, trigger: INT, interrupt: BOOL, abort: BOOL] = { IF NOT h.singleEval THEN { h.evalUntil _ count; h.historyTriggerCount _ trigger; IF trigger>h.evalSinceStartCount THEN h.validStates _ 0; h.interrupt _ interrupt; }; h.abort _ abort; BROADCAST h.proceed; }; EvalsFinished: ENTRY PROC [h: Tester] RETURNS [abort: BOOL] = { resetRunState: BOOL _ FALSE; WHILE (h.evalUntil<=h.evalSinceStartCount OR h.interrupt) AND NOT h.abort DO UpdateDisplay[h.display]; ViewerTools.SetContents[h.runState, "Interrupted"]; resetRunState _ TRUE; BROADCAST h.proceed; h.waiting _ TRUE; WAIT h.proceed; h.waiting _ FALSE; ENDLOOP; IF resetRunState THEN ViewerTools.SetContents[h.runState, "Running"]; abort _ h.abort; }; NextBuf: PROC [h: Tester, buf: NAT] RETURNS [next: NAT] = { next _ (buf + 1) MOD h.historySize; }; AbortSignal: SIGNAL = CODE; testerProp: ATOM _ $RosemaryUserTester; TestProcedureViewer: PUBLIC PROC [cellType: Core.CellType, testButtons: LIST OF ROPE, name: ROPE _ NIL, displayWires: CoreFlat.FlatWires _ NIL, graphWires: CoreFlat.FlatWires _ NIL, cutSet: CoreFlat.CutSet _ NIL, historySize: NAT _ 0, steady: BOOL _ FALSE, recordDeltas: BOOL _ TRUE] RETURNS [tester: Tester] = { AddButton: PROC [name: ROPE, proc: Buttons.ButtonProc, guarded: BOOL _ FALSE] ~ { button: ViewerClasses.Viewer _ Buttons.Create[ info: [name: name, wx: xPos, wy: height, parent: viewer, border: TRUE], guarded: guarded, proc: proc, clientData: tester]; xPos _ xPos+button.ww+entryHSpace; }; AddPrompt: PROC [title: ROPE, width: CARDINAL] RETURNS [v: ViewerClasses.Viewer] ~ { v _ ChoiceButtons.BuildTextPrompt[ viewer: viewer, x: xPos, y: height, title: title, textViewerWidth: width].textViewer; xPos _ v.wx+v.ww+entryHSpace; }; viewer: ViewerClasses.Viewer; -- created after simulation has been expanded height: CARDINAL _ entryVSpace; xPos: CARDINAL _ entryHSpace; tester _ NEW[TesterRec]; tester.display _ NEW[RoseDisplayRec]; tester.steadyInit _ steady; tester.display.cutSet _ cutSet; tester.intermediatePort _ Ports.CreatePort[cellType, TRUE]; tester.display.cellType _ cellType; tester.display.recordDeltas _ recordDeltas; tester.display.simulation _ Rosemary.Instantiate[cellType, tester.intermediatePort, cutSet, historySize]; IF historySize>0 THEN { tester.historySize _ historySize; tester.testVectorBuffer _ NEW[Rosemary.PortSequenceRec[historySize]]; FOR b: NAT IN [0..historySize) DO tester.testVectorBuffer[b] _ Ports.CreatePort[cellType, TRUE]; ENDLOOP; }; viewer _ Containers.Create[[name: name, iconic: TRUE, column: right, scrollable: FALSE]]; CoreProperties.PutCellTypeProp[cellType, rosemaryHandle, tester.display]; -- for retrieval ViewerOps.AddProp[viewer, testerProp, tester]; -- for retrieval [] _ ViewerEvents.RegisterEventProc[proc: TesterDestroyed, event: destroy, filter: viewer, before: TRUE]; -- call proc just before tester viewer is destroyed AddButton["Start Test", ButtonStartTest]; tester.runState _ AddPrompt[" Run State:", 3*pointsPerInch/2]; ViewerTools.InhibitUserEdits[tester.runState]; ViewerTools.SetContents[tester.runState, "Idle"]; tester.evalsSinceStart _ AddPrompt["Evals Since Start:", 1*pointsPerInch]; ViewerTools.InhibitUserEdits[tester.evalsSinceStart]; height _ height + entryHeight + entryVSpace; xPos _ entryHSpace; -- new line AddButton["Abort", Abort, TRUE]; AddButton["Interrupt", Interrupt]; AddButton["Single Eval", SingleEval]; AddButton["Proceed", Proceed]; tester.proceedUntil _ AddPrompt["Until:", 1*pointsPerInch]; height _ height + entryHeight + entryVSpace; xPos _ entryHSpace; -- new line IF historySize>0 THEN { AddButton["Next State", NextState]; AddButton["Previous State", PreviousState]; tester.historyTrigger _ AddPrompt["History Trigger:", 2*pointsPerInch]; height _ height + entryHeight + entryVSpace; xPos _ entryHSpace; -- new line }; IF testButtons.rest#NIL THEN { -- more than 1 test proc, show them all for user choice Column: TYPE = NAT [0..3); ColumnStart: ARRAY Column OF NAT = [entryVSpace, 2*pointsPerInch+entryVSpace, 4*pointsPerInch+entryVSpace]; column: Column _ 0; first: Buttons.Button _ NIL; FOR tbs: LIST OF ROPE _ testButtons, tbs.rest UNTIL tbs=NIL DO this: Buttons.Button _ Buttons.Create[info: [name: tbs.first, wx: ColumnStart[column], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: tester, proc: TestButtonProc]; tester.testButtonList _ CONS[this, tester.testButtonList]; IF first=NIL THEN first _ this; IF column=LAST[Column] THEN { column _ 0; height _ height + entryHeight + entryVSpace; } ELSE column _ column+1; ENDLOOP; IF column>0 THEN height _ height + entryHeight + entryVSpace; Buttons.SetDisplayStyle[first, $WhiteOnBlack]; }; tester.currentTestProc _ testButtons.first; MakeDisplayAndBrowse[displayWires, graphWires, height, tester.display, viewer, name]; }; TestButtonProc: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; selectedButton: ViewerClasses.Viewer _ NARROW[parent]; FOR l: LIST OF Buttons.Button _ h.testButtonList, l.rest WHILE l#NIL DO Buttons.SetDisplayStyle[l.first, IF l.first = selectedButton THEN $WhiteOnBlack ELSE $BlackOnWhite]; ENDLOOP; h.currentTestProc _ selectedButton.name; }; ButtonStartTest: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; StartTest[h]; }; Interrupt: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; SetEvalUntil[h: h, interrupt: TRUE, abort: FALSE]; }; Proceed: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; SetEvalUntil[h: h, interrupt: FALSE, abort: FALSE]; }; Abort: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; SetEvalUntil[h: h, interrupt: FALSE, abort: TRUE]; }; SingleEval: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; DoSingleEval[h]; SetEvalUntil[h: h, interrupt: TRUE, abort: FALSE]; }; NextState: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; DoNextState[h]; }; PreviousState: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; DoPreviousState[h]; }; SetProceedUntil: PUBLIC PROC [tester: Tester, count: INT] = { ViewerTools.SetContents[tester.proceedUntil, Convert.RopeFromInt[from: count, showRadix: FALSE]]; }; UpdateESSC: PROC [h: Tester, new: INT] = { h.evalSinceStartCount _ new; ViewerTools.SetContents[h.evalsSinceStart, Convert.RopeFromCard[from: h.evalSinceStartCount, showRadix: FALSE]]; }; TesterDestroyed: ViewerEvents.EventProc ~ { ref: REF ANY _ ViewerOps.FetchProp[viewer, testerProp]; tester: Tester; IF event#destroy OR before#TRUE OR ref=NIL OR NOT ISTYPE[ref, Tester] THEN RETURN; -- someone is trying to play games with us tester _ NARROW[ref]; -- safe now TRUSTED { Process.Detach[FORK TesterCleanup[tester, viewer]] }; -- fork for safety }; TesterCleanup: PROC [tester: Tester, initial: ViewerClasses.Viewer] ~ { display: RoseDisplay _ tester.display; displayOnCellType: RoseDisplay _ NARROW[CoreProperties.GetCellTypeProp[display.cellType, rosemaryHandle]]; SetUntil[h: tester, count: LAST[INT], trigger: LAST[INT], interrupt: FALSE, abort: TRUE]; -- try to abort simulation, may fail. Should not refer to viewer here as it may be dead! IF displayOnCellType=display THEN CoreProperties.PutCellTypeProp[display.cellType, rosemaryHandle, NIL]; -- NIL circular ref IF display.plot#NIL AND display.plot.private#NIL THEN PlotGraph.DeletePlot[display.plot]; ViewerOps.DestroyViewer[ViewerIO.GetViewerFromStream[display.tsout]]; IF display.ps#NIL THEN {IO.SetLength[display.ps, 0]; IO.Close[display.ps]}; -- backing file }; DebugEvalProcSignal: SIGNAL [port: Ports.Port, state: REF ANY] = CODE; DebugEvalProc: PROC [port: Ports.Port, state: REF ANY] = { SIGNAL DebugEvalProcSignal[port, state]; }; ExploreDesign: ReadEvalPrint.ClientProc = { ENABLE CoreFlat.PathError => {result _ msg; GOTO Done}; Chop: PROC RETURNS [first, rest: ROPE _ NIL ] = { dStream: IO.STREAM = IO.RIS[command]; first _ dStream.GetTokenRope[IO.IDProc ! IO.EndOfStream => CONTINUE].token; rest _ command.Substr[dStream.GetIndex]; }; handle: RoseDisplay _ NARROW[h.clientData]; operation, rest, pathName, fullPathName, wireName: ROPE; [operation, rest] _ Chop[]; pathName _ ViewerTools.GetContents[handle.path]; fullPathName _ Rope.Cat[pathName, rest]; wireName _ Rope.Cat[pathName, ViewerTools.GetContents[handle.currentWire], rest]; SELECT TRUE FROM Rope.Equal[operation, "a"] => { wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; wireKey^ _ CoreFlat.ParseWirePath[handle.cellType, wireName, handle.cutSet]; result _ AddWireToPlot[handle, wireKey]; }; Rope.Equal[operation, "c"] => { resultStream: IO.STREAM _ IO.ROS[]; flatCell: CoreFlat.FlatCellTypeRec _ CoreFlat.ParseCellTypePath[handle.cellType, fullPathName, handle.cutSet]; cellType: Core.CellType _ CoreFlat.ResolveFlatCellType[handle.cellType, flatCell].cellType; CoreOps.PrintCellType[cellType, resultStream]; result _ IO.RopeFromROS[resultStream]; }; Rope.Equal[operation, "cn"] => { flatCell: CoreFlat.FlatCellTypeRec _ CoreFlat.ParseCellTypePath[handle.cellType, fullPathName, handle.cutSet]; cellType: Core.CellType _ CoreFlat.ResolveFlatCellType[handle.cellType, flatCell].cellType; result _ CoreOps.InheritCellTypeName[cellType]; }; Rope.Equal[operation, "cp"] => { resultStream: IO.STREAM _ IO.ROS[]; flatCell: CoreFlat.FlatCellTypeRec _ CoreFlat.ParseCellTypePath[handle.cellType, fullPathName, handle.cutSet]; cellType: Core.CellType _ CoreFlat.ResolveFlatCellType[handle.cellType, flatCell].cellType; CoreOps.PrintWire[cellType.public, resultStream]; result _ Rope.Cat[CoreOps.InheritCellTypeName[cellType], ": ", IO.RopeFromROS[resultStream]]; }; Rope.Equal[operation, "d"] => result _ DescribeWire[goryDetails: TRUE, handle: handle, wireName: wireName]; Rope.Equal[operation, "p"] => { PrintPort: PROC [public: Core.Wire] RETURNS [subWires: BOOL _ TRUE, quit: BOOL _ FALSE] = { IF NOT Ports.WirePortType[cellType, public].levelType=composite THEN { value: Ports.LevelSequence; subWires _ FALSE; thisWire.wire _ public; result _ Rope.Cat[result, CoreOps.GetFullWireName[cellType.public, public], " - "]; value _ Rosemary.WireValue[handle.simulation, thisWire ! Rosemary.NotInstantiated => GOTO NotFound]; result _ Rope.Cat[result, Ports.LevelSequenceToRope[value], "\n"]; EXITS NotFound => result _ Rope.Cat[result, "No such wire\n"]; }; }; flatCell: CoreFlat.FlatCellTypeRec; thisWire: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; cellType: Core.CellType; flatCell _ CoreFlat.ParseCellTypePath[handle.cellType, fullPathName, handle.cutSet]; cellType _ CoreFlat.ResolveFlatCellType[handle.cellType, flatCell].cellType; thisWire.flatCell _ flatCell; thisWire.wireRoot _ public; IF CoreOps.VisitWire[cellType.public, PrintPort] THEN ERROR; }; Rope.Equal[operation, "r"] => { wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; wireKey^ _ CoreFlat.ParseWirePath[handle.cellType, wireName, handle.cutSet]; IF NOT RemoveWireFromPlot[handle, wireKey] THEN result _ "No such wire plotted"; }; Rope.Equal[operation, "s"] => { flatCell: CoreFlat.FlatCellType _ NEW[CoreFlat.FlatCellTypeRec]; roseInstance: Rosemary.RoseCellInstance; flatCell^ _ CoreFlat.ParseCellTypePath[handle.cellType, fullPathName, handle.cutSet]; roseInstance _ NARROW[RefTab.Fetch[x: handle.simulation.coreToRoseInstances, key: flatCell].val]; IF roseInstance=NIL THEN result _ "No such instance" ELSE TRUSTED {Process.Detach[FORK DebugEvalProc[roseInstance.publicPort, roseInstance.state]]}; }; Rope.Equal[operation, "t"] => result _ DescribeWire[goryDetails: FALSE, handle: handle, wireName: wireName]; Rope.Equal[operation, "v"] => result _ WireValueRope[handle, wireName]; ENDCASE => IF NOT Rope.IsEmpty[operation] THEN result _ Rope.Cat["No such command: ", operation, ", commands are (a)dd wire to plot, (r)emove wire from plot, (s)tate, (v)alue, (t)race, (p)orts, (c)elltype, (c)elltype(n)ame, (c)elltype(p)ublic, and (d)rivers"]; EXITS Done => NULL; }; WireValueRope: PROC [handle: RoseDisplay, wireName: ROPE] RETURNS [rope: ROPE] = { key: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; key^ _ CoreFlat.ParseWirePath[handle.cellType, wireName, handle.cutSet]; rope _ Ports.LSToRope[Rosemary.WireValue[handle.simulation, key ! Rosemary.NotInstantiated => GOTO NotFound]]; EXITS NotFound => rope _ "No such wire"; }; DescribeWire: PROC [goryDetails: BOOL, handle: RoseDisplay, wireName: ROPE] RETURNS [result: ROPE] = { wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; parentKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; roseWire: Rosemary.RoseWire; wireKey^ _ CoreFlat.ParseWirePath[handle.cellType, wireName, handle.cutSet]; parentKey^ _ CoreFlat.CanonizeWire[handle.cellType, wireKey^]; roseWire _ NARROW[RefTab.Fetch[handle.simulation.coreToRoseWires, parentKey].val]; result _ IF roseWire=NIL THEN Rope.Cat[CoreFlat.WirePathRope[handle.cellType, wireKey^], " = ", WireValueRope[handle, wireName], "\nThis wire is not stored as a Rosemary wire, try a parent or child of it"] ELSE RoseWirePrint[goryDetails, handle.simulation, handle.cellType, roseWire]; }; RoseWirePrint: PROC [goryDetails: BOOL, simulation: Rosemary.Simulation, root: Core.CellType, roseWire: Rosemary.RoseWire] RETURNS [result: ROPE] = { CatWire: PROC [roseWire: Rosemary.RoseWire] = { result _ Rope.Cat[result, CoreFlat.WirePathRope[root, roseWire.wire], " - "]; IF roseWire.currentValue=NIL THEN { IF goryDetails THEN { result _ Rope.Cat[result, "m: ", IF roseWire.memory THEN "T" ELSE "F"]; result _ Rope.Cat[result, "cd: ", Ports.driveNames[roseWire.connectionDrive]]; result _ Rope.Cat[result, ", sd: ", Ports.driveNames[roseWire.switchDrive]]; result _ Rope.Cat[result, ", ud: ", Ports.driveNames[roseWire.upDrive]]; result _ Rope.Cat[result, ", dd: ", Ports.driveNames[roseWire.downDrive]]; result _ Rope.Cat[result, ", wd: ", Ports.driveNames[roseWire.wireDrive]]; result _ Rope.Cat[result, ", cl: ", Ports.levelNames[roseWire.connectionLevel], ", "]; }; result _ Rope.Cat[result, "wl: ", Ports.levelNames[roseWire.wireLevel]]; } ELSE result _ Ports.LevelSequenceToRope[roseWire.currentValue]; }; CatTran: PROC [roseTran: Rosemary.RoseTransistor] = { result _ Rope.Cat[result, " tt: ", CoreClasses.transistorTypeNames[roseTran.type]]; IF goryDetails THEN result _ Rope.Cat[result, ", tc: ", Ports.driveNames[roseTran.conductivity]]; }; FindPortWire: Ports.EachWirePortPairProc = { IF (quit _ port=clientPort) THEN coreWire.wire _ wire; }; clientPort: Ports.Port; coreWire: CoreFlat.FlatWireRec; coreWire.wireRoot _ public; CatWire[roseWire]; result _ Rope.Cat[result, "\nConnections\n"]; IF roseWire.connections#NIL THEN FOR fields: NAT IN [0..roseWire.connections.size) DO field: Rosemary.Field _ roseWire.connections[fields]; roseInstance: Rosemary.RoseCellInstance _ field.portBinding.instance; result _ Rope.Cat[result, " "]; clientPort _ field.portBinding.clientPort; IF NOT Ports.VisitBinding[wire: IF roseInstance=NIL THEN root.public ELSE CoreFlat.ResolveFlatCellType[root, roseInstance.instance].cellType.public, port: IF roseInstance=NIL THEN simulation.testPort ELSE roseInstance.publicPort, eachWirePortPair: FindPortWire] THEN ERROR; coreWire.flatCell _ IF roseInstance=NIL THEN CoreFlat.rootCellType ELSE roseInstance.instance; result _ Rope.Cat[result, CoreFlat.WirePathRope[root, coreWire]]; IF goryDetails THEN { result _ Rope.Cat[result, " - d: "]; IF clientPort.driveType=aggregate THEN result _ Rope.Cat[result, Ports.driveNames[field.portBinding.currentDrive]] ELSE FOR i: NAT IN [0..field.currentDrive.size) DO IF i=0 THEN result _ Rope.Cat[result, "("]; result _ Rope.Cat[result, Ports.driveNames[field.currentDrive[i]]]; result _ Rope.Cat[result, IF i=field.currentDrive.size-1 THEN ")" ELSE ", "]; ENDLOOP; result _ Rope.Cat[result, ", v: ", Ports.LevelSequenceToRope[field.currentValue]]; result _ Rope.Cat[result, ", sb: ", Convert.RopeFromCard[field.portStartBit]]; result _ Rope.Cat[result, ", fs: ", Convert.RopeFromCard[field.currentValue.size]]; }; result _ Rope.Cat[result, "\n"]; ENDLOOP; result _ Rope.Cat[result, "Channels\n"]; IF roseWire.channels#NIL THEN FOR channels: NAT IN [0..roseWire.channels.size) DO tran: Rosemary.RoseTransistor _ roseWire.channels[channels]; otherWire: Rosemary.RoseWire _ tran.ch1; CatTran[tran]; result _ Rope.Cat[result, "\n oc: "]; IF otherWire=roseWire THEN otherWire _ tran.ch2; CatWire[otherWire]; result _ Rope.Cat[result, "\n g: ", ]; CatWire[tran.gate]; result _ Rope.Cat[result, "\n"]; ENDLOOP; result _ Rope.Cat[result, "Gates\n"]; IF roseWire.gates#NIL THEN FOR gates: NAT IN [0..roseWire.gates.size) DO tran: Rosemary.RoseTransistor _ roseWire.gates[gates]; CatTran[tran]; result _ Rope.Cat[result, "\n c1: "]; CatWire[tran.ch1]; result _ Rope.Cat[result, "\n c2: ", ]; CatWire[tran.ch2]; result _ Rope.Cat[result, "\n"]; ENDLOOP; }; END. RosemaryUserViewerImpl.mesa Copyright Σ 1987 by Xerox Corporation. All rights reserved. Jean-Marc Frailong February 3, 1988 12:20:52 pm PST Pradeep Sindhu February 19, 1988 6:21:48 am PST Management of Rosemary viewers and the Tester abstraction Types & constants Display viewer x: entryHSpace, y: height-borderOffset, Default is always list.first. Tester abstraction check new state same as recorded state; Tester viewer The RoseDisplay is put as a CellType property and a tester viewer property to ease up data structure destrcution when the viewer is destroyed. x: xPos, y: height-borderOffset, Called when the tester is destroyed, before erasure by window manager Remove extraneous viewers, destroy backing file, remove circular references if any Management of typescript Κ‚˜codešœ™Kšœ<™Jšœ œŸ+˜BJšœœŸ"˜Kšœ$˜$Kšœ.œ˜MKšœœ˜œKšœM˜MJšœ0˜0Kšœœ˜8šœœ œ˜Jšœ ˜ Jšœ@˜@Jšœ˜—šœ˜Jšœ˜Jšœ˜J˜—Kšœ˜—Jšœ œ-˜=K˜—Jšœ˜K˜šœ4œœ˜IJšœ$œœœ˜5Jšœ˜—K˜K˜—š  œ)˜5Kšœœ ˜$šœœ˜Kšœ/œœ˜LKšœ6œœ˜RKšœ1œœ˜OKšœœŸ$˜6—Kšœ˜K˜—š  œ)˜3Kšœœ ˜$šœœ˜Kšœ3˜3KšœI˜IKšœH˜HKšœœŸ$˜6—Kš œœœ œœ1œ˜]Kšœ˜K˜—š  œ˜$Kšœœ ˜$šœ$œ˜,Kšœœ˜7K˜—Kšœœ˜œœ˜`Kšœœ˜6Kšœœ˜ KšœG˜GKšœ'˜'Kšœœ˜1KšœœAœ5˜€Kšœ˜—K˜K˜—š œœœœ˜OKšœœ=˜KK˜——™šœ,˜,J˜—š œœœœ˜>Kšœ4œ˜JKšœ˜K˜—š  œœœ˜+š œœ˜Kšœœœ˜7K˜—Kšœœœ^˜Kšœ˜K˜—š  œœ˜!K˜š œœ œœ œœœœ˜Vš  œ˜'Kšœ œœ ˜#KšœP˜PK˜—š  œ˜#Kšœ œœ ˜#Kšœ:˜:K˜—š˜Kšœœ-œ˜LJšœœœ7œ˜pJšœ<˜Kšœ˜—K˜—Kšœ0œœ˜YKšœJŸ˜ZKšœ/Ÿ˜?KšœcœŸ3˜J˜Jšœ)˜)Jšœ?˜?Jšœ.˜.Jšœ1˜1JšœJ˜JJšœ5˜5KšœAŸ ˜LJšœœ˜ Jšœ"˜"Jšœ%˜%Jšœ˜Jšœ;˜;KšœAŸ ˜Lšœœ˜Kšœ#˜#Kšœ+˜+KšœG˜GKšœAŸ ˜LKšœ˜—šœœœŸ7˜VJšœœœ˜Jš  œœœœK˜kJšœ˜Jšœœ˜š œœœœœœ˜>šœ=˜=Jšœ$˜$Jšœ˜Jšœœ-˜I—Jšœœ˜:Jšœœœ˜šœœ œ˜Jšœ ˜ Jšœ,˜,Jšœ˜—Jšœ˜Jšœ˜—Jšœ œ-˜=Jšœ.˜.J˜—Jšœ+˜+JšœU˜UJ˜J˜—š œ˜&Kšœ œ ˜Kšœ'œ ˜6š œœœ+œœ˜GKšœ!œœœ˜dKšœ˜—Kšœ(˜(Kšœ˜K˜—š œ˜'Kšœ œ ˜Kšœ ˜ K˜K˜—š  œ˜!Kšœ œ ˜Kšœœ œ˜2Kšœ˜K˜—š œ˜Kšœ œ ˜Kšœœ œ˜3Kšœ˜K˜—š œ˜Kšœ œ ˜Kšœœ œ˜2Kšœ˜K˜—š  œ˜"Kšœ œ ˜Kšœ˜Kšœœ œ˜2Kšœ˜K˜—š  œ˜!Kšœ œ ˜Kšœ˜Kšœ˜K˜—š  œ˜%Kšœ œ ˜Kšœ˜Kšœ˜K˜—š œœœœ˜=JšœYœ˜aK˜K˜—š  œœœ˜*Kšœ˜Kšœhœ˜pK˜K˜—š œ˜+K™EKšœœœ+˜7K˜KšœœœœœœœœœœŸ*˜}Kšœ œŸ ˜!Kšœœ#Ÿ˜RK˜K˜—š  œœ4˜GKšœR™RKšœ&˜&Kšœ!œC˜jKšœœœ œœœ œŸX˜²KšœœBœŸ˜|Kš œœœœœ$˜YK˜EKš œ œœœœŸ˜[K˜K˜——™š  œœœœœ˜FK˜—š  œœœœ˜:Kšœ"˜(K˜K˜—š  œ˜+Kšœ&œ˜7J˜š  œœœœœ˜1Jš œ œœœœ ˜%Jšœœ œœ˜KJšœ(˜(Jšœ˜J˜—Kšœœ˜+Kšœ3œ˜8Kšœ˜Kšœ0˜0Kšœ(˜(KšœQ˜Qšœœ˜šœ˜Kšœœ˜7KšœL˜LKšœ(˜(Kšœ˜—šœ˜Kš œœœœœ˜#Kšœn˜nKšœ[˜[Kšœ.˜.Kšœ œ˜&K˜—šœ ˜ Kšœn˜nKšœ[˜[Kšœ/˜/K˜—šœ ˜ Kš œœœœœ˜#Kšœn˜nKšœ[˜[Kšœ1˜1Kšœ?œ˜]K˜—KšœAœ&˜kšœ˜K˜š  œœœ œœœœ˜[šœœ:œ˜FKšœ˜Kšœ œ˜Kšœ˜KšœS˜SKšœUœ ˜dKšœB˜BKšœ9˜>K˜—K˜K˜—Kšœ#˜#Kšœœ˜8Kšœ˜KšœT˜TKšœL˜LKšœ˜K˜Kšœ/œœ˜˜_K˜—KšœAœ&˜lKšœG˜GKšœœœœΦ˜„—š˜Kšœœ˜ —K˜K™—š   œœ!œœœ˜RKšœœ˜3KšœH˜HKšœ^œ ˜nKšœ#˜(Kšœ˜K˜—š   œœœ!œœ œ˜fKšœœ˜7Kšœœ˜9Kšœ˜KšœL˜LKšœ>˜>Kšœ œA˜RKšœ œ œœ°˜ΝKšœJ˜NK˜K˜—š   œœœUœ œ˜•K˜š œœ"˜/KšœM˜Mšœœœ˜#šœ œ˜Kšœ!œœœ˜GKšœN˜NKšœL˜LKšœH˜HKšœJ˜JKšœJ˜JKšœV˜VK˜—KšœI˜IK˜—Kšœ;˜?K˜K˜—š œœ(˜5KšœT˜TKšœ œN˜aK˜K˜—š  œ ˜,Kšœœ˜6K˜K˜—Kšœ˜K˜Kšœ˜Kšœ˜Kšœ-˜-š œœœœ œœ ˜UKšœ5˜5KšœE˜EKšœ ˜ Kšœ*˜*Kšœœœœœ œRœœœœ:œœ˜‘Kš œœœœœ˜^KšœA˜Ašœ œ˜Kšœ$˜$Kšœ œL˜rš œœœœ˜2Kšœœ ˜+KšœC˜CKšœœœœ˜MKšœ˜—KšœR˜RKšœN˜NKšœS˜SK˜—Kšœ ˜ Kšœ˜—Kšœ(˜(š œœœœ œœ˜QK˜