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: BOOLFALSE,
waiting: BOOLFALSE,
abort: BOOLFALSE,
interrupt: BOOLFALSE,
singleEval: BOOLFALSE,
testButtonList: LIST OF Buttons.Button,
currentTestProc: ROPENIL,
logChanges: BOOLFALSE,
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: ROPENIL, 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: ROPENIL, displayWires: CoreFlat.FlatWires ← NIL, flatten: BOOLFALSE, cutSets: LIST OF 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.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: NATIF 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: BOOLFALSE;
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: ROPENIL ] = {
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.STREAMIO.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.