FILE: ModelImpl.mesa
Last edited by Ousterhout, November 22, 1983 3:32 pm
Christian LeCocq April 11, 1986 2:19:41 pm PST
This file contains the implementation of various routines and constants for dealing with technology-specific electrical information.
DIRECTORY
Globals,
IO,
Model,
Parse,
RealFns,
Rope,
SlopeModel;
ModelImpl: CEDAR PROGRAM
IMPORTS
Globals,
IO,
Parse,
RealFns,
Rope,
SlopeModel
EXPORTS Model =
BEGIN OPEN Model, Globals;
The model-independent parameters, and tables used to access them.
diffCPerArea: PUBLIC REF REAL ← NEW[REAL ← .00029];
polyCPerArea: PUBLIC REF REAL ← NEW[REAL ← .00004];
metalCPerArea: PUBLIC REF REAL ← NEW[REAL ← .000026];
diffCPerPerim: PUBLIC REF REAL ← NEW[REAL ← .00023];
diffR: PUBLIC REF REAL ← NEW[REAL ← 60];
polyR: PUBLIC REF REAL ← NEW[REAL ← 3];
metalR: PUBLIC REF REAL ← NEW[REAL ← .04];
vdd: PUBLIC REF REAL ← NEW[REAL ← 5.0];
vinv: PUBLIC REF REAL ← NEW[REAL ← 2.5];
rUpFactor: PUBLIC REF REAL ← NEW[REAL ← 1.0];
rDownFactor: PUBLIC REF REAL ← NEW[REAL ← 1.0];
Gives names of various parasitic parameters.
parmNames:
ARRAY[0..9)
OF Rope.
ROPE ←
[
"diffcperarea",
"diffcperperim",
"diffresistance",
"metalcperarea",
"metalresistance",
"polycperarea",
"polyresistance",
"vdd",
"vinv"
];
Gives units for various parmaters (used in printing them out).
parmUnits:
ARRAY[0..9)
OF Rope.
ROPE ←
[
"pf/sq. micron",
"pf/micron",
"ohms/square",
"pf/sq. micron",
"ohms/square",
"pf/sq. micron",
"ohms/square",
"volts",
"volts"
];
parmLocs:
ARRAY[0..9)
OF
REF
REAL ←
[
diffCPerArea,
diffCPerPerim,
diffR,
metalCPerArea,
metalR,
polyCPerArea,
polyR,
vdd,
vinv
];
Information about different models:
nModels: INT = 2;
curModel: INT ← 1;
modelNames:
ARRAY[0..nModels)
OF Rope.
ROPE ←
[
"rc (simple lumped RC approximation)",
"slope"
];
modelDelayProcs:
ARRAY[0..nModels)
OF DelayProc ←
[
RCDelay,
SlopeModel.SlopeDelay
];
TypeTable: PUBLIC ARRAY[0..maxFetTypes) OF TType;
Names of type table fields:
fieldNames:
ARRAY[0..9)
OF Rope.
ROPE ←
[
"cperarea",
"cperwidth",
"histrength",
"lowstrength",
"on",
"rdown",
"rup",
"slopeparmsdown",
"slopeparmsup"
];
ModelCmd:
PUBLIC CmdProc =
BEGIN
index: INT;
If no arguments, just print out information about the available models.
IF args =
NIL
THEN
BEGIN
FOR i:
INT
IN [0..nModels)
DO
IF i = curModel
THEN
IO.PutF[StdOut, "**** %s\n", IO.rope[modelNames[i]]]
ELSE IO.PutF[StdOut, " %s\n", IO.rope[modelNames[i]]];
ENDLOOP;
RETURN;
END;
TRUSTED {index ← Parse.Lookup[args.rope, DESCRIPTOR[modelNames]]};
IF index = -1
THEN
BEGIN
IO.PutF[StdOut, "%s isn't a model name.\n", IO.rope[args.rope]];
RETURN;
END
ELSE
IF index = -2
THEN
BEGIN
IO.PutF[StdOut, "%s is an ambiguous model abbreviation.\n", IO.rope[args.rope]];
RETURN;
END;
curModel ← index;
END;
ParmCmd:
PUBLIC CmdProc =
BEGIN
name: Rope.ROPE;
valueArg: Arg;
value: REAL;
index: INT;
ok: BOOLEAN;
If no arguments, then just print out all current values.
IF args =
NIL
THEN
BEGIN
FOR i:
INTEGER
IN [0..
LENGTH[parmNames])
DO
IO.PutF[StdOut, "%s = %f %s\n", IO.rope[parmNames[i]], IO.real[parmLocs[i]^], IO.rope[parmUnits[i]]];
ENDLOOP;
RETURN;
END;
Arguments must come in <name value> pairs.
WHILE args #
NIL
DO
name ← args.rope;
args ← args.next;
IF args =
NIL
THEN
BEGIN
IO.PutF[StdOut, "No value given for %s.\n", IO.rope[name]];
EXIT;
END;
valueArg ← args;
args ← args.next;
TRUSTED {index ← Parse.Lookup[name, DESCRIPTOR[parmNames]]};
IF index = -2
THEN
BEGIN
IO.PutF[StdOut, "%s isn't a model parameter.\n", IO.rope[name]];
LOOP;
END;
IF index = -1
THEN
BEGIN
IO.PutF[StdOut, "%s is an ambiguous abbreviation.\n", IO.rope[name]];
LOOP;
END;
[ok, value] ← Parse.Real[valueArg];
IF (value <= 0.0)
OR (
NOT ok)
THEN
BEGIN
IO.PutF[StdOut, "Bad value given for %s.\n", IO.rope[name]];
LOOP;
END;
parmLocs[index]^ ← value;
ENDLOOP;
END;
getSlope:
PROC[args: Arg, ratio, rEff, outES:
REF ParmArray]
RETURNS [Arg] =
This is a utility routine used to read in slope table information. The arguments are processed in batches of three, filling up the tables. The return result is the next argument after the last one used.
BEGIN
ok: BOOLEAN;
val: REAL;
i: INT;
FOR i
IN [0..maxSlopePoints)
DO
[ok, val] ← Parse.Real[args];
IF NOT ok THEN EXIT;
args ← args.next;
IF val < 0.0
THEN
BEGIN
IO.PutF[StdOut, "Can't have negative value %f in slope table.\n", IO.real[val]];
EXIT;
END;
ratio[i] ← val;
[ok, val] ← Parse.Real[args];
IF
NOT ok
THEN
BEGIN
IO.PutRope[StdOut, "Only one number supplied for last slope table entry.\n"];
EXIT;
END;
args ← args.next;
rEff[i] ← val;
[ok, val] ← Parse.Real[args];
IF
NOT ok
THEN
BEGIN
IO.PutRope[StdOut, "Only two numbers supplied for last slope table entry.\n"];
EXIT;
END;
args ← args.next;
outES[i] ← val;
Watch out for decreasing ratio values.
IF i > 0
THEN
BEGIN
IF ratio[i] < ratio[i-1]
THEN
BEGIN
IO.PutF[StdOut, "Warning: edge speed ratio %f", IO.real[ratio[i]]];
IO.PutRope[StdOut, " isn't monotonically increasing.\n"];
IO.PutRope[StdOut, " Interpolation table truncated.\n"];
EXIT;
END;
END;
ENDLOOP;
Mark the end of the table with a negative ratio. If there's only a single entry, add a second one so that interpolation and extrapolation will work.
IF i = 0
THEN
BEGIN
ratio[0] ← 0;
rEff[0] ← 1000;
outES[0] ← 0;
i ← 1;
END;
IF i = 1
THEN
BEGIN
ratio[1] ← ratio[0] + 1000;
rEff[1] ← rEff[0];
outES[1] ← outES[0];
ratio[2] ← -1;
END
ELSE IF i < maxSlopePoints THEN ratio[i] ← -1;
RETURN [args];
END;
printType:
PROC[index:
INTEGER] =
This is a utility routine used to print out all the information for a transistor of a given type.
BEGIN
IO.PutF[StdOut, "%s: ", IO.rope[TypeTable[index].name]];
IF TypeTable[index].on0
THEN
IO.PutRope[StdOut, "on gate0"];
IF TypeTable[index].on1
THEN
IO.PutRope[StdOut, "on gate1"];
IF TypeTable[index].onAlways
THEN
IO.PutRope[StdOut, "on always"];
IO.PutF[StdOut, " histrength %d", IO.int[TypeTable[index].strengthHi]];
IO.PutF[StdOut, " lowstrength %d", IO.int[TypeTable[index].strengthLo]];
IO.PutF[StdOut, "\n cperarea %.3f cperwidth %.3f", IO.real[TypeTable[index].cPerArea], IO.real[TypeTable[index].cPerWidth]];
IO.PutF[StdOut, " rup %.1f rdown %.1f\n", IO.real[TypeTable[index].rUp], IO.real[TypeTable[index].rDown]];
IO.PutRope[StdOut, " Slope parameters up (ratio, rEff, outES) =\n"];
printSlope[TypeTable[index].upESRatio, TypeTable[index].upREff, TypeTable[index].upOutES, maxSlopePoints];
IO.PutRope[StdOut, " Slope parameters down (ratio, rEff, outES) =\n"];
printSlope[TypeTable[index].downESRatio, TypeTable[index].downREff, TypeTable[index].downOutES, maxSlopePoints];
printSlope:
PROC[esRatio, rEff, outES:
REF ParmArray, maxPoints:
INT] =
This is a utility routine used to print out the values in slope tables. The values in the tables are printed in a reasonably pretty fashion, two entries from each table per line.
BEGIN
lineHasStuff: BOOLEAN ← FALSE;
FOR i:
INT
IN [0..maxPoints)
DO
IF esRatio[i] < 0 THEN EXIT;
IO.PutF[StdOut, " %8.3f, %8.1f, %8.3f;", IO.real[esRatio[i]], IO.real[rEff[i]], IO.real[outES[i]]];
IF lineHasStuff
THEN
BEGIN
lineHasStuff ← FALSE;
IO.PutRope[StdOut, "\n"];
END
ELSE lineHasStuff ← TRUE;
ENDLOOP;
IF lineHasStuff THEN IO.PutRope[StdOut, "\n"];
END;
TransistorCmd:
PUBLIC CmdProc =
BEGIN
type: INT;
field: Rope.ROPE;
valueArg: Arg;
index, intVal: INT;
realVal: REAL;
ok: BOOLEAN;
If there are no arguments, print out all fields of all transistor types. If there is only one argument print out all fields for that transistor type.
IF args =
NIL
THEN
BEGIN
FOR i:
INTEGER
IN [0..maxFetTypes)
DO
IF TypeTable[i] = NIL THEN RETURN;
printType[i];
ENDLOOP;
RETURN;
END
ELSE
IF args.next =
NIL
THEN
BEGIN
FOR i:
INTEGER
IN [0..maxFetTypes)
DO
IF TypeTable[i] = NIL THEN EXIT;
IF Rope.Equal[args.rope, TypeTable[i].name,
FALSE]
THEN
BEGIN
printType[i];
RETURN;
END;
ENDLOOP;
IO.PutF[StdOut, "Transistor type %s doesn't exist.\n", IO.rope[args.rope]];
RETURN;
END;
Make sure that the type name exists. Create a new one if necessary.
type ← -1;
FOR i:
INTEGER
IN [0..maxFetTypes)
DO
IF TypeTable[i] =
NIL
THEN
BEGIN
type ← i;
TypeTable[type] ←
NEW[TTypeRec ←
[name: args.rope, strengthHi: 0, strengthLo: 0,
cPerArea: 0, cPerWidth: 0, rUp: 0, rDown: 0,
on0: FALSE, on1: TRUE, onAlways: FALSE,
upESRatio: NEW[ParmArray ← [0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
upREff: NEW[ParmArray ← [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
upOutES: NEW[ParmArray ← [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
downESRatio: NEW[ParmArray ← [0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
downREff: NEW[ParmArray ← [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
downOutES: NEW[ParmArray ← [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]];
EXIT;
END;
IF Rope.Equal[args.rope, TypeTable[i].name,
FALSE]
THEN
BEGIN
type ← i;
EXIT;
END;
ENDLOOP;
Process <field value> pairs.
args ← args.next;
WHILE args #
NIL
DO
field ← args.rope;
args ← args.next;
IF args =
NIL
THEN
BEGIN
IO.PutF[StdOut, "No value given for %s.\n", IO.rope[field]];
EXIT;
END;
valueArg ← args;
args ← args.next;
TRUSTED {index ← Parse.Lookup[field, DESCRIPTOR[fieldNames]]};
IF index = -2
THEN
BEGIN
IO.PutF[StdOut, "%s isn't a field name.\n", IO.rope[field]];
LOOP;
END;
IF index = -1
THEN
BEGIN
IO.PutF[StdOut, "%s is an ambiguous abbreviation.\n", IO.rope[field]];
LOOP;
END;
SELECT index
FROM
0 =>
-- cperarea
BEGIN
[ok, realVal] ← Parse.Real[valueArg];
IF (
NOT ok)
OR (realVal < 0)
THEN
IO.PutRope[StdOut, "Bad capacitance value for cperarea.\n"]
ELSE TypeTable[type].cPerArea ← realVal;
END;
1 =>
-- cperwidth
BEGIN
[ok, realVal] ← Parse.Real[valueArg];
IF (
NOT ok)
OR (realVal < 0)
THEN
IO.PutRope[StdOut, "Bad capacitance value for cperwidth.\n"]
ELSE TypeTable[type].cPerWidth ← realVal;
END;
2 =>
-- histrength
BEGIN
[ok, intVal] ← Parse.Int[valueArg];
IF (
NOT ok)
OR (intVal < 0)
THEN
IO.PutRope[StdOut, "Bad value for histrength.\n"]
ELSE TypeTable[type].strengthHi ← intVal;
END;
3 =>
-- lowstrength
BEGIN
[ok, intVal] ← Parse.Int[valueArg];
IF (
NOT ok)
OR (intVal < 0)
THEN
BEGIN
IO.PutRope[StdOut, "Bad value for lowstrength.\n"];
EXIT;
END;
TypeTable[type].strengthLo ← intVal;
END;
4 =>
-- on
BEGIN
IF Rope.Equal[valueArg.rope, "gate1",
TRUE]
THEN
BEGIN
TypeTable[type].on1 ← TRUE;
TypeTable[type].on0 ← FALSE;
TypeTable[type].onAlways ← FALSE;
END
ELSE
IF Rope.Equal[valueArg.rope, "gate0",
TRUE]
THEN
BEGIN
TypeTable[type].on0 ← TRUE;
TypeTable[type].on1 ← FALSE;
TypeTable[type].onAlways ← FALSE;
END
ELSE
IF Rope.Equal[valueArg.rope, "always",
TRUE]
THEN
BEGIN
TypeTable[type].on0 ← FALSE;
TypeTable[type].on1 ← FALSE;
TypeTable[type].onAlways ← TRUE;
END
ELSE
IO.PutF[StdOut, "Unknown \"on\" condition: %s\n",
IO.rope[valueArg.rope]];
END;
5 =>
-- rdown
BEGIN
[ok, realVal] ← Parse.Real[valueArg];
IF (
NOT ok)
OR (realVal < 0)
THEN
IO.PutRope[StdOut, "Bad value for rdown.\n"]
ELSE TypeTable[type].rDown ← realVal;
END;
6 =>
-- rup
BEGIN
[ok, intVal] ← Parse.Int[valueArg];
IF (
NOT ok)
OR (realVal < 0)
THEN
IO.PutRope[StdOut, "Bad value for rup.\n"]
ELSE TypeTable[type].rUp ← intVal;
END;
7 =>
-- slopeparmsdown
BEGIN
args ← getSlope[valueArg,
TypeTable[type].downESRatio,
TypeTable[type].downREff,
TypeTable[type].downOutES];
END;
8 =>
-- slopeparmsup
BEGIN
args ← getSlope[valueArg,
TypeTable[type].upESRatio,
TypeTable[type].upREff,
TypeTable[type].upOutES];
END;
ENDCASE;
ENDLOOP;
rUpFactor^ ← - RealFns.Ln[(vdd^ - vinv^)/vdd^];
rDownFactor^ ← - RealFns.Ln[vinv^/vdd^];
END;
NameToIndex:
PUBLIC
PROC[name: Rope.
ROPE]
RETURNS [index:
INT] =
BEGIN
FOR i:
INTEGER
IN [0..maxFetTypes)
DO
IF TypeTable[i] = NIL THEN RETURN [-1];
IF Rope.Equal[TypeTable[i].name, name, FALSE] THEN RETURN [i];
ENDLOOP;
RETURN [-1];
END;
Delay:
PUBLIC DelayProc =
BEGIN
(modelDelayProcs[curModel])[stage, globalVars];
END;
RCDelay:
PUBLIC DelayProc =
This procedure updates the time value in the given stage by computing the delay in the stage and combining that with the time from the previous stage. A simple RC model is used to compute the delay.
BEGIN
f: Fet;
r, c, tmp, rFactor: REAL;
i: INT;
Make sure that there is stuff in the path.
stage.time ← -1.0;
IF (stage.piece1Size = 0)
AND (stage.piece2Size = 0)
THEN
BEGIN
IO.PutRope[StdOut, "Crystal bug: nothing in stage!"];
RETURN;
END;
Go through the two pieces of the path, summing all the resistances in both pieces and the capacitances in piece2 (this code assumes that the capacitance in piece1 has already been drained away before the driving transistor turns on). If a zero FET resistance is found, it means that the transistor can't drive in the given direction, so quit.
r ← 0.0;
c ← 0.0;
IF stage.rise THEN rFactor ← rUpFactor^
ELSE rFactor ← rDownFactor^;
FOR i
IN [0..stage.piece1Size)
DO
f ← stage.piece1Fet[i];
IF stage.rise THEN tmp ← TypeTable[f.type].rUp
ELSE tmp ← TypeTable[f.type].rDown;
IF tmp = 0 THEN RETURN;
r ← r + tmp*f.aspect + (stage.piece1Node[i].res*rFactor);
ENDLOOP;
FOR i
IN [0..stage.piece2Size)
DO
f ← stage.piece2Fet[i];
IF f #
NIL
THEN
BEGIN
IF stage.rise THEN tmp ← TypeTable[f.type].rUp
ELSE tmp ← TypeTable[f.type].rDown;
IF tmp = 0 THEN RETURN;
r ← r + tmp*f.aspect;
c ← c + f.area*TypeTable[f.type].cPerArea;
END;
r ← r + (stage.piece2Node[i].res*rFactor);
c ← c + stage.piece2Node[i].cap;
ENDLOOP;
Throw out the capacitance and resistance from the node that is supplying the signal (either the first node in piece1, or the first node in piece2 if there isn't a piece1). This node is treated here as an infinite source of charge.
IF stage.piece1Size # 0
THEN
r ← r - (stage.piece1Node[stage.piece1Size-1].res*rFactor)
ELSE
BEGIN
r ← r - (stage.piece2Node[0].res*rFactor);
c ← c - stage.piece2Node[0].cap;
END;
stage.time ← (r*c)/1000.0 + stage.prev.time;
END;
TypeTable[fetNEnh] ←
NEW[TTypeRec ←
[name: "NETran", strengthHi: 2, strengthLo: 3, cPerArea: .0004,
cPerWidth: .00025, rUp: 24800, rDown: 9720, on0: FALSE,
on1: TRUE, onAlways: FALSE,
upESRatio:
NEW[ParmArray ←
[0, .0014, .0026, .017, .16, 1.6, 16, -1, 0, 0]],
upREff:
NEW[ParmArray ←
[24800, 24800, 24600, 25800, 38400, 153000, 1070000, 0, 0, 0]],
upOutES:
NEW[ParmArray ←
[37.2, 37.2, 37.5, 38, 42, 162, 1340, 0, 0, 0]],
downESRatio:
NEW[ParmArray ←
[0, .018, .086, .74, 7.3, 73, -1, 0, 0, 0]],
downREff:
NEW[ParmArray ←
[9720, 9720, 10100, 14000, 36300, 164000, 0, 0, 0, 0]],
downOutES:
NEW[ParmArray ←
[4.0, 4.0, 4.0, 4.3, 10.2, 41.0, 0, 0, 0, 0]]]];
TypeTable[fetNEnhP] ←
NEW[TTypeRec ←
[name: "nenhp", strengthHi: 2, strengthLo: 3, cPerArea: .0004,
cPerWidth: .00025, rUp: 200000, rDown: 200000, on0: FALSE,
on1: TRUE, onAlways: FALSE,
upESRatio:
NEW[ParmArray ←
[0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
upREff:
NEW[ParmArray ←
[200000, 200000, 0, 0, 0, 0, 0, 0, 0, 0]],
upOutES:
NEW[ParmArray ←
[100, 100, 0, 0, 0, 0, 0, 0, 0, 0]],
downESRatio:
NEW[ParmArray ←
[0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
downREff:
NEW[ParmArray ←
[200000, 200000, 0, 0, 0, 0, 0, 0, 0, 0]],
downOutES:
NEW[ParmArray ←
[100, 100, 0, 0, 0, 0, 0, 0, 0, 0]]]];
TypeTable[fetNDep] ←
NEW[TTypeRec ←
[name: "NDTran", strengthHi: 2, strengthLo: 3, cPerArea: .0004,
cPerWidth: .00025, rUp: 50000, rDown: 23000, on0: FALSE,
on1: FALSE, onAlways: TRUE,
upESRatio:
NEW[ParmArray ←
[0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
upREff:
NEW[ParmArray ←
[50000, 50000, 0, 0, 0, 0, 0, 0, 0, 0]],
upOutES:
NEW[ParmArray ←
[75, 75, 0, 0, 0, 0, 0, 0, 0, 0]],
downESRatio:
NEW[ParmArray ←
[0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
downREff:
NEW[ParmArray ←
[23000, 23000, 0, 0, 0, 0, 0, 0, 0, 0]],
downOutES:
NEW[ParmArray ←
[9.5, 9.5, 0, 0, 0, 0, 0, 0, 0, 0]]]];
TypeTable[fetNLoad] ←
NEW[TTypeRec ←
[name: "nload", strengthHi: 2, strengthLo: 0, cPerArea: 0,
cPerWidth: .00025, rUp: 21900, rDown: 0, on0: FALSE,
on1: FALSE, onAlways: TRUE,
upESRatio:
NEW[ParmArray ←
[0, .406, 1.344, 4.027, 13.4, 40.3, -1, 0, 0, 0]],
upREff:
NEW[ParmArray ←
[21900, 21000, 23800, 31400, 43300, 57800, 0, 0, 0, 0]],
upOutES:
NEW[ParmArray ←
[13.3, 13.3, 13.0, 21, 44.7, 107, 0, 0, 0, 0]],
downESRatio:
NEW[ParmArray ←
[0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
downREff:
NEW[ParmArray ←
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],
downOutES:
NEW[ParmArray ←
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]]];
TypeTable[fetNSuper] ←
NEW[TTypeRec ←
[name: "nsuper", strengthHi: 2, strengthLo: 0, cPerArea: .0004,
cPerWidth: .00025, rUp: 4800, rDown: 5100, on0: FALSE,
on1: FALSE, onAlways: TRUE,
upESRatio:
NEW[ParmArray ←
[0, .214, .464, 1.139, 3.58, 10.96, 36.2, 108, -1, 0]],
upREff:
NEW[ParmArray ←
[4800, 4700, 5400, 6800, 8500, 8200, 1900, -17600, 0, 0]],
upOutES:
NEW[ParmArray ←
[3.5, 3.5, 4.2, 6.7, 15.8, 42.9, 140, 413, 0, 0]],
downESRatio:
NEW[ParmArray ←
[0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
downREff:
NEW[ParmArray ←
[5100, 5100, 0, 0, 0, 0, 0, 0, 0, 0]],
downOutES:
NEW[ParmArray ←
[2.5, 2.5, 0, 0, 0, 0, 0, 0, 0, 0]]]];
TypeTable[fetNChan] ←
NEW[TTypeRec ←
[name: "nchan", strengthHi: 2, strengthLo: 3, cPerArea: .0004,
cPerWidth: .00025, rUp: 24800, rDown: 9720, on0: FALSE,
on1: TRUE, onAlways: FALSE,
upESRatio:
NEW[ParmArray ←
[0, .0014, .0026, .017, .16, 1.6, 16, -1, 0, 0]],
upREff:
NEW[ParmArray ←
[24800, 24800, 24600, 25800, 38400, 153000, 1070000, 0, 0, 0]],
upOutES:
NEW[ParmArray ←
[37.2, 37.2, 37.5, 38, 42, 162, 1340, 0, 0, 0]],
downESRatio:
NEW[ParmArray ←
[0, .018, .086, .74, 7.3, 73, -1, 0, 0, 0]],
downREff:
NEW[ParmArray ←
[9720, 9720, 10100, 14000, 36300, 164000, 0, 0, 0, 0]],
downOutES:
NEW[ParmArray ←
[4.0, 4.0, 4.0, 4.3, 10.2, 41.0, 0, 0, 0, 0]]]];
TypeTable[fetPChan] ←
NEW[TTypeRec ←
[name: "PETran", strengthHi: 2, strengthLo: 2, cPerArea: .0004,
cPerWidth: .00025, rUp: 19050, rDown: 200000, on0: TRUE,
on1: FALSE, onAlways: FALSE,
upESRatio:
NEW[ParmArray ←
[0, .017, .028, .118, 1.05, 10.3, 31, 103, -1, 0]],
upREff:
NEW[ParmArray ←
[19050, 19050, 19100, 20100, 27900, 42400, 23400, -114000, 0, 0]],
upOutES:
NEW[ParmArray ←
[8.9, 8.9, 8.9, 8.9, 10.0, 25, 46.3, 97, 0, 0]],
downESRatio:
NEW[ParmArray ←
[0, 1000, -1, 0, 0, 0, 0, 0, 0, 0]],
downREff:
NEW[ParmArray ←
[200000, 200000, 0, 0, 0, 0, 0, 0, 0, 0]],
downOutES:
NEW[ParmArray ←
[100, 100, 0, 0, 0, 0, 0, 0, 0, 0]]]];
rUpFactor^ ← - RealFns.Ln[(vdd^ - vinv^)/vdd^];
rDownFactor^ ← - RealFns.Ln[vinv^/vdd^];
END.