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], globalVars]]];
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;