-- FILE: PrintoutImpl.mesa -- Last edited by Ousterhout, August 30, 1983 1:40 pm DIRECTORY Globals, Hash, IO, Model, Parse, Printout, Rope; PrintoutImpl: CEDAR PROGRAM IMPORTS Globals, Hash, IO, Model, Rope, Parse EXPORTS Printout = BEGIN OPEN Printout, Globals; Units: PUBLIC REAL ← 2.0; -- The following variables are used to communicate between command-level -- routines and enumeration action routines. dupTable: Hash.Table; threshold: REAL; nDups: INT; FetRope: PUBLIC PROC[fet: Fet] RETURNS [rope: Rope.ROPE] = BEGIN rope ← IO.PutFR["g=%s, s=%s, d=%s, loc=%f,%f", IO.rope[fet.gate.name], IO.rope[fet.source.name], IO.rope[fet.drain.name], IO.real[fet.x/Units], IO.real[fet.y/Units]]; RETURN [rope]; END; NodeRope: PUBLIC PROC[node: Node] RETURNS [rope: Rope.ROPE] = BEGIN x,y: REAL; p: Pointer; terminal: Rope.ROPE; f: Fet; -- The only tricky thing about this routine is that nodes -- don't contain (x,y) locations. I've found that the best -- way to identify a node is with a transistor gate. So, this -- procedure checks the first few transistors attached to the -- node to see if there's a gate available for use as a reference -- point. p ← node.firstPointer; IF p = NIL THEN BEGIN RETURN [node.name]; END ELSE BEGIN FOR i:INT IN [0..10) DO f ← p.fet; IF node = f.gate THEN EXIT; IF p.next = NIL THEN EXIT; p ← p.next; ENDLOOP; x ← f.x/Units; y ← f.y/Units; IF node = f.gate THEN terminal ← "gate" ELSE IF node = f.drain THEN terminal ← "drain" ELSE IF node = f.source THEN terminal ← "source" ELSE BEGIN IO.PutF[StdOut, "Crystal bug: node %s doesn't connect right!\n", IO.rope[node.name]]; RETURN ["??"]; END; rope ← IO.PutFR["%s (see %s at %f,%f)", IO.rope[node.name], IO.rope[terminal], IO.real[x], IO.real[y]]; RETURN [rope]; END; END; PrintCap: PUBLIC CmdProc = BEGIN ParseOK: BOOLEAN; dupTable ← Hash.NewTable[]; nDups ← 0; threshold ← 0.0; -- Read off switches, if there are any. WHILE args # NIL DO IF Rope.Fetch[args.rope, 0] # '- THEN EXIT; IF Rope.Length[args.rope] # 2 THEN BEGIN IO.PutF[StdOut, "Bad switch: %s\n", IO.rope[args.rope]]; args ← args.next; LOOP; END; SELECT Rope.Fetch[args.rope, 1] FROM 't => BEGIN [ParseOK, threshold] ← Parse.Real[args.next]; IF ParseOK THEN args ← args.next ELSE IO.PutF[StdOut, "No threshold value given, using 0.\n"]; END; ENDCASE => IO.PutF[StdOut, "Bad switch: %s\n", IO.rope[args.rope]]; args ← args.next; ENDLOOP; -- Read off nodes. For each node, look it up in the node table and print -- out its capacitance if it's greater than threshold. nDups ← 0; IF args = NIL THEN Hash.Enumerate[table: NodeTable, pattern: "*", proc: capProc, errorStream: StdOut] ELSE WHILE args # NIL DO Hash.Enumerate[table: NodeTable, pattern: args.rope, proc: capProc, errorStream: StdOut]; args ← args.next; ENDLOOP; IF nDups > 0 THEN IO.PutF[StdOut, "%d duplicates not printed.\n", IO.int[nDups]]; END; capProc: Hash.EnumProc = BEGIN valRope: Rope.ROPE; node: Node; node ← NARROW[entry.clientData]; IF node = NIL THEN RETURN; IF node.cap >= threshold THEN BEGIN valRope ← IO.PutFR["%.3f", IO.real[node.cap]]; entry ← Hash.Find[dupTable, valRope]; IF (entry.clientData # $Duplicate) OR DupsOK THEN BEGIN entry.clientData ← $Duplicate; IO.PutF[StdOut, "%s pf capacitance at %s.\n", IO.rope[valRope], IO.rope[NodeRope[node]]]; END ELSE nDups ← nDups + 1; END; END; PrintRes: PUBLIC CmdProc = BEGIN ParseOK: BOOLEAN; dupTable ← Hash.NewTable[]; nDups ← 0; threshold ← 0.0; -- Read off switches, if there are any. WHILE args # NIL DO IF Rope.Fetch[args.rope, 0] # '- THEN EXIT; IF Rope.Length[args.rope] # 2 THEN BEGIN IO.PutF[StdOut, "Bad switch: %s\n", IO.rope[args.rope]]; args ← args.next; LOOP; END; SELECT Rope.Fetch[args.rope, 1] FROM 't => BEGIN [ParseOK, threshold] ← Parse.Real[args.next]; IF ParseOK THEN args ← args.next ELSE IO.PutF[StdOut, "No threshold value given, using 0.\n"]; END; ENDCASE => IO.PutF[StdOut, "Bad switch: %s\n", IO.rope[args.rope]]; args ← args.next; ENDLOOP; -- Read off nodes. For each node, look it up in the node table and print -- out its resistance if it's greater than threshold. nDups ← 0; IF args = NIL THEN Hash.Enumerate[table: NodeTable, pattern: "*", proc: resProc, errorStream: StdOut] ELSE WHILE args # NIL DO Hash.Enumerate[table: NodeTable, pattern: args.rope, proc: resProc, errorStream: StdOut]; args ← args.next; ENDLOOP; IF nDups > 0 THEN IO.PutF[StdOut, "%d duplicates not printed.\n", IO.int[nDups]]; END; resProc: Hash.EnumProc = BEGIN valRope: Rope.ROPE; node: Node; node ← NARROW[entry.clientData]; IF node = NIL THEN RETURN; IF node.res >= threshold THEN BEGIN valRope ← IO.PutFR["%.1f", IO.real[node.res]]; entry ← Hash.Find[dupTable, valRope]; IF (entry.clientData # $Duplicate) OR DupsOK THEN BEGIN entry.clientData ← $Duplicate; IO.PutF[StdOut, "%s ohms resistance at %s.\n", IO.rope[valRope], IO.rope[NodeRope[node]]]; END ELSE nDups ← nDups + 1; END; END; PrintFets: PUBLIC CmdProc = BEGIN IF args = NIL THEN Hash.Enumerate[table: NodeTable, pattern: "*", proc: fetProc, errorStream: StdOut] ELSE WHILE args # NIL DO Hash.Enumerate[table: NodeTable, pattern: args.rope, proc: fetProc, errorStream: StdOut]; args ← args.next; ENDLOOP; END; fetProc: Hash.EnumProc = BEGIN node: Node; pointer: Pointer; fet: Fet; fp: FlowPtr; node ← NARROW[entry.clientData]; FOR pointer ← node.firstPointer, pointer.next UNTIL pointer = NIL DO fet ← pointer.fet; IF fet.gate = node THEN BEGIN IO.PutF[StdOut, "%s, type=%s, aspect=%.3f, area=%.3f\n", IO.rope[FetRope[fet]], IO.rope[Model.TypeTable[fet.type].name], IO.real[fet.aspect], IO.real[fet.area/(Units*Units)]]; IO.PutRope[StdOut, " Flags:"]; IF fet.flowFromSource THEN IO.PutRope[StdOut, " fromSource"]; IF fet.flowFromDrain THEN IO.PutRope[StdOut, " fromDrain"]; IF fet.forcedOn THEN IO.PutRope[StdOut, " forcedOn"]; IF fet.forcedOff THEN IO.PutRope[StdOut, " forcedOff"]; IF fet.on0 THEN IO.PutRope[StdOut, " on0"]; IF fet.on1 THEN IO.PutRope[StdOut, " on1"]; IF fet.onAlways THEN IO.PutRope[StdOut, " onAlways"]; IF fet.noSourceInfo THEN IO.PutRope[StdOut, " noSourceInfo"]; IF fet.noDrainInfo THEN IO.PutRope[StdOut, " noDrainInfo"]; IF fet.firstFlow # NIL THEN IO.PutRope[StdOut, " Flow:"]; FOR fp ← fet.firstFlow, fp.next UNTIL fp = NIL DO IF fp.source THEN IO.PutF[StdOut, " s=%s", IO.rope[fp.flow.name]]; IF fp.drain THEN IO.PutF[StdOut, " d=%s", IO.rope[fp.flow.name]]; ENDLOOP; IO.PutRope[StdOut, "\n"]; END; ENDLOOP; END; PrintNodes: PUBLIC CmdProc = BEGIN IF args = NIL THEN Hash.Enumerate[table: NodeTable, pattern: "*", proc: nodeProc, errorStream: StdOut] ELSE WHILE args # NIL DO Hash.Enumerate[table: NodeTable, pattern: args.rope, proc: nodeProc, errorStream: StdOut]; args ← args.next; ENDLOOP; END; nodeProc: Hash.EnumProc = BEGIN node: Node ← NARROW[entry.clientData]; IO.PutF[StdOut, "%s:", IO.rope[node.name]]; IF node.always0 THEN IO.PutRope[StdOut, " always 0"]; IF node.always1 THEN IO.PutRope[StdOut, " always 1"]; IF node.input THEN IO.PutRope[StdOut, " input"]; IF node.output THEN IO.PutRope[StdOut, " output"]; IF node.precharged THEN IO.PutRope[StdOut, " precharged"]; IF node.bus THEN IO.PutRope[StdOut, " bus"]; IF node.dynamic THEN IO.PutRope[StdOut, " dynamic"]; IF node.inPath THEN IO.PutRope[StdOut, " inPath"]; IF node.ratioError THEN IO.PutRope[StdOut, " ratioError"]; IF node.watched THEN IO.PutRope[StdOut, " watched"]; IO.PutF[StdOut, "\n capacitance = %.5f, resistance = %.1f,", IO.real[node.cap], IO.real[node.res]]; IO.PutF[StdOut, "\n rise time = %.1f, fall time = %.1f\n", IO.real[node.hiTime], IO.real[node.loTime]]; END; END.