RosemaryUserImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Barth, June 13, 1986 2:26:02 pm PDT
Louis Monier June 11, 1986 12:31:44 pm PDT
DIRECTORY Buttons, ChoiceButtons, Containers, Convert, Core, CoreClasses, CoreFlat, CoreOps, HashTable, IO, Ports, Process, Rope, ReadEvalPrint, Rosemary, RosemaryUser, Rules, ViewerClasses, ViewerIO, ViewerOps, ViewerTools;
RosemaryUserImpl:
CEDAR
MONITOR
IMPORTS Buttons, ChoiceButtons, Containers, Convert, CoreClasses, CoreFlat, CoreOps, HashTable, IO, Ports, Process, Rope, ReadEvalPrint, 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];
Tester: TYPE = REF TesterRec;
TesterRec:
TYPE =
RECORD [
testPort: Ports.Port ← NIL,
intermediatePort: Ports.Port ← 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,
testButtonList: LIST OF Buttons.Button,
currentTestProc: ROPE ← NIL,
logChanges: BOOL ← FALSE,
display: RoseDisplay ← NIL];
DisplayWireHandle: TYPE = REF DisplayWireHandleRec;
DisplayWireHandleRec:
TYPE =
RECORD[
packedPath: CoreFlat.PackedPath,
wire: Core.Wire,
wireSize: NAT];
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]
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, 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, flatten:
BOOL ←
FALSE, cutSets:
LIST
OF
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.display ← NEW[RoseDisplayRec];
h.display.cellType ← cellType;
h.testPort ← Ports.CreatePort[cellType.public, TRUE];
h.intermediatePort ← Ports.CreatePort[cellType.public, TRUE];
simulation ← h.display.simulation ← IF flatten THEN Rosemary.InstantiateInstances[cellType, h.intermediatePort, cutSets, 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 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: h, 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;
MakeDisplayAndBrowse[displayWires, height, h.display, viewer, name];
};
MakeDisplayAndBrowse:
PROC [displayWires: CoreFlat.FlatWires, height:
CARDINAL, handle: RoseDisplay, viewer: ViewerClasses.Viewer, name:
ROPE] = {
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: CoreFlat.FlatWires ← displayWires, dws.rest
UNTIL dws=
NIL
DO
handle.displayWires ← CONS[ChoiceButtons.BuildTextPrompt[viewer: viewer, x: ColumnStart[column], y: height-borderOffset, title: CoreFlat.WirePathRope[handle.cellType, dws.first^], textViewerWidth: 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];
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]]];
height ← height + entryVSpace;
{
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];
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];
};
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;
StartTest: Buttons.ButtonProc = {
h: Tester ← NARROW[clientData];
IF NOT AlreadyStarted[h] THEN DoStartTest[h];
};
DoStartTest:
PROC [h: Tester] = {
Eval:
PROC = {
UpdateWire: Rosemary.UpdateProc = {
coreWire: CoreFlat.FlatWireRec;
IF h.abort THEN SIGNAL AbortSignal;
IF NOT h.logChanges THEN RETURN;
UpdateDisplay[h.display];
coreWire ← Rosemary.GetWirePath[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 h.testPort;
Ports.CopyPortValue[from: testPort, to: h.intermediatePort];
Rosemary.Settle[h.display.simulation, UpdateWire];
IF h.logChanges THEN IO.PutRope[h.display.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.display.simulation, h.currentStatePoint];
Ports.CopyPortValue[from: h.testPort, 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;
check new state same as recorded state;
}
ELSE EXIT;
ENDLOOP;
};
wireKey: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec];
testProc: TestProc ← NARROW[HashTable.Fetch[table: testProcTable, key: h.currentTestProc].value, REF TestProc]^;
IF testProc=NIL THEN ERROR;
UpdateESSC[h, 0];
h.validStates ← 0;
SetEvalUntil[h: h, interrupt: FALSE, abort: FALSE];
ViewerTools.SetContents[h.runState, "Running"];
testProc[h.display.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.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];
};
};
};
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 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 = {
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, "v"] => result ← Rosemary.WireValueRope[handle.simulation, wireName];
Rope.Equal[operation, "c"] => {
resultStream: IO.STREAM ← IO.ROS[];
path: CoreFlat.PackedPath ← CoreFlat.FindPath[handle.cellType, fullPathName];
CoreOps.PrintCellType[CoreFlat.GetCellType[handle.cellType, path], resultStream];
result ← IO.RopeFromROS[resultStream];
};
Rope.Equal[operation, "d"] => result ← DescribeWire[goryDetails: TRUE, handle: handle, wireName: wireName];
Rope.Equal[operation, "t"] => result ← DescribeWire[goryDetails: FALSE, handle: handle, wireName: wireName];
ENDCASE => IF NOT Rope.IsEmpty[operation] THEN result ← Rope.Cat["No such command: ", operation, ", commands are (v)alue, (t)race, (c)elltype, and (d)rivers"];
EXITS Done => NULL;
};
DescribeWire:
PROC [goryDetails:
BOOL, handle: RoseDisplay, wireName:
ROPE]
RETURNS [result:
ROPE] = {
wireKey: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec];
wireRoot: CoreFlat.WireRoot;
roseWire: Rosemary.RoseWire;
cellType: Core.CellType;
bindings: HashTable.Table;
bind: CoreFlat.WireBind;
[wireKey^, wireRoot] ← CoreFlat.FindWire[handle.cellType, wireName];
[bindings, cellType] ← CoreFlat.BoundCellType[handle.cellType, wireKey.path];
bind ← NARROW[HashTable.Fetch[table: bindings, key: wireKey.wire].value];
wireKey.path ← bind.path;
wireKey.wire ← bind.wire;
roseWire ← Rosemary.RawRoseWire[handle.simulation, wireKey];
result ← Rope.Cat[CoreFlat.WirePathRope[handle.cellType, wireKey^, wireRoot], " = ", Rosemary.WireValueRope[handle.simulation, wireName], "\n"];
result ← Rope.Cat[result, IF roseWire=NIL THEN "This 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;
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 CoreOps.ToBasic[root].public ELSE roseInstance.instance.instance.type.public, port: IF roseInstance=NIL THEN simulation.testPort ELSE roseInstance.publicPort, eachWirePortPair: FindPortWire] THEN ERROR;
coreWire.path ← IF roseInstance=NIL THEN CoreFlat.NullPath ELSE CoreFlat.AddInstance[roseInstance.instance.path, roseInstance.instance.instance, CoreFlat.GetCellType[root, roseInstance.instance.path]];
result ← Rope.Cat[result, CoreFlat.WirePathRope[root, coreWire, public]];
IF goryDetails
THEN {
result ← Rope.Cat[result, " - d: ", Ports.driveNames[field.portBinding.currentDrive]];
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;
};
Wire Display
DisplayInstancePortLeafWires:
PUBLIC
PROC [instance: CoreFlat.FlatInstanceRec]
RETURNS [displayWires: CoreFlat.FlatWires] = {
displayWires ← DisplayPortLeafWires[instance.path, instance.instance.type.public];
};
DisplayCellTypePortLeafWires:
PUBLIC
PROC [cellType: Core.CellType]
RETURNS [displayWires: CoreFlat.FlatWires] = {
displayWires ← DisplayPortLeafWires[CoreFlat.NullPath, cellType.public];
};
DisplayPortLeafWires:
PUBLIC
PROC [path: CoreFlat.PackedPath, wire: Core.Wire]
RETURNS [displayWires: CoreFlat.FlatWires] = {
FindLeaves: CoreOps.EachWireProc = {
IF Ports.WirePortType[wire]#composite
THEN {
subWires ← FALSE;
displayWires ← CONS[NEW[CoreFlat.FlatWireRec ← [path: path, wire: wire]], displayWires];
};
};
IF CoreOps.VisitWire[wire, FindLeaves] THEN ERROR;
};
END.