DIRECTORY Check, Globals, HashTable, IO, Model, Printout, Rope; CheckImpl: CEDAR PROGRAM IMPORTS Globals, HashTable, IO, Printout EXPORTS Check = BEGIN OPEN Check; msgLimit: INT _ 100; normalLow: REAL _ 3.8; normalHigh: REAL _ 4.2; passLow: REAL _ 7.8; passHigh: REAL _ 8.2; cmdTable: ARRAY[0..3] OF Rope.ROPE _ [ "normalhigh", "normallow", "passhigh", "passlow" ]; msg1, msg2, msg3, msg4, msg5, msg6, skipped: INT; IntRec: TYPE = RECORD[val: INT]; CheckCmd: PUBLIC Globals.CmdProc ~ { CheckProc: HashTable.EachPairAction = BEGIN p: Globals.Pointer; f: Globals.Fet; node: Globals.Node _ NARROW[value]; drives, driven: BOOLEAN _ FALSE; IF node.firstPointer = NIL THEN BEGIN msg1 _ msg1 + 1; IF msg1 <= msgLimit THEN IO.PutF[Globals.StdOut, "Node %s doesn't connect to any transistors.\n", IO.rope[Printout.NodeRope[node, globalVars]]] ELSE skipped _ skipped + 1; IF msg1 = msgLimit THEN IO.PutRope[Globals.StdOut, " No more of these messages will be printed.\n"]; RETURN; END; FOR p _ node.firstPointer, p.next UNTIL p = NIL DO f _ p.fet; IF f.source = node THEN BEGIN IF f.flowFromDrain THEN driven _ TRUE; IF f.flowFromSource THEN drives _ TRUE; END; IF f.drain = node THEN BEGIN IF f.flowFromSource THEN driven _ TRUE; IF f.flowFromDrain THEN drives _ TRUE; END; IF f.gate = node THEN BEGIN drives _ TRUE; IF NOT (f.flowFromSource OR f.flowFromDrain) THEN BEGIN msg4 _ msg4 + 1; IF msg4 <= msgLimit THEN BEGIN IO.PutF[Globals.StdOut, "No flow through FET: %s\n", IO.rope[Printout.FetRope[f, globalVars]]]; IF msg4 = 1 THEN IO.PutRope[Globals.StdOut, " Maybe you haven't marked all the inputs and outputs?\n"]; END ELSE skipped _ skipped + 1; IF msg4 = msgLimit THEN IO.PutRope[Globals.StdOut, " No more of these messages will be printed.\n"]; END; IF f.flowFromSource AND f.flowFromDrain AND f.firstFlow = NIL THEN BEGIN msg5 _ msg5 + 1; IF msg5 <= msgLimit THEN BEGIN IO.PutF[Globals.StdOut, "Bidirectional FET: %s\n", IO.rope[Printout.FetRope[f, globalVars]]]; IF msg5 = 1 THEN IO.PutRope[Globals.StdOut, " Maybe you should label flow?\n"]; END ELSE skipped _ skipped + 1; IF msg5 = msgLimit THEN IO.PutRope[Globals.StdOut, " No more of these messages will be printed.\n"]; END; IF (f.drain = globalVars.VddNode AND f.source = globalVars.GroundNode) OR (f.source = globalVars.VddNode AND f.drain = globalVars.GroundNode) THEN BEGIN msg6 _ msg6 + 1; IF msg6 <= msgLimit THEN IO.PutF[Globals.StdOut, "FET between Vdd and Ground: %s\n", IO.rope[Printout.FetRope[f, globalVars]]] ELSE skipped _ skipped + 1; IF msg6 = msgLimit THEN IO.PutRope[Globals.StdOut, " No more of these messages will be printed.\n"]; END; END; ENDLOOP; IF NOT (node.output OR drives) THEN BEGIN msg3 _ msg3 + 1; IF msg3 <= msgLimit THEN BEGIN IO.PutF[Globals.StdOut, "Node doesn't drive anything: %s.\n", IO.rope[Printout.NodeRope[node, globalVars]]]; IF msg3 = 1 THEN IO.PutRope[Globals.StdOut, " Maybe you haven't marked all the inputs and outputs?\n"]; END ELSE skipped _ skipped + 1; IF msg3 = msgLimit THEN IO.PutRope[Globals.StdOut, " No more of these messages will be printed.\n"]; END; IF NOT (node.input OR driven) THEN BEGIN msg2 _ msg2 + 1; IF msg2 <= msgLimit THEN BEGIN IO.PutF[Globals.StdOut, "Node isn't driven: %s.\n", IO.rope[Printout.NodeRope[node, globalVars]]]; IF msg2 = 1 THEN IO.PutRope[Globals.StdOut, " Maybe you haven't marked all the inputs and outputs?\n"]; END ELSE skipped _ skipped + 1; IF msg2 = msgLimit THEN IO.PutRope[Globals.StdOut, " No more of these messages will be printed.\n"]; END; END; msg1 _ 0; msg2 _ 0; msg3 _ 0; msg4 _ 0; msg5 _ 0; msg6 _ 0; skipped _ 0; [] _ HashTable.Pairs[globalVars.nodeTable, CheckProc] }; END. ÜFILE: CheckImpl.mesa Last edited by Ousterhout, August 23, 1983 1:03 pm Christian LeCocq December 19, 1986 11:42:16 am PST Flow, Hash, Parse, Flow, Hash, Parse, Limit of how many message of any one type to print: Limits for valid transistor ratios: Info used to suppress printing of many identical ratio errors: ratioLimit: PUBLIC INT _ 5; ratioTable: Hash.Table; ratioDups: INT; totalRatioErrors: INT; totalRatioLimit: PUBLIC INT _ 1000; Info shared between CheckCmd and checkProc: 1. Make sure the node has transistors attached. Go through all the transistors attached to the node. See if the node is driven and if it drives anything, and also check out the transistors on the way (only check a transistor when its gate is seen, to avoid duplication). 4. If transistor can't flow at all, error. 5. If transistor is bidirectional but has no flow indicator, issue a warning. 6. If transistor connects Vdd and Ground, error. 3 & 4. Make sure that the node can drive and be driven. Hash.Enumerate[table: globalVars.nodeTable, pattern: "*", proc: checkProc, errorStream: Globals.StdOut]; RatioCmd: PUBLIC Globals.CmdProc = BEGIN RatioProc: HashTable.EachPairAction = BEGIN p: Globals.Pointer; node: Globals.Node _ NARROW[value]; IF (node = globalVars.VddNode) OR (node = globalVars.GroundNode) THEN RETURN; FOR p _ node.firstPointer, p.next UNTIL p = NIL DO IF p.fet.type = Model.fetNLoad THEN EXIT; ENDLOOP; IF p = NIL THEN RETURN; checkRatio[origin: node, current: node, loadSize: p.fet.aspect, curSize: 0.0, gotPass: FALSE, globalVars: globalVars]; END; index: INT; val: REAL; ok: BOOLEAN; ratioTable _ Hash.NewTable[]; ratioDups _ 0; totalRatioErrors _ 0; normalLow _ 3.8; normalHigh _ 4.2; passLow _ 7.8; passHigh _ 8.2; Read in parameters, if there are any. WHILE args # NIL DO TRUSTED {index _ Parse.Lookup[args.rope, DESCRIPTOR[cmdTable]]}; IF index < 0 THEN BEGIN IO.PutF[Globals.StdOut, "Bad limit %s: try normalhigh, normallow, ", IO.rope[args.rope]]; IO.PutRope[Globals.StdOut, "passhigh, or passlow.\n"]; args _ args.next; LOOP; END; args _ args.next; IF args = NIL THEN BEGIN IO.PutF[Globals.StdOut, "No value given for %s.\n", IO.rope[cmdTable[index]]]; EXIT; END; [ok, val] _ Parse.Real[args]; args _ args.next; IF NOT ok THEN BEGIN IO.PutF[Globals.StdOut, "Bad value given for %s.\n", IO.rope[cmdTable[index]]]; LOOP; END; SELECT index FROM =0 => normalHigh _ val; =1 => normalLow _ val; =2 => passHigh _ val; =3 => passLow _ val; ENDCASE; ENDLOOP; Process all of the nodes in the hash table. Hash.Enumerate[table: globalVars.nodeTable, pattern: "*", proc: ratioProc, errorStream: Globals.StdOut]; [] _ HashTable.Pairs[globalVars.nodeTable, RatioProc]; ratioTable _ NIL; IF totalRatioErrors > totalRatioLimit THEN IO.PutF[Globals.StdOut, "Ratio checking aborted after %d errors.\n", IO.int[totalRatioErrors]]; IF ratioDups > 0 THEN IO.PutF[Globals.StdOut, "%d duplicate ratio errors not printed.\n", IO.int[ratioDups]]; END; checkRatio: PROC[origin, current: Globals.Node, loadSize, curSize: REAL, gotPass: BOOLEAN, globalVars: Globals.GlobalVars] = This is a recursive procedure that does all of the real work in checking transistor ratios. It scans recursively through pulldowns and checks ratios whenever it reaches ground. Error messages are printed if ratio errors are found. BEGIN p, p2: Globals.Pointer; f: Globals.Fet; newSize, ratio: REAL; newPass: BOOLEAN; error: Rope.ROPE; count: REF IntRec; next: Globals.Node; h: Hash.Entry; Set a flag to avoid infinite recursion through circular structures. current.inPath _ TRUE; Skim through all of the transistors attached to the node. If the transistor connects to ground, check the ratio. Otherwise, call this routine recursively to check on the pother side. FOR p _ current.firstPointer, p.next UNTIL p = NIL DO IF totalRatioErrors > totalRatioLimit THEN BEGIN current.inPath _ FALSE; RETURN; END; f _ p.fet; Make sure that the transistor's source or drain connects to this node and that flow in this direction is OK. IF f.source = current THEN BEGIN next _ f.drain; IF NOT f.flowFromDrain THEN LOOP; END ELSE IF f.drain = current THEN BEGIN next _ f.source; IF NOT f.flowFromSource THEN LOOP; END ELSE LOOP; Ignore circular paths and paths to Vdd. IF next.inPath THEN LOOP; IF next = globalVars.VddNode THEN LOOP; IF f.firstFlow # NIL THEN IF NOT Flow.Lock[f, next] THEN LOOP; See if the gate of this transistor is load driven or pass transistor driven. Inputs are considered to be equal to load driven nodes. FOR p2 _ f.gate.firstPointer, p2.next UNTIL p2 = NIL DO IF (p2.fet.type = Model.fetNLoad) OR (p2.fet.type = Model.fetNSuper) THEN EXIT; ENDLOOP; IF (p2 = NIL) AND NOT f.gate.input THEN newPass _ TRUE ELSE newPass _ gotPass; Now check the ratio. newSize _ curSize + f.aspect; IF next = globalVars.GroundNode THEN BEGIN ratio _ loadSize/newSize; IF newPass THEN BEGIN IF (ratio >= passLow) AND (ratio <= passHigh) THEN BEGIN IF f.firstFlow # NIL THEN Flow.Unlock[f, next]; LOOP; END; END ELSE IF (ratio >= normalLow) AND (ratio <= normalHigh) THEN BEGIN IF f.firstFlow # NIL THEN Flow.Unlock[f, next]; LOOP; END; There's been an error. This piece of code eliminates extra messages: there can be no more than one message about a particular node, no more than a certain number of messages about a particular ratio, and no more than a certain total number of messages. IF origin.ratioError THEN BEGIN ratioDups _ ratioDups + 1; IF f.firstFlow # NIL THEN Flow.Unlock[f, next]; LOOP; END; origin.ratioError _ TRUE; totalRatioErrors _ totalRatioErrors + 1; error _ IO.PutFR["pullup = %.1f, pulldown = %.1f", IO.real[loadSize], IO.real[newSize]]; h _ Hash.Find[table: ratioTable, name: error]; IF h.clientData = NIL THEN h.clientData _ NEW[IntRec _ [0]]; count _ NARROW[h.clientData]; count.val _ count.val + 1; IF count.val > ratioLimit THEN ratioDups _ ratioDups + 1 ELSE BEGIN IO.PutF[Globals.StdOut, "Ratio error at node %s: %s\n", IO.rope[Printout.NodeRope[origin, globalVars]], IO.rope[error]]; IO.PutF[Globals.StdOut, " Last pulldown is at (%.1f, %.1f)\n", IO.real[f.x/Printout.Units], IO.real[f.y/Printout.Units]]; END; END ELSE checkRatio[origin: origin, current: next, loadSize: loadSize, curSize: newSize, gotPass: newPass, globalVars: globalVars]; IF f.firstFlow # NIL THEN Flow.Unlock[f, next]; ENDLOOP; current.inPath _ FALSE; END; Ê ˜Jšœ™šœ2™2Icode™2—J˜šÏk ˜ J˜J™J˜J™J˜ Jšœ˜J˜J™J˜ J˜—J˜JšÏn œœ˜š˜J™J˜J™J˜ Jšœ˜J™J˜—Jšœ˜Jš˜Jšœ˜ J˜Jšœ3™3J˜Jšœ œ˜J˜Jšœ#™#J˜Jšœ œ˜Jšœ œ˜Jšœ œ˜Jšœ œ˜J˜Jšœ>™>J˜Jšœ œœ™J™Jšœ œ™Jšœœ™Jšœœœ™#šœ œœœ˜$J˜J˜ J˜ J˜ J˜ J˜—J˜Jšœ+™+J˜Jšœ-œ˜1J˜Jšœœœœ˜ J˜J˜Jšžœœœ˜$˜šÏb œ˜%Jš˜Jšœ˜Jšœ˜Jšœœ˜#Jšœœœ˜ J˜Jšœ/™/J˜šœœ˜Jš˜J˜šœ˜JšœFœ+˜v—Jšœ˜šœ˜JšœM˜O—Jšœ˜Jšœ˜—J˜Jšœß™ßJ˜šœœœ˜2J˜ šœ˜Jš˜Jšœœ œ˜&Jšœœ œ˜'Jšœ˜—šœ˜Jš˜Jšœœ œ˜'Jšœœ œ˜&Jšœ˜—šœ˜Jš˜Jšœ œ˜J˜Jšœ*™*J˜šœœœ˜1Jš˜J˜šœ˜Jš˜Jšœ2œ(˜_Jšœ œW˜jJš˜—Jšœ˜JšœœM˜gJšœ˜J˜—Jšœ<™<šœ™J˜—šœœ˜'Jšœœ˜Jš˜J˜šœ˜Jš˜Jšœ0œ(˜]Jšœ œ?˜RJš˜—Jšœ˜JšœœM˜gJšœ˜—J˜Jšœ0™0J˜šœœ"˜FJšœ œ"˜KJš˜J˜Jšœœ9œ'˜~Jšœ˜JšœœM˜gJšœ˜—Jšœ˜—Jšœ˜J˜—šœ8™8J˜—šœœœ ˜#Jš˜J˜šœ˜Jš˜Jšœ;œ,˜lJšœ œW˜jJš˜—Jšœ˜JšœœM˜gJšœ˜—šœœ œ ˜"Jš˜J˜šœ˜Jš˜Jšœ1œ,˜bJšœ œW˜jJš˜—Jšœ˜JšœœM˜gJšœ˜—Jšœ˜—J˜ J˜ J˜ J˜ J˜ J˜ J˜ Jšœh™hJšœ5˜5Jšœ˜—J˜šžœœ™"Jš™šž œ™%Jš™Jšœ™šœœ™#J™—Jšœœ œœ™Mšœœœ™2Jšœœœ™)Jšœ™—Jšœœœœ™JšœWœ™vJšœ™J™—Jšœœ™ Jšœœ™ Jšœœ™ J™J™J™J™J™J™J™J™J™Jšœ%™%J™šœœ™Jšœ" œ ™@šœ ™Jš™JšœBœ™YJšœ4™6J™Jšœ™Jšœ™—J™šœœ™Jš™Jšœ1œ™NJšœ™Jšœ™—J™J™šœœ™Jš™Jšœ2œ™OJšœ™Jšœ™—šœ™J™J™J™J™Jšœ™Jšœ™—J™Jšœ+™+J™Jšœh™hJšœ6™6Jšœ œ™šœ$™*JšœBœ™_—šœ™JšœAœ™W—Jšœ™——J™J™šŸ œœ3œ œ#™|šœè™èJ™—Jš™Jšœ™Jšœ™Jšœœ™Jšœ œ™Jšœ œ™Jšœœ™Jšœ™™J™—šœC™CJ™—šœœ™J™—šœ¹™¹J™—šœ"œœ™5šœ$™*Jš™Jšœœ™Jšœ™Jšœ™—J™ ™Jšœl™l—™šœ™Jš™J™Jšœœœœ™!Jš™—šœœ™Jš™J™Jšœœœœ™"Jš™—Jšœœ™ —™Jšœ'™'——™Jšœ œœ™Jšœœœ™'šœœ™Jšœœœœ™$—™Jšœ…™…—™šœ#œœ™7šœ™!Jšœ!œœ™-—Jšœ™—Jš œœœœœ ™6Jšœ™—™Jšœ™—™J™šœ™$Jš™J™šœ ™Jš™šœœ™3Jš™Jšœœœ™/Jšœ™Jšœ™—Jš™—šœœœ™;Jš™Jšœœœ™/Jšœ™Jšœ™—™Jšœÿ™ÿ—™šœ™Jš™J™Jšœœœ™/Jšœ™Jšœ™—Jšœœ™J™(Jšœœ(œœ™XJ™.Jšœœœœ™