<> <> <> <> <> DIRECTORY Build, Delay, DPrint, Flow, Globals, <> IO, Model, Parse, Printout, Rope, StagePool; DelayImpl: CEDAR PROGRAM IMPORTS Build, DPrint, Globals, Flow, <> IO, Model, Parse, Printout, <> StagePool EXPORTS Delay = BEGIN OPEN Delay; <> delayCount: INT _ 0; DelayLimit: PUBLIC INT _ 200000; <> stageOverflowCount: INT _ 0; stageOverflowLimit: INT _ 10; <> Print: PUBLIC BOOLEAN _ FALSE; PrintAll: PUBLIC BOOLEAN _ FALSE; <> BusThreshold: PUBLIC REAL _ 2.0; <> chaseVGCalls: INT _ 0; chaseGatesCalls: INT _ 0; chaseLoadsCalls: INT _ 0; propagateCalls: INT _ 0; feedbacks: INT _ 0; <> hiTime, loTime: REAL; chaseVG: PROC[stage: Globals.Stage, globalVars: Globals.GlobalVars] RETURNS [BOOLEAN] = <= 1 entries in piece1, plus piece2Node[0] must be initialized with the correct value for the first call to chaseGates. The return value is TRUE if the procedure terminated normally, and FALSE if it gave up because too many nodes had been searched. This procedure continues searching for sources of Vdd or Ground, calling itself recursively until all possible paths have been tried. For each source of Vdd or Ground, chaseGates gets called.>> BEGIN p: Globals.Pointer; f: Globals.Fet; node, other: Globals.Node; size: INT; result: BOOLEAN; { chaseVGCalls _ chaseVGCalls + 1; <> size _ stage.piece1Size; node _ stage.piece1Node[size-1]; IF node.inPath THEN RETURN [TRUE]; node.inPath _ TRUE; IF Globals.Stop^ OR (delayCount >= DelayLimit) THEN GOTO giveUp; <> IF node.bus OR node.input OR node.cap >= BusThreshold THEN BEGIN IF NOT node.always0 THEN BEGIN stage.piece2Size _ 1; stage.rise _ TRUE; IF NOT chaseGates[stage, globalVars] THEN GOTO giveUp; END; IF NOT node.always1 THEN BEGIN stage.piece2Size _ 1; stage.rise _ FALSE; IF NOT chaseGates[stage, globalVars] THEN GOTO giveUp; END; GOTO done; END; <> FOR p _ node.firstPointer, p.next UNTIL p = NIL DO f _ p.fet; <> IF f.source = node THEN BEGIN other _ f.drain; IF NOT f.flowFromDrain THEN LOOP; END ELSE IF f.drain = node THEN BEGIN other _ f.source; IF NOT f.flowFromSource THEN LOOP; END ELSE LOOP; IF f.forcedOff THEN LOOP; IF f.firstFlow # NIL THEN IF NOT Flow.Lock[f, other] THEN LOOP; <> <> IF size >= Globals.pieceLimit THEN BEGIN stageOverflowCount _ stageOverflowCount + 1; IF f.firstFlow # NIL THEN Flow.Unlock[f, other]; IF stageOverflowCount > stageOverflowLimit THEN GOTO done; IO.PutF[Globals.StdOut, "More than %d transistors in series, see %s.\n", IO.int[Globals.pieceLimit], IO.rope[Printout.NodeRope[node, globalVars]]]; IF stageOverflowCount = stageOverflowLimit THEN IO.PutRope[Globals.StdOut, "No more messages of this kind will be printed....\n"]; GOTO done; END; <> stage.piece1Fet[size] _ f; stage.piece1Node[size] _ other; stage.piece1Size _ size + 1; IF other = globalVars.VddNode THEN BEGIN stage.piece2Size _ 1; stage.rise _ TRUE; result _ chaseGates[stage, globalVars]; END ELSE IF other = globalVars.GroundNode THEN BEGIN stage.piece2Size _ 1; stage.rise _ FALSE; result _ chaseGates[stage, globalVars]; END ELSE result _ chaseVG[stage, globalVars]; IF f.firstFlow # NIL THEN Flow.Unlock[f, other]; IF NOT result THEN GOTO giveUp; ENDLOOP; GOTO done; EXITS giveUp => BEGIN IO.PutF[Globals.StdOut, "ChaseVG giving up at %s.\n", IO.rope[Printout.NodeRope[node, globalVars]]]; node.inPath _ FALSE; RETURN [FALSE]; END; done => BEGIN node.inPath _ FALSE; RETURN [TRUE]; END } END; chaseGates: PROC[stage: Globals.Stage, globalVars: Globals.GlobalVars] RETURNS [BOOLEAN] = <> BEGIN p: Globals.Pointer; f: Globals.Fet; node, other: Globals.Node; size: INT; result: BOOLEAN; { chaseGatesCalls _ chaseGatesCalls + 1; <> size _ stage.piece2Size; stage.piece2Fet[size-1] _ NIL; -- expected by the modelling routines. node _ stage.piece2Node[size-1]; IF node.always0 OR node.always1 THEN RETURN [TRUE]; IF node.inPath THEN BEGIN feedbacks _ feedbacks + 1; IF stage.prev.time >= DPrint.Threshold[memory] THEN DPrint.Record[stage.prev, memory]; RETURN [TRUE]; END; <> IF node.precharged AND stage.rise THEN RETURN [TRUE]; node.inPath _ TRUE; IF Globals.Stop^ OR (delayCount >= DelayLimit) THEN GOTO giveUp; <> IF (stage.piece1Size # 0) OR (size # 1) THEN BEGIN IF node.input AND NOT node.output THEN GOTO done; Model.Delay[stage, globalVars]; IF stage.rise THEN BEGIN IF stage.time > node.hiTime THEN BEGIN node.hiTime _ stage.time; Propagate[stage, globalVars]; END; END ELSE IF stage.time > node.loTime THEN BEGIN node.loTime _ stage.time; Propagate[stage, globalVars]; END; IF Globals.Stop^ OR (delayCount > DelayLimit) THEN GOTO giveUp; <> IF node.bus OR node.cap >= BusThreshold THEN GOTO done; END; <> FOR p _ node.firstPointer, p.next UNTIL p = NIL DO f _ p.fet; IF f.forcedOff THEN LOOP; IF f.source = node THEN BEGIN other _ f.drain; IF NOT f.flowFromSource THEN LOOP; END ELSE IF f.drain = node THEN BEGIN other _ f.source; IF NOT f.flowFromDrain THEN LOOP; END ELSE LOOP; IF other.always1 OR other.always0 THEN LOOP; IF f.firstFlow # NIL THEN IF NOT Flow.Lock[f, node] THEN LOOP; <> IF size >= Globals.pieceLimit THEN BEGIN IF f.firstFlow # NIL THEN Flow.Unlock[f, node]; stageOverflowCount _ stageOverflowCount + 1; IF stageOverflowCount > stageOverflowLimit THEN GOTO done; IO.PutF[Globals.StdOut, "More than %d transistors in series, see %s.\n", IO.int[Globals.pieceLimit], IO.rope[Printout.NodeRope[node, globalVars]]]; IF stageOverflowCount = stageOverflowLimit THEN IO.PutRope[Globals.StdOut, "No more messages of this kind will be printed....\n"]; GOTO done; END; stage.piece2Fet[size-1] _ f; stage.piece2Node[size] _ other; stage.piece2Size _ size + 1; result _ chaseGates[stage, globalVars]; IF f.firstFlow # NIL THEN Flow.Unlock[f, node]; IF NOT result THEN GOTO giveUp; ENDLOOP; GOTO done; EXITS giveUp => BEGIN IO.PutF[Globals.StdOut, "ChaseGates giving up at %s.\n", IO.rope[Printout.NodeRope[node, globalVars]]]; node.inPath _ FALSE; RETURN [FALSE]; END; done => BEGIN node.inPath _ FALSE; RETURN [TRUE]; END } END; chaseLoads: PROC[node: Globals.Node, stage: Globals.Stage, globalVars: Globals.GlobalVars] = <> <> BEGIN p: Globals.Pointer; f: Globals.Fet; other: Globals.Node; chaseLoadsCalls _ chaseLoadsCalls + 1; <> IF node.always1 OR node.always0 THEN RETURN; IF node.inPath THEN BEGIN feedbacks _ feedbacks + 1; IF stage.prev.time >= DPrint.Threshold[memory] THEN DPrint.Record[stage.prev, memory]; RETURN; END; <> FOR p _ node.firstPointer, p.next UNTIL p = NIL DO f _ p.fet; IF NOT (f.forcedOn OR f.onAlways) THEN LOOP; IF f.source = node THEN BEGIN other _ f.drain; IF NOT f.flowFromDrain THEN LOOP; END ELSE IF f.drain = node THEN BEGIN other _ f.source; IF NOT f.flowFromSource THEN LOOP; END ELSE LOOP; IF other.always1 THEN stage.rise _ TRUE ELSE IF other.always0 THEN stage.rise _ FALSE ELSE LOOP; IF f.firstFlow # NIL THEN IF NOT Flow.Lock[f, other] THEN LOOP; stage.piece1Size _ 0; stage.piece2Size _ 2; stage.piece2Node[0] _ other; stage.piece2Node[1] _ node; stage.piece2Fet[0] _ f; [] _ chaseGates[stage, globalVars]; IF f.firstFlow # NIL THEN Flow.Unlock[f, other]; RETURN; ENDLOOP; <> node.inPath _ TRUE; FOR p _ node.firstPointer, p.next UNTIL p = NIL DO f _ p.fet; IF f.forcedOff THEN LOOP; IF f.source = node THEN BEGIN other _ f.drain; IF NOT f.flowFromSource THEN LOOP; END ELSE IF f.drain = node THEN BEGIN other _ f.source; IF NOT f.flowFromDrain THEN LOOP; END ELSE LOOP; IF f.firstFlow # NIL THEN BEGIN IF Flow.Lock[f, node] THEN BEGIN chaseLoads[other, stage, globalVars]; Flow.Unlock[f, node]; END; END ELSE chaseLoads[other, stage, globalVars]; ENDLOOP; node.inPath _ FALSE; RETURN; END; Propagate: PUBLIC PROC[prevStage: Globals.Stage, globalVars: Globals.GlobalVars] = BEGIN p: Globals.Pointer; f: Globals.Fet; node: Globals.Node; stage: Globals.Stage; result: BOOLEAN; oldInPath: BOOLEAN; propagateCalls _ propagateCalls + 1; <> delayCount _ delayCount + 1; IF Globals.Stop^ OR (delayCount >= DelayLimit) THEN BEGIN IF delayCount = DelayLimit THEN BEGIN IO.PutF[Globals.StdOut, "Aborting delay analysis: no solution after %d stages.\n", IO.int[DelayLimit]]; IO.PutRope[Globals.StdOut, "Perhaps you forgot to mark some of the flow in"]; IO.PutRope[Globals.StdOut, " pass transistors?\n The information below may point"]; IO.PutRope[Globals.StdOut, " out the trouble spot.\n"]; END; RETURN; END; node _ prevStage.piece2Node[prevStage.piece2Size - 1]; <> <<((Rope.Fetch[node.name, 0] < '0) OR Rope.Fetch[node.name, 0] > '9)) THEN>> <> IF PrintAll OR Print THEN IO.PutF[Globals.StdOut, "Delay at %s set to %6.1fns up, %6.1fns down.\n", IO.rope[Printout.NodeRope[node, globalVars]], IO.real[node.hiTime], IO.real[node.loTime]]; <> IF prevStage.time >= DPrint.Threshold[any] THEN DPrint.Record[prevStage, any]; IF node.dynamic AND (prevStage.time >= DPrint.Threshold[memory]) THEN DPrint.Record[prevStage, memory]; IF node.watched AND (prevStage.time >= DPrint.Threshold[watched]) THEN DPrint.Record[prevStage, watched]; stage _ StagePool.New[]; stage.prev _ prevStage; <> IF node.input OR node.bus OR node.cap >= BusThreshold THEN BEGIN stage.piece1Size _ 0; stage.piece2Size _ 1; stage.piece2Node[0] _ node; stage.rise _ prevStage.rise; <> oldInPath _ node.inPath; node.inPath _ FALSE; result _ chaseGates[stage, globalVars]; node.inPath _ oldInPath; IF NOT result THEN BEGIN StagePool.Free[stage]; RETURN; END; END; <> FOR p _ node.firstPointer, p.next UNTIL p = NIL DO f _ p.fet; IF f.gate # node THEN LOOP; IF f.onAlways OR f.forcedOn OR f.forcedOff THEN LOOP; <> IF (prevStage.rise AND NOT f.on0) OR ((NOT prevStage.rise) AND NOT f.on1) THEN BEGIN IF f.flowFromSource THEN BEGIN IF f.firstFlow # NIL THEN IF NOT Flow.Lock[f, f.source] THEN GOTO skipSource; stage.piece1Size _ 1; stage.piece1Fet[0] _ f; stage.piece1Node[0] _ f.source; stage.piece2Size _ 1; stage.piece2Node[0] _ f.drain; IF f.source = globalVars.GroundNode THEN BEGIN stage.rise _ FALSE; result _ chaseGates[stage, globalVars]; END ELSE IF f.source = globalVars.VddNode THEN BEGIN stage.rise _ TRUE; result _ chaseGates[stage, globalVars]; END ELSE result _ chaseVG[stage, globalVars]; IF f.firstFlow # NIL THEN Flow.Unlock[f, f.source]; IF NOT result THEN BEGIN StagePool.Free[stage]; RETURN; END; EXITS skipSource => NULL; END; IF f.flowFromDrain THEN BEGIN IF f.firstFlow # NIL THEN IF NOT Flow.Lock[f, f.drain] THEN GOTO skipDrain; stage.piece1Size _ 1; stage.piece1Fet[0] _ f; stage.piece1Node[0] _ f.drain; stage.piece2Size _ 1; stage.piece2Node[0] _ f.source; IF f.drain = globalVars.GroundNode THEN BEGIN stage.rise _ FALSE; result _ chaseGates[stage, globalVars]; END ELSE IF f.drain = globalVars.VddNode THEN BEGIN stage.rise _ TRUE; result _ chaseGates[stage, globalVars]; END ELSE result _ chaseVG[stage, globalVars]; IF f.firstFlow # NIL THEN Flow.Unlock[f, f.drain]; IF NOT result THEN BEGIN StagePool.Free[stage]; RETURN; END; EXITS skipDrain => NULL; END; END <> ELSE BEGIN IF f.flowFromSource THEN BEGIN oldInPath _ f.source.inPath; f.source.inPath _ TRUE; [] _ chaseLoads[f.drain, stage, globalVars]; f.source.inPath _ oldInPath; END; IF f.flowFromDrain THEN BEGIN oldInPath _ f.drain.inPath; f.drain.inPath _ TRUE; [] _ chaseLoads[f.source, stage, globalVars]; f.drain.inPath _ oldInPath; END; END; ENDLOOP; StagePool.Free[stage]; END; DelayCmd: PUBLIC Globals.CmdProc = BEGIN DelayProc: PROC [node: Globals.Node] ~ { stage: Globals.Stage _ StagePool.New[]; stage.prev _ NIL; stage.piece1Size _ 0; stage.piece2Size _ 1; stage.piece2Node[0] _ node; stage.piece2Fet[0] _ NIL; IF hiTime >= 0 THEN BEGIN stage.time _ hiTime; stage.rise _ TRUE; IF hiTime > node.hiTime THEN node.hiTime _ hiTime; Propagate[stage, globalVars]; END; IF loTime >= 0 THEN BEGIN stage.time _ loTime; stage.rise _ FALSE; IF loTime > node.loTime THEN node.loTime _ loTime; Propagate[stage, globalVars]; END; StagePool.Free[stage]; }; nodeName: Rope.ROPE; ok: BOOLEAN; <> IF args = NIL THEN GOTO noArgs; nodeName _ args.rope; args _ args.next; IF args = NIL THEN GOTO noArgs; [ok, hiTime] _ Parse.Real[args]; IF NOT ok THEN GOTO noArgs; args _ args.next; IF args = NIL THEN GOTO noArgs; [ok, loTime] _ Parse.Real[args]; IF NOT ok THEN GOTO noArgs; <> DelayProc[Build.NodeFromRope[nodeName, globalVars]]; EXITS noArgs => BEGIN IO.PutRope[Globals.StdOut, "Delay requires three arguments:\n"]; IO.PutRope[Globals.StdOut, " node name, rise time, fall time.\n"]; END; END; Stats: PUBLIC PROC[] = BEGIN IO.PutF[Globals.StdOut, "Number of calls to chase Vdd or GND: %d.\n", IO.int[chaseVGCalls]]; IO.PutF[Globals.StdOut, "Number of calls to chase gates: %d.\n", IO.int[chaseGatesCalls]]; IO.PutF[Globals.StdOut, "Number of calls to chase loads: %d.\n", IO.int[chaseLoadsCalls]]; IO.PutF[Globals.StdOut, "Number of calls to propagate delays: %d.\n", IO.int[propagateCalls]]; IO.PutF[Globals.StdOut, "Number of delay feedback paths: %d.\n", IO.int[feedbacks]]; END; END.