RosemaryUserImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Barth, March 25, 1986 10:56:22 am PST
Louis Monier January 17, 1986 5:30:28 pm PST
Last Edited by: Gasbarro January 23, 1986 11:45:55 am PST
Last Edited by: Neil Gunther February 27, 1986 11:29:46 am PST
DIRECTORY Buttons, ChoiceButtons, Containers, Convert, Core, CoreClasses, CoreOps, IO, Ports, Process, Rope, Rosemary, RosemaryUser, Rules, ViewerClasses, ViewerIO, ViewerOps, ViewerTools;
RosemaryUserImpl: CEDAR MONITOR
IMPORTS Buttons, ChoiceButtons, Containers, Convert, CoreOps, IO, Ports, Process, Rope, Rosemary, Rules, ViewerIO, ViewerOps, ViewerTools
EXPORTS RosemaryUser
= BEGIN OPEN RosemaryUser;
debug: BOOLFALSE;
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: BOOLFALSE,
waiting: BOOLFALSE,
abort: BOOLFALSE,
interrupt: BOOLFALSE,
singleEval: BOOLFALSE,
displayWires: LIST OF ChoiceButtons.PromptDataRef ← NIL,
bitBucket: Ports.LevelSequence ← NIL,
testButtonList: LIST OF Buttons.Button,
currentTestProc: TestProc,
tsin: IO.STREAMNIL,
tsout: IO.STREAMNIL];
TestHandle: TYPE = REF TestHandleRec;
TestHandleRec: TYPE = RECORD[
h: Tester,
proc: TestProc];
DisplayWireHandle: TYPE = REF DisplayWireHandleRec;
DisplayWireHandleRec: TYPE = RECORD[
h: Tester,
instantiationPath: Rosemary.InstantiationPath,
wire: Core.Wire,
wireSize: NAT];
MakeStandardViewer: PUBLIC PROC [name: ROPENIL, cellType: Core.CellType, testButtons: LIST OF TestButton, displayWires: DisplayWires ← NIL, flatten: BOOLFALSE, cutSet: ROPENIL, 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;
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;
maxWireSize: NAT ← 0;
FOR dws: DisplayWires ← displayWires, dws.rest UNTIL dws=NIL DO
root: Core.Wire;
rec: CoreClasses.RecordCellType;
last: Rosemary.InstantiationPath ← dws.first.instantiationPath;
nameList: LIST OF ROPE;
dw: DisplayWireHandle;
IF last=NIL THEN {
ct: Core.CellType ← Rosemary.Recordify[h.cellType];
rec ← NARROW[ct.data];
}
ELSE {
UNTIL last.rest=NIL DO last ← last.rest ENDLOOP;
rec ← NARROW[last.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;
maxWireSize ← MAX[maxWireSize, dw.wireSize];
ENDLOOP;
IF column>0 THEN height ← height + entryHeight + entryVSpace;
h.bitBucket ← NEW[Ports.LevelSequenceRec[maxWireSize]];
Containers.ChildXBound[viewer, Rules.Create[[parent: viewer, wy: height, ww: viewer.cw, wh: 2]]];
height ← height + entryVSpace;
};
IF testButtons.rest#NIL THEN {
column: Column ← 0;
FOR tbs: LIST OF TestButton ← testButtons, tbs.rest UNTIL tbs=NIL DO
testHandle: TestHandle ← NEW[TestHandleRec ← [h, tbs.first.proc]];
h.testButtonList ← CONS[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];
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[h.testButtonList.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.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]]];
height ← height + 10 * entryHeight;
height ← height + entryHeight + entryVSpace/2;
ViewerOps.SetOpenHeight[viewer, height];
ViewerOps.PaintViewer[viewer, all];
};
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 = {
UpdateDisplay[h];
IF wire.currentValue=NIL THEN IO.PutF[h.tsout, "%g←%g ", IO.rope[CoreOps.GetShortWireName[wire.wire]], IO.rope[SELECT wire.wireLevel FROM L => "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, IF debug THEN UpdateWire ELSE NIL];
IF debug 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;
check new state same as recorded state;
}
ELSE EXIT;
ENDLOOP;
};
h.evalSinceStartCount ← 0;
h.validStates ← 0;
ViewerTools.SetContents[h.evalsSinceStart, "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: NATIF 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: BOOLFALSE;
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;
Rosemary.GetWireValue[h.simulation, dw.instantiationPath, dw.wire, h.bitBucket];
new ← Ports.LevelSequenceToRope[h.bitBucket, 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: NAT] = {
h.evalSinceStartCount ← h.evalSinceStartCount + 1;
ViewerTools.SetContents[h.evalsSinceStart, Convert.RopeFromCard[from: h.evalSinceStartCount, showRadix: FALSE]];
};
DisplayPortLeafWires: PUBLIC PROC [wire: Core.Wire, instantiationPath: Rosemary.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[wire, 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: ROPENIL] = {
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 {
container: Ports.LevelSequence ← NEW[Ports.LevelSequenceRec[ CoreOps.WireBits[namedWire]]];
Rosemary.GetWireValue[simulation, NIL, namedWire, container];
val ← Ports.LevelSequenceToRope[container, container.size, base];
};
};
END.