-- 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.