<> <> <> <<>> DIRECTORY Buttons, ChoiceButtons, Containers, Convert, Core, CoreClasses, CoreFlat, CoreOps, IO, Ports, Process, Rope, ReadEvalPrint, Rosemary, RosemaryUser, Rules, ViewerClasses, ViewerIO, ViewerOps, ViewerTools; RosemaryUserImpl: CEDAR MONITOR IMPORTS Buttons, ChoiceButtons, Containers, Convert, CoreFlat, CoreOps, IO, Ports, Process, Rope, ReadEvalPrint, Rosemary, Rules, ViewerIO, ViewerOps, ViewerTools EXPORTS RosemaryUser = BEGIN OPEN RosemaryUser; debug: BOOL _ FALSE; 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]; Tester: TYPE = REF TesterRec; TesterRec: TYPE = RECORD [ cellType: Core.CellType, testPort: Ports.Port _ NIL, intermediatePort: Ports.Port _ NIL, simulation: Rosemary.Simulation _ NIL, runState: ViewerClasses.Viewer _ NIL, evalsSinceStart: ViewerClasses.Viewer _ NIL, evalSinceStartCount: INT, proceedUntil: ViewerClasses.Viewer _ NIL, evalUntil: INT, historyTrigger: ViewerClasses.Viewer _ NIL, historyTriggerCount: INT, currentStatePoint: NAT _ 0, displayedStatePoint: NAT _ 0, validStates: NAT _ 0, historySize: NAT _ 0, testVectorBuffer: Rosemary.PortSequence _ NIL, proceed: CONDITION, testStarted: BOOL _ FALSE, waiting: BOOL _ FALSE, abort: BOOL _ FALSE, interrupt: BOOL _ FALSE, singleEval: BOOL _ FALSE, displayWires: LIST OF ChoiceButtons.PromptDataRef _ NIL, testButtonList: LIST OF Buttons.Button, currentTestProc: TestProc, tsin: IO.STREAM _ NIL, tsout: IO.STREAM _ NIL, currentInstancePath: CoreFlat.InstantiationPath _ NIL, currentWirePath: CoreFlat.WirePath _ NIL, logChanges: BOOL _ FALSE, path: ViewerClasses.Viewer _ NIL, currentWire: ViewerClasses.Viewer _ NIL]; TestHandle: TYPE = REF TestHandleRec; TestHandleRec: TYPE = RECORD[ h: Tester, proc: TestProc]; DisplayWireHandle: TYPE = REF DisplayWireHandleRec; DisplayWireHandleRec: TYPE = RECORD[ h: Tester, instantiationPath: CoreFlat.InstantiationPath, wire: Core.Wire, wireSize: NAT]; MakeStandardViewer: PUBLIC PROC [name: ROPE _ NIL, cellType: Core.CellType, testButtons: LIST OF TestButton, displayWires: DisplayWires _ NIL, flatten: BOOL _ FALSE, cutSet: ROPE _ NIL, historySize: NAT _ 0] RETURNS [simulation: Rosemary.Simulation] = { viewer: ViewerClasses.Viewer_ Containers.Create[[ name: name, iconic: FALSE, column: left, scrollable: FALSE ]]; height: CARDINAL _ entryVSpace; h: Tester _ NEW[TesterRec]; h.cellType _ cellType; h.testPort _ Ports.CreatePort[cellType.public, TRUE]; h.intermediatePort _ Ports.CreatePort[cellType.public, TRUE]; simulation _ h.simulation _ IF flatten THEN Rosemary.InstantiateInstances[cellType, h.intermediatePort, cutSet, historySize] ELSE Rosemary.InstantiateCellType[cellType, h.intermediatePort, historySize]; IF historySize>0 THEN { h.historySize _ historySize; h.testVectorBuffer _ NEW[Rosemary.PortSequenceRec[historySize]]; FOR b: NAT IN [0..historySize) DO h.testVectorBuffer[b] _ Ports.CreatePort[cellType.public, TRUE]; ENDLOOP; }; [] _ Buttons.Create[info: [name: "Start Test", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: StartTest]; h.runState _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[1], y: height-borderOffset, title: "Run State:", textViewerWidth: 2*pointsPerInch].textViewer; ViewerTools.InhibitUserEdits[h.runState]; ViewerTools.SetContents[h.runState, "Idle"]; IF historySize>0 THEN h.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: h, proc: Interrupt]; h.evalsSinceStart _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[1], y: height-borderOffset, title: "Evals Since Start:", textViewerWidth: 1*pointsPerInch].textViewer; ViewerTools.InhibitUserEdits[h.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: h, 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: h, proc: Proceed]; h.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: h, 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: h, 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: h, proc: SingleEval]; height _ height + entryHeight + entryVSpace; [] _ Buttons.Create[info: [name: "Log", wx: ColumnStart[0], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: h, proc: LogChanges]; height _ height + entryHeight + entryVSpace; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; IF displayWires#NIL THEN { Column: TYPE = NAT [0..2); ColumnStart: ARRAY Column OF NAT = [entryVSpace, 3*pointsPerInch+pointsPerInch/4+entryVSpace]; column: Column _ 0; FOR dws: DisplayWires _ displayWires, dws.rest UNTIL dws=NIL DO root: Core.Wire; rec: CoreClasses.RecordCellType; nameList: LIST OF ROPE; dw: DisplayWireHandle; IF dws.first.instantiationPath=NIL THEN rec _ NARROW[CoreFlat.Recordify[h.cellType].data] ELSE rec _ NARROW[dws.first.instantiationPath.first.type.data]; root _ rec.internal; nameList _ CoreOps.GetFullWireNames[root, dws.first.wire]; dw _ NEW[DisplayWireHandleRec _ [h, dws.first.instantiationPath, dws.first.wire, CoreOps.WireBits[dws.first.wire]]]; h.displayWires _ CONS[ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[column], y: height-borderOffset, title: IF nameList=NIL THEN NIL ELSE nameList.first, textViewerWidth: pointsPerInch, clientdata: dw], h.displayWires]; 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; }; 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 TestButton _ testButtons, tbs.rest UNTIL tbs=NIL DO testHandle: TestHandle _ NEW[TestHandleRec _ [h, tbs.first.proc]]; this: Buttons.Button _ Buttons.Create[info: [name: tbs.first.name, wx: ColumnStart[column], wy: height, ww: 0, wh: entryHeight, parent: viewer, border: TRUE], clientData: testHandle, proc: TestButtonProc]; h.testButtonList _ CONS[this, h.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; }; h.currentTestProc _ testButtons.first.proc; h.path _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[0], y: height-borderOffset, title: "Instantiation Path:", textViewerWidth: 4*pointsPerInch].textViewer; ViewerTools.InhibitUserEdits[h.path]; height _ height + entryHeight + entryVSpace; h.currentWire _ ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[0], y: height-borderOffset, title: "Current Wire:", textViewerWidth: 4*pointsPerInch].textViewer; ViewerTools.InhibitUserEdits[h.currentWire]; height _ height + entryHeight + entryVSpace; Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]]; height _ height + entryVSpace; { rep: ReadEvalPrint.Handle; [h.tsin, h.tsout] _ ViewerIO.CreateViewerStreams[name: "Rosemary Script", viewer:ViewerOps.CreateViewer[flavor: $TypeScript, info:[parent: viewer, wy: height+2, ww: 7*pointsPerInch, wh: 56 * entryHeight, scrollable: TRUE, border: FALSE]]]; rep _ ReadEvalPrint.CreateStreamEvaluator[clientProc: ExploreDesign, prompt: "%l> %l", in: h.tsin, out: h.tsout, topLevel: TRUE]; rep.clientData _ h; ReadEvalPrint.MainLoop[h: rep, properties: NIL]; height _ height + 10 * entryHeight; height _ height + entryHeight + entryVSpace/2; }; ViewerOps.SetOpenHeight[viewer, height]; ViewerOps.PaintViewer[viewer, all]; }; LogChanges: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; IF (h.logChanges _ ~h.logChanges) THEN { Buttons.SetDisplayStyle[NARROW[parent], $WhiteOnBlack]; } ELSE Buttons.SetDisplayStyle[NARROW[parent], $BlackOnWhite]; }; TestButtonProc: Buttons.ButtonProc = { t: TestHandle _ NARROW[clientData]; h: Tester _ t.h; 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 _ t.proc; }; AbortSignal: SIGNAL = CODE; StartTest: Buttons.ButtonProc = { h: Tester _ NARROW[clientData]; IF NOT AlreadyStarted[h] THEN DoStartTest[h]; }; DoStartTest: PROC [h: Tester] = { Eval: PROC = { UpdateWire: Rosemary.UpdateProc = { path: CoreFlat.PackedPath; coreWire: Core.Wire; IF h.abort THEN SIGNAL AbortSignal; IF NOT h.logChanges THEN RETURN; UpdateDisplay[h]; [path, coreWire] _ Rosemary.GetWirePath[wire]; < "L", X => "X", H => "H", ENDCASE => ERROR]];>> }; DO inBuf: BOOL _ h.displayedStatePoint#h.currentStatePoint AND h.validStates>0; testPort: Ports.Port _ IF inBuf THEN h.testVectorBuffer[NextBuf[h, h.displayedStatePoint]] ELSE h.testPort; Ports.CopyPortValue[from: testPort, to: h.intermediatePort]; Rosemary.Settle[h.simulation, UpdateWire]; IF h.logChanges THEN IO.PutRope[h.tsout, "\n\n"]; UpdateESSC[h, h.evalSinceStartCount+1]; 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.simulation, h.currentStatePoint]; Ports.CopyPortValue[from: h.testPort, to: h.testVectorBuffer[h.currentStatePoint]]; }; Ports.CheckPortValue[root: h.cellType.public, truth: testPort, question: h.intermediatePort ! Ports.CheckError => UpdateDisplay[h]]; 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; }; UpdateESSC[h, 0]; h.validStates _ 0; SetEvalUntil[h: h, interrupt: FALSE, abort: FALSE]; ViewerTools.SetContents[h.runState, "Running"]; h.currentTestProc[h.cellType, h.testPort, Eval ! 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]; 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.tsout, "No next state"] ELSE { h.displayedStatePoint _ NextBuf[h, h.displayedStatePoint]; Rosemary.RestoreState[h.simulation, h.displayedStatePoint]; UpdateESSC[h, h.evalSinceStartCount+1]; UpdateDisplay[h]; }; }; }; 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.tsout, "No previous state, not enough evals since history trigger"]; ndsp=h.currentStatePoint => IO.PutRope[h.tsout, "No previous state, buffer depth exceeded"]; ENDCASE => { h.displayedStatePoint _ ndsp; Rosemary.RestoreState[h.simulation, h.displayedStatePoint]; UpdateESSC[h, h.evalSinceStartCount-1]; UpdateDisplay[h]; }; }; }; 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]; 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; }; UpdateDisplay: PROC [h: Tester] = { FOR dwvs: LIST OF ChoiceButtons.PromptDataRef _ h.displayWires, dwvs.rest UNTIL dwvs=NIL DO dw: DisplayWireHandle _ NARROW[dwvs.first.clientdata]; new: ROPE; value: Ports.LevelSequence _ Rosemary.WireValue[h.simulation, dw.instantiationPath, dw.wire]; new _ Ports.LevelSequenceToRope[value, dw.wireSize]; 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]]; }; ExploreDesign: ReadEvalPrint.ClientProc = { uh: Tester _ NARROW[h.clientData]; [uh.currentInstancePath, uh.currentWirePath] _ CoreFlat.NewPath[uh.cellType, command, uh.currentInstancePath, uh.currentWirePath ! CoreFlat.PathError => {result _ msg; GOTO Done}]; IF uh.currentWirePath#NIL THEN result _ Ports.LevelSequenceToRope[Rosemary.WireValue[uh.simulation, uh.currentInstancePath, uh.currentWirePath.first], 0, 16]; <> <> EXITS Done => NULL; }; DisplayPortLeafWires: PUBLIC PROC [rootWire: Core.Wire, instantiationPath: CoreFlat.InstantiationPath _ NIL] RETURNS [displayWires: DisplayWires _ NIL] = { FindLeaves: CoreOps.EachWireProc = { IF Ports.WirePortType[wire]#composite THEN { subWires _ FALSE; dws _ CONS[[instantiationPath: instantiationPath, wire: wire], dws]; }; }; dws: DisplayWires _ NIL; IF CoreOps.VisitWire[rootWire, FindLeaves] THEN ERROR; FOR d: DisplayWires _ dws, d.rest UNTIL d=NIL DO displayWires _ CONS[d.first, displayWires]; ENDLOOP; }; WireValue: PUBLIC PROC [simulation: Rosemary.Simulation, name: ROPE, base: NAT _ 16] RETURNS [val: ROPE _ NIL] = { DiscoverWire: CoreOps.EachWireProc = { IF CoreOps.IsFullWireName[root, wire, name] THEN { namedWire _ wire; matchCount _ 1; quit _ TRUE; } ELSE IF Rope.Equal[name, CoreOps.GetShortWireName[wire]] THEN { namedWire _ wire; matchCount _ matchCount + 1; }; }; namedWire: Core.Wire _ NIL; root: Core.Wire _ simulation.coreCellType.public; matchCount: NAT _ 0; [] _ CoreOps.VisitWire[root, DiscoverWire]; IF matchCount=1 THEN val _ Ports.LevelSequenceToRope[Rosemary.WireValue[simulation, NIL, namedWire], 0, base]; }; END.