FILE: DprintImpl.mesa
Last edited by Ousterhout, January 24, 1984 1:59 pm
Christian LeCocq December 30, 1986 1:56:42 pm PST
DIRECTORY
Build,
DPrint,
FS,
Globals,
IO,
Model,
Parse,
Printout,
Rope,
StagePool;
DPrintImpl: CEDAR PROGRAM
IMPORTS
Build,
FS,
Globals,
IO,
Model,
Parse,
Printout,
Rope,
StagePool
EXPORTS DPrint =
BEGIN
OPEN DPrint;
The following arrays and values are used to record delay paths. In the arrays, lower indices correspond to shorter delays.
NumPaths: PUBLIC ARRAY listType OF INT ← [5,5,5];
Threshold: PUBLIC ARRAY listType OF REAL ← [0.0, 0.0, 0.0];
Paths: ARRAY listType OF ARRAY[0..MaxPaths) OF Globals.Stage;
The following values are used to record statistical information.
numRecords: ARRAY listType OF INT ← [0,0,0];
numDups: INT ← 0;
PrintEdgeSpeeds: PUBLIC BOOLEANFALSE;
CopyPath: PROC[src: Globals.Stage] RETURNS [copy: Globals.Stage] =
This local procedure simply makes a copy of a path (a chain of stages) and returns a pointer to the copy.
BEGIN
prev, cur: Globals.Stage;
copy ← NIL;
WHILE src # NIL DO
prev ← StagePool.New[];
prev^ ← src^;
IF copy = NIL THEN copy ← prev
ELSE cur.prev ← prev;
cur ← prev;
src ← src.prev;
ENDLOOP;
RETURN [copy];
END;
DeletePath: PROC[stage: Globals.Stage] =
Returns to the stage pool all of the stages linked to stage.
BEGIN
next: Globals.Stage;
WHILE stage # NIL DO
next ← stage.prev;
StagePool.Free[stage];
stage ← next;
ENDLOOP;
END;
Record: PUBLIC PROC[stage: Globals.Stage, list: listType] =
BEGIN
i, max: INT;
cur: Globals.Stage;
bot, top: REAL;
done: BOOLEANFALSE;
IF stage.time < Threshold[list] THEN RETURN;
numRecords[list] ← numRecords[list] + 1;
max ← NumPaths[list];
See if this path's delay duplicates a delay already in the array.
bot ← stage.time * .999;
top ← stage.time * 1.001;
FOR i IN [0..NumPaths[list]) DO
cur ← Paths[list][i];
IF cur = NIL THEN LOOP;
IF cur.time > top THEN EXIT;
IF (cur.time >= bot) AND (cur.rise = stage.rise) THEN
BEGIN
numDups ← numDups + 1;
RETURN;
END;
ENDLOOP;
Find the slot in which to store the new path.
DeletePath[Paths[list][0]];
FOR i IN [1..max) DO
cur ← Paths[list][i];
IF cur = NIL THEN LOOP;
IF stage.time < cur.time THEN
BEGIN
Paths[list][i-1] ← CopyPath[stage];
done ← TRUE;
EXIT;
END;
Paths[list][i-1] ← cur;
ENDLOOP;
IF NOT done THEN Paths[list][max-1] ← CopyPath[stage];
Find the new smallest times in the arrays for use as a threshold.
IF Paths[list][0] = NIL THEN Threshold[list] ← 0
ELSE Threshold[list] ← 1.001 * Paths[list][0].time;
END;
PrintStage: PUBLIC PROC[stream: IO.STREAM, stage: Globals.Stage, globalVars: Globals.GlobalVars] =
BEGIN
first: BOOLEANTRUE;
i: INT;
direction, format: Rope.ROPE;
IF stage = NIL THEN
BEGIN
IO.PutRope[stream, "No such critical path.\n"];
RETURN;
END;
WHILE stage # NIL DO
IF stage.rise THEN direction ← "high" ELSE direction ← "low";
IF first THEN
BEGIN
format ← "Node %s is driven %s at %.2fns";
first ← FALSE;
END
ELSE format ← " after\n %s is driven %s at %.2fns";
IO.PutF[stream, format, IO.rope[Build.RopeFromNode[stage.piece2Node[stage.piece2Size-1], globalVars]], IO.rope[direction], IO.real[stage.time]];
IF PrintEdgeSpeeds THEN
IO.PutF[stream, " with edge speed %.3f ns/volt", IO.real[stage.edgeSpeed]];
FOR i DECREASING IN [0..stage.piece2Size-2] DO
IO.PutF[stream, "\n ...through fet at (%.1f, %.1f) to %s", IO.real[stage.piece2Fet[i].x/Printout.Units], IO.real[stage.piece2Fet[i].y/Printout.Units], IO.rope[Build.RopeFromNode[stage.piece2Node[i], globalVars]]];
ENDLOOP;
FOR i IN [0..stage.piece1Size) DO
IO.PutF[stream, "\n ...through fet at (%.1f, %.1f) to %s", IO.real[stage.piece1Fet[i].x/Printout.Units], IO.real[stage.piece1Fet[i].y/Printout.Units], IO.rope[Build.RopeFromNode[stage.piece1Node[i], globalVars]]];
ENDLOOP;
stage ← stage.prev;
ENDLOOP;
IO.PutRope[stream, "\n"];
END;
CriticalCmd: PUBLIC Globals.CmdProc =
BEGIN
list: listType ← any;
ok: BOOLEAN;
index: INT ← 1;
fileName: Rope.ROPENIL;
stream: IO.STREAM;
msg: Rope.ROPENIL;
Scan off all of the arguments.
WHILE args # NIL DO
IF (Rope.Fetch[args.rope, 0] >= '0)
AND (Rope.Fetch[args.rope, 0] <= '9) THEN
BEGIN
IF Rope.Fetch[args.rope, Rope.Length[args.rope] - 1] = 'm THEN
BEGIN
list ← memory;
args.rope ← Rope.Substr[args.rope, 0, Rope.Length[args.rope] - 1];
END
ELSE IF Rope.Fetch[args.rope, Rope.Length[args.rope] - 1] = 'w THEN
BEGIN
list ← watched;
args.rope ← Rope.Substr[args.rope, 0, Rope.Length[args.rope] - 1];
END
ELSE list ← any;
[ok, index] ← Parse.Int[args];
IF index < 1 OR NOT ok THEN
BEGIN
IO.PutF[Globals.StdOut, "Bad critical path number: %s\n", IO.rope[args.rope]];
RETURN;
END;
END
ELSE IF Rope.Fetch[args.rope, 0] # '- THEN fileName ← args.rope
ELSE IO.PutF[Globals.StdOut, "Unknown %s switch ignored.\n", IO.rope[args.rope]];
args ← args.next;
ENDLOOP;
Make sure the index is within the range of what we've recorded.
IF index > NumPaths[list] THEN
BEGIN
IO.PutF[Globals.StdOut, "Sorry, but there are only %d paths.", IO.int[NumPaths[list]]];
IO.PutF[Globals.StdOut, " Using index %d.\n", IO.int[NumPaths[list]]];
index ← 0;
END
ELSE index ← NumPaths[list] - index;
Open the file, if neccessary, then call the procedure to print out stuff.
IF fileName # NIL THEN
BEGIN
stream ← FS.StreamOpen[fileName, $create
! FS.Error => IF error.group # bug
THEN {msg ← error.explanation; CONTINUE}];
IF msg # NIL THEN
BEGIN
IO.PutF[Globals.StdOut, "Couldn't open %s: %s\n", IO.rope[fileName], IO.rope[msg]];
RETURN;
END;
END
ELSE stream ← Globals.StdOut;
PrintStage[stream, Paths[list][index], globalVars];
IF fileName # NIL THEN IO.Close[stream];
END;
Clear: PUBLIC PROC[] =
BEGIN
FOR i:INT IN [0..MaxPaths) DO
Paths[memory][i] ← NIL;
Paths[any][i] ← NIL;
Paths[watched][i] ← NIL;
ENDLOOP;
Threshold[memory] ← 0.0;
Threshold[any] ← 0.0;
Threshold[watched] ← 0.0;
END;
Stats: PUBLIC PROC[] =
BEGIN
IO.PutF[Globals.StdOut, "Number of calls to record delays: %d.\n", IO.int[numRecords[any]]];
IO.PutF[Globals.StdOut, "Number of calls to record memory delays: %d.\n", IO.int[numRecords[memory]]];
IO.PutF[Globals.StdOut, "Number of calls to record watched delays: %d.\n", IO.int[numRecords[watched]]];
IO.PutF[Globals.StdOut, "Number of dups eliminated in recording: %d.\n", IO.int[numDups]];
END;
RecomputeCmd: PUBLIC Globals.CmdProc =
BEGIN
FOR i:INT IN [0..NumPaths[any]) DO
Recompute[Paths[any][i], globalVars];
ENDLOOP;
FOR i:INT IN [0..NumPaths[memory]) DO
Recompute[Paths[memory][i], globalVars];
ENDLOOP;
FOR i:INT IN [0..NumPaths[watched]) DO
Recompute[Paths[watched][i], globalVars];
ENDLOOP;
END;
Recompute: PROC[stage: Globals.Stage, globalVars: Globals.GlobalVars] =
BEGIN
IF (stage = NIL) OR (stage.prev = NIL) THEN RETURN;
Recompute[stage.prev, globalVars];
Model.Delay[stage, globalVars];
END;
DumpFet: PROC[stream: IO.STREAM, fet: Globals.Fet] =
This is a local utility procedure that prints information about a transistor in ASCII form.
BEGIN
IO.PutF[stream, " fet %d 0 %f %f %f %f\n", IO.int[fet.type], IO.real[fet.area], IO.real[fet.aspect]];
END;
DumpNode: PROC[stream: IO.STREAM, node: Globals.Node, globalVars: Globals.GlobalVars] =
This is a local utility procedure that prints information about a node in ASCII form.
BEGIN
IO.PutF[stream, " node 0 %s %f %f %f %f\n", IO.rope[Build.RopeFromNode[node, globalVars]], IO.real[node.cap], IO.real[node.res], IO.real[node.hiTime], IO.real[node.loTime]];
END;
DumpStage: PROC[stream: IO.STREAM, stage: Globals.Stage, globalVars: Globals.GlobalVars] =
This is a recursive local utility procedure that prints information about a path consisting of a chain of stages. The stages are printed in increasing order of delay time.
BEGIN
IF stage.prev # NIL THEN DumpStage[stream, stage.prev, globalVars];
IO.PutF[stream, " stage %d %d ", IO.int[stage.piece1Size], IO.int[stage.piece2Size]];
IF stage.rise THEN IO.PutRope[stream, "1 "]
ELSE IO.PutRope[stream, "0 "];
IO.PutF[stream, "%f %f\n", IO.real[stage.time], IO.real[stage.edgeSpeed]];
FOR i:INT IN [0..stage.piece1Size) DO
DumpFet[stream, stage.piece1Fet[i]];
DumpNode[stream, stage.piece1Node[i], globalVars];
ENDLOOP;
FOR i:INT IN [0..stage.piece2Size) DO
IF i # stage.piece2Size-1 THEN
DumpFet[stream, stage.piece2Fet[i]];
DumpNode[stream, stage.piece2Node[i], globalVars];
ENDLOOP;
END;
DumpCmd: PUBLIC Globals.CmdProc =
BEGIN
stream: IO.STREAM;
msg: Rope.ROPENIL;
IF args = NIL THEN stream ← Globals.StdOut
ELSE stream ← FS.StreamOpen[args.rope, $create
! FS.Error => IF error.group # bug
THEN {msg ← error.explanation; CONTINUE}];
IF msg # NIL THEN
BEGIN
IO.PutF[Globals.StdOut, "Couldn't open %s for writing: %s.\n", IO.rope[args.rope], IO.rope[msg]];
RETURN;
END;
FOR i: INT IN [0..NumPaths[any]) DO
IF Paths[any][i] = NIL THEN LOOP;
IO.PutF[stream, "Any %d\n", IO.int[i]];
DumpStage[stream, Paths[any][i], globalVars];
ENDLOOP;
FOR i: INT IN [0..NumPaths[memory]) DO
IF Paths[memory][i] = NIL THEN LOOP;
IO.PutF[stream, "Memory %d\n", IO.int[i]];
DumpStage[stream, Paths[memory][i], globalVars];
ENDLOOP;
FOR i: INT IN [0..NumPaths[watched]) DO
IF Paths[watched][i] = NIL THEN LOOP;
IO.PutF[stream, "Watch %d\n", IO.int[i]];
DumpStage[stream, Paths[watched][i], globalVars];
ENDLOOP;
IO.Close[stream];
END;
UndumpFet: PROC[stream: IO.STREAM] RETURNS [fet: Globals.Fet] =
This is a local utility procedure that reads in the description of a transistor from an ASCII file, as dumped by dumpFet.
BEGIN
fet ← NEW[Globals.FetRec ← [NIL, NIL, NIL, 0.0, 0.0, 0.0, 0.0, 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NIL]];
[] ← IO.GetTokenRope[stream, Parse.WhiteSpace];
fet.type ← IO.GetInt[stream];
[] ← IO.GetTokenRope[stream, Parse.WhiteSpace];
fet.area ← IO.GetReal[stream];
fet.aspect ← IO.GetReal[stream];
RETURN [fet];
END;
UndumpNode: PROC[stream: IO.STREAM] RETURNS [node: Globals.Node] =
This is a local routine that reads in the description of a node, as dumped by dumpNode, and returns a new node.
BEGIN
node ← NEW[Globals.NodeRec ← [NIL, 0, 0, 0, 0, NIL, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE]];
[] ← IO.GetTokenRope[stream, Parse.WhiteSpace];
[] ← IO.GetTokenRope[stream, Parse.WhiteSpace];
[token: node.name] ← IO.GetTokenRope[stream, Parse.WhiteSpace];
node.cap ← IO.GetReal[stream];
node.res ← IO.GetReal[stream];
node.hiTime ← IO.GetReal[stream];
node.loTime ← IO.GetReal[stream];
RETURN [node];
END;
UndumpStage: PROC[stream: IO.STREAM] RETURNS [stage: Globals.Stage] =
Local procedure to read in ASCII description of stage.
BEGIN
i: INT;
stage ← NEW[Globals.StageRec];
stage.piece1Size ← IO.GetInt[stream];
stage.piece2Size ← IO.GetInt[stream];
i ← IO.GetInt[stream];
IF i # 0 THEN stage.rise ← TRUE
ELSE stage.rise ← FALSE;
stage.time ← IO.GetReal[stream];
stage.edgeSpeed ← IO.GetReal[stream];
stage.prev ← NIL;
FOR i IN [0..stage.piece1Size) DO
stage.piece1Fet[i] ← UndumpFet[stream];
stage.piece1Node[i] ← UndumpNode[stream];
ENDLOOP;
FOR i IN [0..stage.piece2Size) DO
IF i = stage.piece2Size-1 THEN stage.piece2Fet[i] ← NIL
ELSE stage.piece2Fet[i] ← UndumpFet[stream];
stage.piece2Node[i] ← UndumpNode[stream];
ENDLOOP;
RETURN [stage];
END;
UndumpCmd: PUBLIC Globals.CmdProc =
BEGIN
rope: Rope.ROPE;
index: INT;
prev, next: Globals.Stage;
stream: IO.STREAM;
msg: Rope.ROPENIL;
list: listType;
{ENABLE ANY => CONTINUE;
IF args = NIL THEN
BEGIN
IO.PutRope[Globals.StdOut, "No file name given.\n"];
RETURN;
END;
stream ← FS.StreamOpen[args.rope
! FS.Error => IF error.group # bug
THEN {msg ← error.explanation; CONTINUE}];
IF msg # NIL THEN
BEGIN
IO.PutF[Globals.StdOut, "Couldn't open %s for reading: %s.\n",
IO.rope[args.rope], IO.rope[msg]];
RETURN;
END;
FOR i: INT IN [0..MaxPaths) DO
Paths[any][i] ← NIL;
Paths[memory][i] ← NIL;
Paths[watched][i] ← NIL;
ENDLOOP;
[token: rope] ← IO.GetTokenRope[stream, Parse.WhiteSpace];
WHILE TRUE DO
index ← IO.GetInt[stream];
IF Rope.Equal[rope, "Memory"] THEN list ← memory
ELSE IF Rope.Equal[rope, "Watch"] THEN list ← watched
ELSE list ← any;
prev ← NIL;
WHILE TRUE DO
[token: rope] ← IO.GetTokenRope[stream, Parse.WhiteSpace];
IF NOT Rope.Equal[rope, "stage"] THEN EXIT;
next ← UndumpStage[stream];
next.prev ← prev;
Paths[list][index] ← next;
prev ← next;
ENDLOOP;
ENDLOOP;
};
IO.Close[stream];
END;
END.