SpiceOutputViewImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Christian LeCocq March 25, 1987 10:01:45 am PST
Description of what this module does.
DIRECTORY
Commander,
Core,
CoreFlat,
CoreOps,
FS,
HashTable,
IO,
PlotGraph,
Rope,
SpiceOps,
TerminalIO;
SpiceOutputViewImpl: CEDAR PROGRAM
IMPORTS Commander, CoreFlat, CoreOps, FS, HashTable, IO, PlotGraph, Rope, SpiceOps, TerminalIO
EXPORTS SpiceOps
~ BEGIN
ConvData: TYPE ~ SpiceOps.ConvData;
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ PlotGraph.VEC;
VecList: TYPE ~ LIST OF VEC;
DisplayList: TYPE = LIST OF DisplayListRec;
DisplayListRec: TYPE = RECORD [
graph: PlotGraph.Graph,
list: VecList
];
matchingPattern: ROPE = "0**** ";
transientAnalysis: ROPE = "TRANSIENT ANALYSIS";
inputListing: ROPE ← "INPUT LISTING";
patternLength: INT = Rope.Length[matchingPattern];
CR: ROPE = "\n";
leftPar: ROPE = "(";
rigthPar: ROPE = ")";
window: PlotGraph.Rectangle ← [0.0, 0.0, 100.0, 5.0];
Public
DisplaySpiceListing: PUBLIC PROC [listingFile: Rope.ROPE] ~ {
plot: PlotGraph.Plot;
convData: ConvData;
msg: Rope.ROPE;
stream: IO.STREAM;
never put a catch phrase in an initialization !
stream ← FS.StreamOpen[listingFile ! FS.Error => {
msg ← error.explanation;
CONTINUE
}];
IF msg # NIL THEN {
TerminalIO.PutRopes["Couldn't open ", listingFile, ": "];
TerminalIO.PutRopes[msg, ".\n"];
RETURN;
};
IF stream=NIL THEN RETURN;
SearchListingFile[stream, inputListing];
convData ← TryToRemember[stream];
SearchListingFile[stream, transientAnalysis];
plot ← PlotGraph.CreatePlot[IF convData#NIL THEN CoreOps.GetCellTypeName[convData.rootCell] ELSE listingFile];
ReadFirstLine[stream, plot];
IF convData#NIL THEN ChangeNames[plot, convData.rootCell, convData.invTable];
FillPlot[stream, plot];
PlotGraph.RefreshPlot[plot: plot, within: window, eraseFirst: TRUE]
};
ChangeNames: PROC [plot: PlotGraph.Plot, cellType: Core.CellType, nameTable: HashTable.Table] ~ {
FOR iAxis: PlotGraph.AxisList ← plot.axis, iAxis.rest UNTIL iAxis=NIL DO
wire: CoreFlat.FlatWire ← NARROW[HashTable.Fetch[nameTable, iAxis.first.name].value];
IF wire#NIL THEN iAxis.first.name ← CoreFlat.WirePathRope[cellType, wire^];
ENDLOOP;
};
TryToRemember: PROC [stream: IO.STREAM] RETURNS [convData: ConvData] ~ {
id: ROPE;
i0, l: INT ← 0;
FOR iLine: NAT IN [0..60] UNTIL l>i0 DO -- until we find a good line in the first page
id ← IO.GetLineRope[stream]; -- should be "* 12345: myCell..."
i0 ← Rope.Index[id, 0, "*"]+2;
l ← Rope.Index[id, i0, ":"]-i0;
ENDLOOP;
IF l>i0 THEN id ← Rope.Substr[id, i0, l]; -- id="12345"
convData ← NARROW[HashTable.Fetch[SpiceOps.pendingSimulations, id].value];
};
SpiceDisplayCmd: Commander.CommandProc ~ {
PROC [cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
fName: ROPE;
fName ← IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc ! IO.EndOfStream => CONTINUE].token;
IF Rope.Find[fName, "."]=-1 THEN fName ← Rope.Concat[fName, ".spo"];
DisplaySpiceListing[fName];
};
I/Os
SearchListingFile: PUBLIC PROC [stream: IO.STREAM, partName: ROPE] ~ {
Description of the procedure.
DO
l: ROPE IO.GetLineRope[stream];
IF Rope.Equal[Rope.Substr[l, 0, patternLength], matchingPattern] THEN
IF Rope.Find[l, partName]> 0 THEN EXIT;
ENDLOOP;
[] ← IO.GetLineRope[stream]; -- blank line
[] ← IO.GetLineRope[stream]; -- *****... line
[] ← IO.GetLineRope[stream]; -- blank line
[] ← IO.GetLineRope[stream]; -- blank line
[] ← IO.GetLineRope[stream]; -- blank line
for transient analysis the next line is : "
TIME V(1) V(2)"...
which is where the data begins.
};
SpaceInsideLine: IO.BreakProc ~ {
PROC [char: CHAR] RETURNS [CharClass]
IF (char = IO.CR) OR (char = '() OR (char = ')) THEN RETURN [break];
IF (char = IO.TAB) OR (char = IO.LF) OR (char = IO.SP) THEN RETURN [sepr];
RETURN[other];
};
ReadFirstLine: PUBLIC PROC [stream: IO.STREAM, plot: PlotGraph.Plot] ~ {
Description of the procedure.
displayList: DisplayList;
nLines: INT ← 0;
base, height: REAL;
token: ROPEIO.GetTokenRope[stream, SpaceInsideLine].token; -- gets "TIME"
token ← IO.GetTokenRope[stream, SpaceInsideLine].token; -- 1st output
UNTIL Rope.Equal[token, CR] DO
name: ROPE;
graph: PlotGraph.Graph ← NEW[PlotGraph.GraphRec ← [class: gClass]];
SELECT TRUE FROM
Rope.Equal[token, "V"] => {base ← 0.0; height ← 5.0};
Rope.Equal[token, "I"] => {base ← 0.005; height ← 0.01; name ← "Current in "};
ENDCASE => ERROR;
IF ~Rope.Equal[IO.GetTokenRope[stream, SpaceInsideLine].token, leftPar] THEN ERROR;
name ← Rope.Cat[name, IO.GetTokenRope[stream, SpaceInsideLine].token, " "];
the extra space is needed in order to recognize the wire name - see SpiceInputGenImpl.NextInstanceId which generates rope numbers.
IF ~Rope.Equal[IO.GetTokenRope[stream, SpaceInsideLine].token, rigthPar] THEN ERROR;
nLines ← nLines+1;
plot.axis ← CONS[NEW[PlotGraph.AxisRec ← [
graphs: LIST[graph],
bounds: [0.0, base, 100.0, height],
name: name,
style: analog,
axisData: [axisData, axisData]
]], plot.axis];
displayList ← CONS[[graph: graph], displayList];
token ← IO.GetTokenRope[stream, SpaceInsideLine].token;
ENDLOOP;
plot.data ← displayList;
};
MyGetReal: PROC [stream: IO.STREAM] RETURNS [r: REAL] ~ {
Tries to cope with 0 being written as 0. e+00, which is 2 tokens for IO.
r ← IO.GetReal[stream];
IF IO.PeekChar[stream]#'. THEN RETURN;
[] ← IO.GetTokenRope[stream, SpaceInsideLine];
IF r=0.0 THEN IF ~Rope.Equal[IO.GetTokenRope[stream, SpaceInsideLine].token, "e+00"] THEN ERROR;
};
ReadValues: PUBLIC PROC [stream: IO.STREAM, nVal: INT] RETURNS [vecList: VecList] ~ {
Description of the procedure.
time: REAL ← MyGetReal[stream]*1.e9;
THROUGH [1..nVal] DO
vecList ← CONS[[time, MyGetReal[stream]], vecList];
ENDLOOP;
IF ~Rope.Equal[IO.GetTokenRope[stream, SpaceInsideLine].token, CR] THEN ERROR;
};
FillPlot: PROC [stream: IO.STREAM, plot: PlotGraph.Plot] ~ {
nVal: INT ← 0;
displayList: DisplayList ← NARROW[plot.data];
[] ← IO.GetTokenRope[stream, SpaceInsideLine];
[] ← IO.GetTokenRope[stream, SpaceInsideLine]; -- skip 2 lines
plot.lowerBounds ← [1.0e24, 1.0e24];
plot.upperBounds ← [-1.0e24, -1.0e24];
FOR iAxis: PlotGraph.AxisList ← plot.axis, iAxis.rest UNTIL iAxis=NIL DO
nVal ← nVal+1;
ENDLOOP;
DO
vecList: VecList;
IF IO.PeekChar[stream]#IO.SP THEN RETURN;
vecList ← ReadValues[stream, nVal];
FOR iDisplayList: DisplayList ← displayList, iDisplayList.rest UNTIL iDisplayList=NIL DO
plot.lowerBounds.x ← MIN[plot.lowerBounds.x, vecList.first.x];
plot.lowerBounds.y ← MIN[plot.lowerBounds.y, vecList.first.y];
plot.upperBounds.x ← MAX[plot.upperBounds.x, vecList.first.x];
plot.upperBounds.y ← MAX[plot.upperBounds.y, vecList.first.y];
iDisplayList.first.list ← CONS[vecList.first, iDisplayList.first.list];
vecList ← vecList.rest;
ENDLOOP;
ENDLOOP;
};
Display
Enum: PROC [plot: PlotGraph.Plot, graph: PlotGraph.Graph, bounds: PlotGraph.Rectangle, eachPoint: PlotGraph.PointProc, data: REF ANYNIL] RETURNS [invalidEnumeration: BOOLFALSE] ~ {
quit: BOOLEANFALSE;
displayList: DisplayList ← NARROW[plot.data];
FOR iDisplayList: DisplayList ← displayList, iDisplayList.rest UNTIL iDisplayList=NIL OR quit DO
IF iDisplayList.first.graph=graph THEN
FOR iVecList: VecList ← iDisplayList.first.list, iVecList.rest UNTIL iVecList=NIL DO
quit ← eachPoint[iVecList.first.x, iVecList.first.y, data]
ENDLOOP;
ENDLOOP;
};
gClass: PlotGraph.GraphClass ← NEW[PlotGraph.GraphClassRec ← [
insert: NIL,
delete: NIL,
enumerate: Enum
]];
axisData: PlotGraph.AxisData ← [1.0, TRUE, FALSE];
Commander.Register[key: "SpiceOps", proc: SpiceDisplayCmd, doc: "Display files sent by Spice"];
END.