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: 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,
bitBucket: Ports.LevelSequence ← NIL,
testButtonList: LIST OF Buttons.Button,
currentTestProc: TestProc,
tsin: IO.STREAM ← NIL,
tsout: IO.STREAM ← NIL];
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:
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;
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: 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;
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:
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 {
container: Ports.LevelSequence ← NEW[Ports.LevelSequenceRec[ CoreOps.WireBits[namedWire]]];
Rosemary.GetWireValue[simulation, NIL, namedWire, container];
val ← Ports.LevelSequenceToRope[container, container.size, base];
};
};
END.