DIRECTORY Atom, Basics, Buttons, ChoiceButtons, Containers, Convert, Core, CoreClasses, CoreFlat, CoreOps, FS, HashTable, IO, List, PlotGraph, Ports, Process, ProcessProps, Rope, ReadEvalPrint, Real, Rosemary, RosemaryUser, Rules, ViewerClasses, ViewerIO, ViewerOps, ViewerTools; RosemaryUserImpl: CEDAR MONITOR IMPORTS Buttons, ChoiceButtons, Containers, Convert, CoreClasses, CoreFlat, CoreOps, FS, HashTable, IO, List, PlotGraph, Ports, Process, ProcessProps, Rope, ReadEvalPrint, Real, Rosemary, Rules, 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 pointsPerInch: NAT = 72; -- horizontal space for text ropes borderOffset: NAT = 2; Column: TYPE = NAT [0..3); ColumnStart: ARRAY Column OF NAT = [entryVSpace, 1*pointsPerInch+entryVSpace, 4*pointsPerInch+entryVSpace]; testProcTable: HashTable.Table _ HashTable.Create[equal: HashTable.RopeEqual, hash: HashTable.HashRope]; 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: FALSE, 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]; }; 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] = { viewer: ViewerClasses.Viewer_ Containers.Create[[ name: name, iconic: FALSE, column: left, scrollable: FALSE ]]; height: CARDINAL _ entryVSpace; tester _ NEW[TesterRec]; tester.display _ NEW[RoseDisplayRec]; tester.steadyInit _ steady; tester.recordDeltas _ recordDeltas; tester.display.cutSet _ cutSet; tester.display.cellType _ cellType; tester.intermediatePort _ Ports.CreatePort[cellType, TRUE]; 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; }; [] _ Buttons.Create[info: [name: "Start Test", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: tester, proc: ButtonStartTest]; tester.runState _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[1], y: height-borderOffset, title: "Run State:", textViewerWidth: 2*pointsPerInch].textViewer; ViewerTools.InhibitUserEdits[tester.runState]; ViewerTools.SetContents[tester.runState, "Idle"]; IF historySize>0 THEN tester.historyTrigger _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[2], y: height-borderOffset, title: "History Trigger:", textViewerWidth: 2*pointsPerInch].textViewer; height _ height + entryHeight + entryVSpace; [] _ Buttons.Create[info: [name: "Interrupt", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: tester, proc: Interrupt]; tester.evalsSinceStart _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[1], y: height-borderOffset, title: "Evals Since Start:", textViewerWidth: 1*pointsPerInch].textViewer; ViewerTools.InhibitUserEdits[tester.evalsSinceStart]; IF historySize>0 THEN [] _ Buttons.Create[info: [name: "Next State", wx: ColumnStart[2], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: tester, proc: NextState]; height _ height + entryHeight + entryVSpace; [] _ Buttons.Create[info: [name: "Proceed", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: tester, proc: Proceed]; tester.proceedUntil _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[1], y: height-borderOffset, title: "Proceed Until:", textViewerWidth: 1*pointsPerInch].textViewer; IF historySize>0 THEN [] _ Buttons.Create[info: [name: "Previous State", wx: ColumnStart[2], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: tester, proc: PreviousState]; height _ height + entryHeight + entryVSpace; [] _ Buttons.Create[info: [name: "Abort", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: tester, proc: Abort, guarded: TRUE]; [] _ Buttons.Create[info: [name: "Single Eval", wx: ColumnStart[1]+borderOffset, wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: tester, proc: SingleEval]; height _ height + entryHeight + entryVSpace; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; IF testButtons.rest#NIL THEN { 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, $BlackOnGrey]; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; }; tester.currentTestProc _ testButtons.first; MakeDisplayAndBrowse[displayWires, graphWires, height, tester.display, viewer, name]; }; MakeDisplayAndBrowse: PROC [displayWires: CoreFlat.FlatWires, graphWires: CoreFlat.FlatWires, height: CARDINAL, handle: RoseDisplay, viewer: ViewerClasses.Viewer, name: ROPE] = { handle.wDir _ ProcessProps.GetProp[$WorkingDirectory]; { rep: ReadEvalPrint.Handle; [handle.tsin, handle.tsout] _ ViewerIO.CreateViewerStreams[name: Rope.Cat[name, " Rosemary Script"]]; 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]; }; IF displayWires#NIL THEN { Column: TYPE = NAT [0..2); ColumnStart: ARRAY Column OF NAT = [entryVSpace, 3*pointsPerInch+pointsPerInch/4+entryVSpace]; column: Column _ 0; count: INT _ 0; 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^]; IF Rope.Equal[Rope.Substr[dn, 0, 7], "public."] THEN dn _ Rope.Substr[dn, 7]; handle.displayWires _ CONS[ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[column], y: height-borderOffset, title: dn, textViewerWidth: 2*pointsPerInch, clientdata: dws.first], handle.displayWires]; ViewerTools.InhibitUserEdits[handle.displayWires.first.textViewer]; IF column=LAST[Column] THEN { column _ 0; height _ height + entryHeight + entryVSpace; } ELSE column _ column+1; ENDLOOP; IF column>0 THEN height _ height + entryHeight + entryVSpace; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; }; [] _ Buttons.Create[info: [name: "Update", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: handle, proc: UpdateDisplayButton]; [] _ Buttons.Create[info: [name: "Log", wx: ColumnStart[1], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: handle, proc: LogChanges]; height _ height + entryHeight + entryVSpace; handle.path _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[0], y: height-borderOffset, title: "Instantiation Path:", textViewerWidth: 4*pointsPerInch].textViewer; height _ height + entryHeight + entryVSpace; handle.currentWire _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[0], y: height-borderOffset, title: "Current Wire:", textViewerWidth: 4*pointsPerInch].textViewer; height _ height + entryHeight + entryVSpace; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; ViewerOps.SetOpenHeight[viewer, height]; ViewerOps.PaintViewer[viewer, all]; handle.name _ name; FOR wires: CoreFlat.FlatWires _ graphWires, wires.rest UNTIL wires=NIL DO IF AddWireToPlot[handle, wires.first]#NIL THEN ERROR; ENDLOOP; }; LogChanges: Buttons.ButtonProc = { h: RoseDisplay _ NARROW[clientData]; IF (h.logChanges _ ~h.logChanges) THEN { Buttons.SetDisplayStyle[NARROW[parent], $WhiteOnBlack]; } ELSE Buttons.SetDisplayStyle[NARROW[parent], $BlackOnWhite]; }; RegisterTestProc: PUBLIC PROC [name: ROPE, proc: TestProc] = { [] _ HashTable.Store[table: testProcTable, key: name, value: NEW[TestProc _ proc]]; }; 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 $BlackOnGrey ELSE $BlackOnWhite]; ENDLOOP; h.currentTestProc _ selectedButton.name; }; AbortSignal: SIGNAL = CODE; LogSettle: PUBLIC PROC [handle: RoseDisplay, time: INT] = { UpdateWire: Rosemary.UpdateProc = { coreWire: CoreFlat.FlatWireRec; RecordDelta[handle, roseWire, time]; IF NOT handle.logChanges THEN RETURN; UpdateDisplay[handle]; coreWire _ roseWire.wire; wireKey^ _ coreWire; IO.PutF[handle.tsout, "%g_%g ", IO.rope[CoreFlat.WirePathRope[handle.cellType, coreWire]], IO.rope[Ports.LevelSequenceToRope[Rosemary.WireValue[ handle.simulation, wireKey]]]]; }; wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; Rosemary.Settle[handle.simulation, UpdateWire]; DeltaFinished[handle, time]; IF handle.logChanges THEN IO.PutRope[handle.tsout, "\n\n"]; }; ButtonStartTest: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; StartTest[h]; }; 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] = { UpdateWire: Rosemary.UpdateProc = { coreWire: CoreFlat.FlatWireRec; IF h.abort THEN SIGNAL AbortSignal; IF h.recordDeltas THEN RecordDelta[h.display, roseWire, h.evalSinceStartCount+1]; IF h.display.logChanges THEN { UpdateDisplay[h.display]; coreWire _ roseWire.wire; wireKey^ _ coreWire; IO.PutF[h.display.tsout, "%g_%g ", IO.rope[CoreFlat.WirePathRope[h.display.cellType, coreWire]], IO.rope[Ports.LevelSequenceToRope[Rosemary.WireValue[ h.display.simulation, wireKey]]]]; }; }; 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]; IF h.display.logChanges 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]]; }; 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; }; wireKey: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec]; testProc: TestProc _ NARROW[HashTable.Fetch[table: testProcTable, key: h.currentTestProc].value, REF TestProc]^; currentTestPort: Ports.Port _ Ports.CreatePort[h.display.cellType, TRUE]; IF testProc=NIL THEN ERROR; UpdateESSC[h, 0]; h.validStates _ 0; SetEvalUntil[h: h, interrupt: FALSE, abort: FALSE]; ViewerTools.SetContents[h.runState, "Initializing"]; Rosemary.Initialize[simulation: h.display.simulation, steady: h.steadyInit]; InitializeDeltas[h.display]; ViewerTools.SetContents[h.runState, "Running"]; testProc[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]]; 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; }; 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]; }; 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; }; NextState: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; DoNextState[h]; }; 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]; }; }; }; PreviousState: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; DoPreviousState[h]; }; 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]; }; }; }; SetProceedUntil: PUBLIC PROC [tester: Tester, count: INT] = { ViewerTools.SetContents[tester.proceedUntil, Convert.RopeFromInt[from: count, showRadix: FALSE]]; }; 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; }; UpdateDisplayButton: Buttons.ButtonProc = { handle: RoseDisplay _ NARROW[clientData]; UpdateDisplay[handle]; }; 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, CoreOps.WireBits[dw.wire]]; 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; }; NextBuf: PROC [h: Tester, buf: NAT] RETURNS [next: NAT] = { next _ (buf + 1) MOD h.historySize; }; UpdateESSC: PROC [h: Tester, new: INT] = { h.evalSinceStartCount _ new; ViewerTools.SetContents[h.evalsSinceStart, Convert.RopeFromCard[from: h.evalSinceStartCount, showRadix: FALSE]]; }; 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[HashTable.Fetch[table: handle.simulation.coreToRoseInstances, key: flatCell].value]; 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[HashTable.Fetch[handle.simulation.coreToRoseWires, parentKey].value]; 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, "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; }; DisplayPortLeafWires: PUBLIC PROC [root: Core.CellType, flatCell: CoreFlat.FlatCellTypeRec _ CoreFlat.rootCellType] RETURNS [displayWires: CoreFlat.FlatWires] = { CompareFlatWires: List.CompareProc = { flat1: CoreFlat.FlatWire _ NARROW[ref1]; flat2: CoreFlat.FlatWire _ NARROW[ref2]; IF flat1.flatCell.path.length>flat2.flatCell.path.length THEN RETURN [greater]; IF flat1.flatCell.path.length RETURN [greater]; (NOT one) AND other => RETURN [less]; ENDCASE; ENDLOOP; IF flat1.flatCell.recastCount>flat2.flatCell.recastCount THEN RETURN [greater]; IF flat1.flatCell.recastCount GOTO NoSuchWire]; graphPlotData: GraphPlotData _ NEW[GraphPlotDataRec]; plot: PlotGraph.Plot _ handle.plot; axis: PlotGraph.Axis _ NEW[PlotGraph.AxisRec _ [ bounds: [0.0, 0.0, 10.0, 6.0], name: CoreFlat.WirePathRope[handle.cellType, wire^], axisData: [[ ticks: 1.0, visible: TRUE, grid: FALSE],[ ticks: 1.0, visible: TRUE, grid: FALSE]]]]; graph: PlotGraph.Graph _ NEW[PlotGraph.GraphRec _ [ class: RoseGraphClass, data: graphPlotData]]; size: NAT _ 0; graphPlotData.roseValues _ roseValues; [graphPlotData.bits, graphPlotData.parts, size] _ BitsAndParts[handle, roseValues]; IF Rope.Equal[Rope.Substr[axis.name, 0, 7], "public."] THEN axis.name _ Rope.Substr[axis.name, 7]; IF roseValues.rest=NIL AND roseValues.first.fieldWidth=1 THEN axis.style _ analog ELSE { axis.style _ hexaV; axis.maxChars _ (size+3)/4; }; IF plot=NIL THEN { plot _ handle.plot _ PlotGraph.CreatePlot[handle.name]; PlotGraph.LockPlot[plot]; plot.lowerBounds _ [0.0, 0.0]; plot.upperBounds _ [Real.Float[handle.lastValidTime], 5.0]; plot.data _ handle; } ELSE PlotGraph.LockPlot[plot]; IF plot.axis#NIL THEN axis.bounds _ plot.axis.first.bounds; plot.axis _ CONS[axis, plot.axis]; axis.graphs _ CONS[graph, axis.graphs]; PlotGraph.UnlockPlot[plot]; PlotGraph.RefreshPlot[plot: plot, eraseFirst: TRUE]; EXITS NoSuchWire => msg _ "Not stored as a Rosemary wire"; }; RemoveWireFromPlot: PUBLIC PROC [handle: RoseDisplay, wire: CoreFlat.FlatWire] RETURNS [found: BOOL _ FALSE] = { roseValues: Rosemary.RoseValues _ Rosemary.GetValues[handle.simulation, wire ! Rosemary.NotInstantiated => GOTO NoSuchWire]; plot: PlotGraph.Plot _ handle.plot; trail: PlotGraph.AxisList _ NIL; IF plot=NIL THEN RETURN; PlotGraph.LockPlot[plot]; FOR axis: PlotGraph.AxisList _ plot.axis, axis.rest UNTIL axis=NIL DO data: GraphPlotData _ NARROW[axis.first.graphs.first.data]; IF data.roseValues=roseValues THEN { IF trail=NIL THEN plot.axis _ axis.rest ELSE trail.rest _ axis.rest; found _ TRUE; EXIT; }; trail _ axis; REPEAT FINISHED => found _ FALSE; ENDLOOP; PlotGraph.UnlockPlot[plot]; PlotGraph.RefreshPlot[plot: plot, eraseFirst: TRUE]; EXITS NoSuchWire => NULL; }; InitializeDeltas: PUBLIC PROC [handle: RoseDisplay] = { SetDelta: HashTable.EachPairAction = { roseWire: Rosemary.RoseWire _ NARROW[value]; head: GraphData _ NARROW[roseWire.data]; IF head#NIL THEN head.first _ head.last _ head.nextToLast _ head.secondToLast _ NIL; RecordDelta[handle, roseWire, 0]; }; IF handle.ps=NIL THEN handle.ps _ FS.StreamOpen["///Temp/RoseBackingStore.bin", $create] ELSE IO.Reset[handle.ps]; IF handle.psHash=NIL THEN handle.psHash _ HashTable.Create[]; [] _ HashTable.Pairs[table: handle.simulation.coreToRoseWires, action: SetDelta]; handle.lastValidTime _ 0; IF handle.plot#NIL THEN PlotGraph.RefreshPlot[plot: handle.plot, eraseFirst: TRUE]; }; DeltaFinished: PUBLIC PROC [handle: RoseDisplay, time: INT] = { plot: PlotGraph.Plot _ handle.plot; handle.lastValidTime _ time; IF plot#NIL THEN { oldUpper: REAL _ plot.upperBounds.x; newUpper: REAL _ Real.Float[time]; plot.upperBounds.x _ newUpper; PlotGraph.RefreshPlot[plot: plot, within: [oldUpper, 0.0, newUpper-oldUpper, 6.0]]; }; }; GraphPlotData: TYPE = REF GraphPlotDataRec; GraphPlotDataRec: TYPE = RECORD [ roseValues: Rosemary.RoseValues _ NIL, parts: GraphValueSequence _ NIL, bits: Ports.LevelSequence _ NIL]; GraphData: TYPE = REF GraphDataRec; GraphDataRec: TYPE = RECORD [ first, last, nextToLast, secondToLast: GraphValue _ NIL, interested: BOOL _ FALSE]; GraphValue: TYPE = REF GraphValueRec; GraphValueRec: TYPE = RECORD [ next: GraphValue _ NIL, time: INT _ LAST[INT], value: SEQUENCE size: CARDINAL OF Ports.Level]; GraphValueSequence: TYPE = REF GraphValueSequenceRec; GraphValueSequenceRec: TYPE = RECORD [ parts: SEQUENCE size: CARDINAL OF GraphValue]; RecordDelta: PUBLIC PROC [handle: RoseDisplay, wire: Rosemary.RoseWire, time: INT] = { head: GraphData _ NARROW[wire.data]; single: BOOL _ wire.currentValue=NIL; size: NAT _ IF single THEN 1 ELSE wire.currentValue.size; new: BOOL _ FALSE; LockBackingStore[handle]; IF head=NIL THEN wire.data _ head _ NEW[GraphDataRec]; IF head.last=NIL THEN new _ TRUE ELSE IF time>head.last.time THEN { IF single THEN new _ wire.wireLevel#head.last[0] ELSE FOR i: NAT IN [0..size) DO IF head.last.value[i] # wire.currentValue[i] THEN { new _ TRUE; EXIT; }; ENDLOOP; } ELSE { collapse: BOOL _ FALSE; IF head.nextToLast#NIL THEN { IF single THEN collapse _ head.nextToLast.value[0] = wire.wireLevel ELSE { collapse _ TRUE; FOR i: NAT IN [0..size) DO IF head.nextToLast.value[i] # wire.currentValue[i] THEN { collapse _ FALSE; EXIT; }; ENDLOOP; }; }; IF collapse THEN { head.last.time _ LAST[INT]; head.last _ head.nextToLast; head.nextToLast _ head.secondToLast; head.secondToLast _ NIL; } ELSE IF single THEN head.last.value[0] _ wire.wireLevel ELSE FOR i: NAT IN [0..size) DO head.last.value[i] _ wire.currentValue[i]; ENDLOOP; }; IF new THEN { value: GraphValue; IF head.secondToLast=NIL OR head.interested THEN { value _ IF head.last=NIL OR head.last.next=NIL THEN NEW[GraphValueRec[size]] ELSE head.last.next; IF head.first=NIL AND head.last=NIL THEN head.first _ value; } ELSE { WriteLong: PROC [l: bytes Basics.LongNumber] = { IO.PutChar[handle.ps, LOOPHOLE[l.lh]]; IO.PutChar[handle.ps, LOOPHOLE[l.ll]]; IO.PutChar[handle.ps, LOOPHOLE[l.hh]]; IO.PutChar[handle.ps, LOOPHOLE[l.hl]]; }; value _ head.secondToLast; WriteLong[LOOPHOLE[head]]; [] _ HashTable.Insert[handle.psHash, head, head]; WriteLong[LOOPHOLE[value.time]]; FOR i: CARDINAL IN [0..value.size) DO IO.PutChar[handle.ps, LOOPHOLE[value.value[i]]]; ENDLOOP; value.next _ NIL; head.first _ NIL; }; value.time _ time; IF single THEN value.value[0] _ wire.wireLevel ELSE FOR i: NAT IN [0..size) DO value.value[i] _ wire.currentValue[i]; ENDLOOP; IF head.last#NIL THEN head.last.next _ value; head.secondToLast _ head.nextToLast; head.nextToLast _ head.last; head.last _ value; }; UnlockBackingStore[handle]; }; LockBackingStore: ENTRY PROC [h: RoseDisplay] = { UNTIL NOT h.psLock DO WAIT h.psWait ENDLOOP; h.psLock _ TRUE; }; UnlockBackingStore: ENTRY PROC [h: RoseDisplay] = { h.psLock _ FALSE; BROADCAST h.psWait; }; BitsAndParts: PROC [handle: RoseDisplay, roseValues: Rosemary.RoseValues] RETURNS [bits: Ports.LevelSequence, parts: GraphValueSequence, size: NAT _ 0] = { partCount: NAT _ 0; fetchValues: HashTable.Table _ HashTable.Create[]; LockBackingStore[handle]; FOR vals: Rosemary.RoseValues _ roseValues, vals.rest UNTIL vals=NIL DO graphData: GraphData _ NARROW[vals.first.roseWire.data]; size _ size + vals.first.fieldWidth; IF graphData=NIL THEN vals.first.roseWire.data _ graphData _ NEW[GraphDataRec]; partCount _ partCount + 1; graphData.interested _ TRUE; IF graphData.first=NIL AND graphData.last#NIL THEN IF NOT HashTable.Insert[fetchValues, graphData, NIL] THEN ERROR; ENDLOOP; IF HashTable.GetSize[fetchValues]>0 THEN { ReadLong: PROC RETURNS [l: bytes Basics.LongNumber] = { l.lh _ LOOPHOLE[IO.GetChar[handle.ps]]; l.ll _ LOOPHOLE[IO.GetChar[handle.ps]]; l.hh _ LOOPHOLE[IO.GetChar[handle.ps]]; l.hl _ LOOPHOLE[IO.GetChar[handle.ps]]; }; index: INT _ IO.GetIndex[handle.ps]; IO.SetIndex[handle.ps, 0]; TRUSTED { UNTIL IO.GetIndex[handle.ps]=index DO head: GraphData _ NARROW[HashTable.Fetch[handle.psHash, LOOPHOLE[ReadLong[]]].value]; size: CARDINAL _ head.last.size; found: BOOL; lastRef: REF ANY; [found, lastRef] _ HashTable.Fetch[fetchValues, head]; IF found THEN { last: GraphValue _ NARROW[lastRef]; new: GraphValue _ NEW[GraphValueRec[size]]; new.time _ LOOPHOLE[ReadLong[]]; FOR i: CARDINAL IN [0..size) DO new.value[i] _ LOOPHOLE[IO.GetChar[handle.ps]]; ENDLOOP; IF last=NIL THEN { head.first _ new; new.next _ SELECT TRUE FROM head.secondToLast#NIL => head.secondToLast, head.nextToLast#NIL => head.nextToLast, ENDCASE => head.last; } ELSE { new.next _ last.next; last.next _ new; }; IF NOT HashTable.Replace[fetchValues, head, new] THEN ERROR; } ELSE { [] _ ReadLong[]; FOR i: CARDINAL IN [0..size) DO [] _ IO.GetChar[handle.ps]; ENDLOOP; }; ENDLOOP; }; }; UnlockBackingStore[handle]; bits _ NEW[Ports.LevelSequenceRec[size]]; parts _ NEW[GraphValueSequenceRec[partCount]]; }; InitBitsAndParts: PROC [roseValues: Rosemary.RoseValues, bits: Ports.LevelSequence, parts: GraphValueSequence, bound: REAL] RETURNS [lastTime: INT _ 0] = { EnumValues: PROC [valueExpr: PROC [graphData: GraphData] RETURNS [value: GraphValue]] RETURNS [quit: BOOL _ FALSE] = { firstFreeBit: NAT _ 0; partCount: NAT _ 0; FOR vals: Rosemary.RoseValues _ roseValues, vals.rest UNTIL vals=NIL DO graphData: GraphData _ NARROW[vals.first.roseWire.data]; value: GraphValue _ valueExpr[graphData]; IF value=NIL THEN RETURN [TRUE]; parts[partCount] _ value; partCount _ partCount + 1; FOR bit: NAT IN [0..value.size) DO bits[firstFreeBit+bit] _ value.value[bit]; ENDLOOP; firstFreeBit _ firstFreeBit + value.size; ENDLOOP; }; BoundValue: PROC [graphData: GraphData] RETURNS [value: GraphValue _ NIL] = { CheckValue: PROC [check: GraphValue] = { IF check#NIL AND check.time<=bound THEN { value _ check; lastTime _ MAX[lastTime, check.time]; }; }; IF graphData#NIL THEN { CheckValue[graphData.last]; IF value=NIL THEN CheckValue[graphData.nextToLast]; IF value=NIL THEN CheckValue[graphData.secondToLast]; }; }; UnboundValue: PROC [graphData: GraphData] RETURNS [value: GraphValue] = { value _ IF graphData=NIL THEN NIL ELSE graphData.first; }; IF EnumValues[BoundValue] THEN { lastTime _ 0; IF EnumValues[UnboundValue] THEN lastTime _ -1; }; }; WireTimeValue: PUBLIC PROC [handle: RoseDisplay, flatWire: CoreFlat.FlatWire, time: INT] RETURNS [value: Ports.LevelSequence] = { simulation: Rosemary.Simulation _ handle.simulation; roseValues: Rosemary.RoseValues _ Rosemary.GetValues[simulation, flatWire]; parts: GraphValueSequence; partCount: NAT _ 0; [value, parts] _ BitsAndParts[handle, roseValues]; partCount _ parts.size; IF InitBitsAndParts[roseValues, value, parts, time]>=0 THEN DO firstBit: NAT _ 0; minTime: INT _ LAST[INT]; FOR v: NAT IN [0..partCount) DO IF parts[v].next#NIL THEN minTime _ MIN[minTime, parts[v].next.time]; ENDLOOP; IF minTime > time THEN EXIT; FOR v: NAT IN [0..partCount) DO IF parts[v].next#NIL AND parts[v].next.time=minTime THEN { parts[v] _ parts[v].next; FOR bit: NAT IN [0..parts[v].size) DO value[firstBit+bit] _ parts[v].value[bit]; ENDLOOP; }; firstBit _ firstBit + parts[v].size; ENDLOOP; ENDLOOP; }; RoseGraphEnumerate: PlotGraph.GraphEnumerateProc = { WritePoint: PROC [time: INT] RETURNS [quit: BOOL] = { quit _ IF analog THEN eachPoint[ Real.Float[time], SELECT bits[0] FROM L => 0.0, X => 2.5, H => 5.0, ENDCASE => ERROR, data] ELSE eachPoint[x: Real.Float[time], y:0.0, data: data, rope: Ports.LSToRope[bits]]; }; handle: RoseDisplay _ NARROW[plot.data]; graphPlotData: GraphPlotData _ NARROW[graph.data]; roseValues: Rosemary.RoseValues _ graphPlotData.roseValues; parts: GraphValueSequence _ graphPlotData.parts; bits: Ports.LevelSequence _ graphPlotData.bits; analog: BOOL _ roseValues.rest=NIL AND roseValues.first.fieldWidth=1; partCount: NAT _ parts.size; lastTime: INT _ InitBitsAndParts[roseValues, bits, parts, bounds.x]; IF lastTime>=0 AND NOT WritePoint[lastTime] THEN { quit: BOOL _ FALSE; minTime: INT; DO firstBit: NAT _ 0; minTime _ LAST[INT]; FOR v: NAT IN [0..partCount) DO IF parts[v].next#NIL THEN minTime _ MIN[minTime, parts[v].next.time]; ENDLOOP; IF minTime > handle.lastValidTime THEN EXIT; IF analog THEN IF (quit _ WritePoint[minTime]) THEN EXIT; FOR v: NAT IN [0..partCount) DO IF parts[v].next#NIL AND parts[v].next.time=minTime THEN { parts[v] _ parts[v].next; FOR bit: NAT IN [0..parts[v].size) DO bits[firstBit+bit] _ parts[v].value[bit]; ENDLOOP; }; firstBit _ firstBit + parts[v].size; ENDLOOP; lastTime _ minTime; IF (quit _ WritePoint[lastTime]) THEN EXIT; ENDLOOP; IF (NOT quit) AND lastTime < handle.lastValidTime THEN [] _ WritePoint[handle.lastValidTime]; }; }; END. ΊRosemaryUserImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Barth, February 17, 1987 10:57:59 am PST Bertrand Serlet October 17, 1986 10:07:27 pm PDT Last Edited by: Gasbarro October 24, 1986 12:39:47 pm PDT Jean-Marc Frailong November 3, 1986 5:36:54 pm PST check new state same as recorded state; Wire Display Plotting [plot: Plot, graph: Graph, bounds: Rectangle, eachPoint: PointProc, data: REF ANY] Κ*€– "cedar" style˜codešœ™Kšœ Οmœ7™BK™(K™0K™9K™2K™—KšΟk œbžœ žœ›˜—K˜•StartOfExpansion[]šΠbnœžœž˜KšžœNžœ žœ}˜γKšžœ ˜Kšœžœžœ˜—J˜Jšœ žœΟc&˜=Jšœ žœ '˜>Jšœžœ "˜Kšžœ˜—K˜—J˜šœ.˜.Jšœ˜Jšœ˜Jšœžœ.˜J—Jšœ­˜­Jšœ.˜.Jšœ1˜1JšžœžœΊ˜ΟJšœ,˜,J˜Jšœ~žœ(˜ͺJšœΌ˜ΌJšœ5˜5Jšžœžœ€žœ(˜ΑJšœ,˜,J˜Jšœ|žœ&˜¦Jšœ΅˜΅Jšžœžœ„žœ,˜ΙJšœ,˜,J˜Jšœzžœ-žœ˜±Jšœžœ)˜ΊJšœ,˜,J˜Jšœa˜aJšœ˜J˜šžœžœžœ˜Jšœž œ˜Jšœ žœžœžœK˜kJšœ˜Jšœžœ˜š žœžœžœžœžœžœž˜>šœ=˜=Jšœ$˜$Jšœ˜Jšœžœ-˜I—Jšœžœ˜:Jšžœžœžœ˜šžœžœ žœ˜Jšœ ˜ Jšœ,˜,Jšœ˜—Jšžœ˜Jšžœ˜—Jšžœ žœ-˜=Jšœ-˜-Jšœa˜aJšœ˜J˜—Jšœ+˜+J˜JšœU˜UJ˜J˜—š‘œžœLžœ;žœ˜²Kšœ6˜6šœ˜Kšœ˜Kšœe˜eKšœ…žœ˜‹Kšœ˜Kšœ+žœ˜0K˜—šžœžœžœ˜Jšœžœžœ˜Jšœ žœžœžœ>˜^Jšœ˜Jšœžœ˜šžœ2žœžœž˜EK˜Kšžœ˜—Kšžœ žœžœ]žœ ˜šžœ2žœžœž˜JKšœžœ6˜>Kšžœ.žœ˜MKšœžœΉ˜ΣJšœC˜Cšžœžœ žœ˜Jšœ ˜ Jšœ,˜,Jšœ˜—Jšžœ˜Kšžœ˜—Jšžœ žœ-˜=Kšœa˜aKšœ˜K˜J˜—Jšœ{žœ2˜±Jšœxžœ)˜₯Jšœ,˜,Jšœ²˜²Jšœ,˜,Jšœ³˜³Jšœ,˜,J˜Jšœa˜aJšœ(˜(Jšœ#˜#K˜šžœ4žœžœž˜IJšžœ$žœžœžœ˜5Jšžœ˜—K˜K˜—šΟb œ˜"Kšœžœ ˜$šžœ žœ˜(Kšœžœ˜7K˜—Kšžœžœ˜Kšœ=žœ˜SKšœ˜K˜—š‘œ˜&Kšœ žœ ˜Kšœ'žœ ˜6š žœžœžœ+žœžœž˜GKšœ!žœžœžœ˜cKšžœ˜—Kšœ(˜(Kšœ˜K˜—šœ žœžœ˜K˜—š‘ œžœžœžœ˜;K˜š‘ œ˜#Kšœ˜Kšœ$˜$Kšžœžœžœžœ˜%Kšœ˜Kšœ˜Kšœ˜Kšžœžœ9žœS˜°K˜—K˜Kšœžœ˜7Kšœ/˜/Kšœ˜Kšžœžœžœ˜;˜K˜——š‘œ˜'Kšœ žœ ˜Kšœ ˜ K˜K˜—š‘ œžœžœ˜+š‘œžœ˜Kšžœžœžœ˜7K˜—Kšœžœžœ^˜Kšœ˜K˜—š‘ œžœ˜!K˜š‘œžœ žœžœ˜$K˜š‘ œ˜#Kšœ˜Kšžœ žœžœ ˜#Kšžœžœ;˜Qšžœžœ˜Kšœ˜Kšœ˜Kšœ˜Kšžœ!žœ<žœV˜ΉK˜—K˜K˜—šž˜Kšœžœ-žœ˜LJšœžœžœ7žœ˜pJšœ<˜žœžœž˜`Kšœžœ˜6Kšœžœ˜ KšœG˜GKšœB˜BKšžœžœ˜1KšžœžœAžœ5˜€Kšžœ˜—K˜K˜—š ‘œžœžœžœžœ˜;Kšœžœ˜#K˜K˜—š‘ œžœžœ˜*Kšœ˜Kšœhžœ˜pK˜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šœ žœF˜WKšœ žœ žœžœ°˜ΝKšžœJ˜NK˜K˜—š ‘ œžœžœUžœ žœ˜•K˜š‘œžœ"˜/KšœM˜Mšžœžœžœ˜#šžœ žœ˜Kšœ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˜žœ ˜›Kšœ žœ˜Kšœ2˜2Kšœ˜šžœ3žœžœž˜GKšœžœ˜8Kšœ$˜$Kšžœ žœžœ(žœ˜OKšœ˜Kšœžœ˜Kšžœžœžœžœžœžœžœ*žœžœžœ˜sKšžœ˜—šžœ"žœ˜*K˜š‘œžœžœ!˜7Kšœžœžœ˜'Kšœžœžœ˜'Kšœžœžœ˜'Kšœžœžœ˜'K˜K˜—Kšœžœžœ˜$Kšžœ˜šžœ˜ šžœžœž˜%Kšœžœ žœ˜UKšœžœ˜ Kšœžœ˜ Kšœ žœžœ˜Kšœ6˜6šžœžœ˜Kšœžœ ˜#Kšœžœ˜+Kšœ žœ ˜ šžœžœžœ ž˜Kšœžœžœ˜/Kšžœ˜—šžœžœžœ˜Kšœ˜šœ žœžœž˜Kšœžœ˜+Kšœžœ˜'Kšžœ˜—K˜—šžœ˜K˜K˜K˜—Kšžœžœ+žœžœ˜Kšœ žœ˜Kšœ žœžœžœ˜šžœžœžœž˜Kšžœžœžœ žœ˜EKšžœ˜—Kšžœžœžœ˜šžœžœžœž˜šžœžœžœžœ˜:K˜šžœžœžœž˜%Kšœ*˜*Kšžœ˜—K˜—Kšœ$˜$Kšžœ˜—Kšžœ˜—K˜K˜—š‘œ"˜4KšœR™RK˜š ‘ œžœžœžœžœ˜5šœžœžœ ˜ Kšœ˜šžœ žœ˜K˜ K˜ K˜ Kšžœžœ˜—Kšœ˜—KšžœO˜SK˜K˜—Kšœžœ ˜(Kšœžœ ˜2Kšœ;˜;Kšœ0˜0Kšœ/˜/Kšœžœžœžœ˜EKšœ žœ˜Kšœ žœ7˜Dšžœ žœžœžœ˜2Kšœžœžœ˜Kšœ žœ˜ šž˜Kšœ žœ˜Kšœ žœžœ˜šžœžœžœž˜Kšžœžœžœ žœ˜EKšžœ˜—Kšžœ žœžœ˜,Kš žœžœžœžœžœ˜9šžœžœžœž˜šžœžœžœžœ˜:K˜šžœžœžœž˜%Kšœ)˜)Kšžœ˜—K˜—Kšœ$˜$Kšžœ˜—Kšœ˜Kšžœžœžœ˜+Kšžœ˜—Kšžœžœžœ!žœ'˜]K˜—K˜K˜——Kšžœ˜—…—‘ΠΞ.