-- FILE: SlopeModelImpl.mesa -- Last edited by Ousterhout, November 29, 1983 2:50 pm -- This file implements the slope model for Xerox Crystal. To understand -- how the slope model works, see either the Berkeley code or the paper -- by Ousterhout on the Crystal models. This model uses slopes and the -- Penfield-Rubinstein model for distributed capacitance. It uses intrinsic -- rise-times everywhere (the outES tables are not used). DIRECTORY Globals, IO, Model, Printout, SlopeModel; SlopeModelImpl: CEDAR PROGRAM IMPORTS Globals, IO, Model, Printout EXPORTS SlopeModel = BEGIN OPEN Globals, Model; -- The following stuff is used to keep from printing zillions of -- messages when the tables overflow a lot. maxUpRatio: ARRAY[0..maxFetTypes) OF REAL ← ALL[0]; maxDownRatio: ARRAY[0..maxFetTypes) OF REAL ← ALL[0]; SlopeDelay: PUBLIC DelayProc = BEGIN f: Fet; r, c, resVolts, rFactor, rcIntegral, tmp: REAL; rEff, ratio: REF ParmArray; thisC, thisR, tmp2: REAL; esIntegral, es: REAL; isLoad: BOOLEAN; type: TType; i: INT; -- Make sure that there is stuff in the stage. stage.time ← -1.0; stage.edgeSpeed ← 0; IF (stage.piece1Size = 0) AND (stage.piece2Size <= 1) THEN BEGIN IO.PutRope[StdOut, "Crystal bug: nothing in stage!\n"]; RETURN; END; -- Precompute the voltage drop used to compute resistor edge speeds. IF stage.rise THEN BEGIN resVolts ← vdd↑ - vinv↑; rFactor ← rUpFactor↑; END ELSE BEGIN resVolts ← vinv↑; rFactor ← rDownFactor↑; END; -- Figure out if there's a load driving this stage. We know there's a -- load if there's no piece1 and the first node in piece2 is fixed in value. IF (stage.piece1Size = 0) AND (stage.piece2Node[0].always0 OR stage.piece2Node[0].always1) THEN isLoad ← TRUE ELSE isLoad ← FALSE; -- Go through the two pieces of the path, computing the integral of RdC -- through the path. There are a couple of hitches in this. First of all, -- don't count any capacitance in piece1: we assume it's been discharged -- already. Also, we have to leave out any resistance associated with the -- trigger transistor for now (it will be interpolated and added later). To -- add in its value later, we have to remember the total capacitance of -- the path. Also, leave out the capacitance and resistance of the node -- that is signal source: it is supposed to have infinite capacitance and -- zero resistance. r ← 0.0; c ← 0.0; es ← 0.0; rcIntegral ← 0.0; esIntegral ← 0.0; FOR i IN [0..stage.piece1Size) DO IF i # 0 THEN BEGIN f ← stage.piece1Fet[i]; type ← TypeTable[f.type]; IF stage.rise THEN BEGIN tmp ← type.upREff[0]; es ← es + type.upOutES[0] * f.aspect; END ELSE BEGIN tmp ← type.downREff[0]; es ← es + type.downOutES[0] * f.aspect; END; IF tmp = 0 THEN RETURN; r ← r + (tmp * f.aspect); END; -- The last node in piece1 is the signal source, so don't -- consider it. IF i # (stage.piece1Size - 1) THEN BEGIN tmp ← stage.piece1Node[i].res; r ← r + (tmp * rFactor); es ← es + tmp/(resVolts*1000); END; ENDLOOP; FOR i IN [0..stage.piece2Size) DO -- When the stage is load-driven, we don't consider the -- first transistor (it will be interpolated below), or the -- first node in piece2, since it is the signal source. IF (i=0) AND isLoad THEN LOOP; -- If no piece1, then first node in piece2 supplies signal -- so don't use the capacitance or resistance associated -- with the node. IF (i # 0) OR (stage.piece1Size # 0) THEN BEGIN thisR ← stage.piece2Node[i].res; thisC ← stage.piece2Node[i].cap; r ← r + (thisR*rFactor); c ← c + thisC; rcIntegral ← rcIntegral + (r * thisC); es ← es + thisR/(resVolts*1000); esIntegral ← esIntegral + (es * thisC); END; f ← stage.piece2Fet[i]; IF f # NIL THEN BEGIN type ← TypeTable[f.type]; IF stage.rise THEN BEGIN thisR ← type.upREff[0]; es ← es + type.upOutES[0] * f.aspect; END ELSE BEGIN thisR ← type.downREff[0]; es ← es + type.downOutES[0] * f.aspect; END; IF thisR = 0 THEN RETURN; r ← r + thisR*f.aspect; thisC ← f.area * type.cPerArea; c ← c + thisC; rcIntegral ← rcIntegral + (thisC * r); esIntegral ← esIntegral + (thisC * es); END; ENDLOOP; -- If this stage is a carry-over from a bus (no piece1 and not a load), then -- we're done; return the RC integral as the delay, and sum the RC integral -- and the edgeSpeed from the last stage to produce the new edgeSpeed for -- this stage. If this isn't a bus carryover, then figure out which is the -- transistor that is to be used for interpolation. IF stage.piece1Size = 0 THEN BEGIN IF NOT isLoad THEN BEGIN stage.time ← rcIntegral/1000.0 + stage.prev.time; stage.edgeSpeed ← esIntegral; RETURN; END; f ← stage.piece2Fet[0]; END ELSE f ← stage.piece1Fet[0]; -- Now do linear interpolation in the slope tables to compute the -- effective resistance of the trigger or load transistor. type ← TypeTable[f.type]; IF stage.rise THEN BEGIN ratio ← type.upESRatio; rEff ← type.upREff; esIntegral ← esIntegral + (c * type.upOutES[0] * f.aspect); END ELSE BEGIN ratio ← type.downESRatio; rEff ← type.downREff; esIntegral ← esIntegral + (c * type.downOutES[0] * f.aspect); END; -- Zero resistance means this transistor can't drive in this direction, so -- return immediately. Zero capacitance means the node transits instantly. IF rEff[0] = 0 THEN RETURN; IF c = 0 THEN BEGIN IO.PutF[StdOut, "Zero capacitance in stage leading to %s!\n", IO.rope[Printout.NodeRope[stage.piece2Node[stage.piece2Size-1]]]]; stage.time ← stage.prev.time; stage.edgeSpeed ← 0; RETURN; END; tmp ← stage.prev.edgeSpeed/esIntegral; FOR i IN [0..maxSlopePoints-1) DO IF tmp < ratio[i+1] THEN EXIT; IF ratio[i+1] < ratio[i] THEN EXIT; ENDLOOP; -- If we ran off the top of the table, then use the last two values in -- the table for extrapolation. IF tmp >= ratio[i+1] THEN BEGIN IF stage.rise THEN BEGIN IF tmp > maxUpRatio[f.type] THEN BEGIN maxUpRatio[f.type] ← tmp; IO.PutF[StdOut, "Warning: ran off end of %s up slope table with\n", IO.rope[type.name]]; IO.PutF[StdOut, " edge speed ratio %f. Maybe you should ", IO.real[tmp]]; IO.PutRope[StdOut, "expand\n the range of the table.\n"]; END; END ELSE BEGIN IF tmp > maxDownRatio[f.type] THEN BEGIN maxDownRatio[f.type] ← tmp; IO.PutF[StdOut, "Warning: ran off end of %s down slope table with\n", IO.rope[type.name]]; IO.PutF[StdOut, " edge speed ratio %f. Maybe you should ", IO.real[tmp]]; IO.PutRope[StdOut, "expand\n the range of the table.\n"]; END; END; i ← i-1; END; tmp ← (tmp - ratio[i])/(ratio[i+1] - ratio[i]); tmp2 ← f.aspect * (rEff[i] + (tmp * (rEff[i+1] - rEff[i]))); rcIntegral ← rcIntegral + tmp2*c; stage.time ← rcIntegral/1000.0 + stage.prev.time; stage.edgeSpeed ← esIntegral; END; END.