<> <> <> <> DIRECTORY Globals, IO, Model, Parse, RealFns, Rope, SlopeModel; ModelImpl: CEDAR PROGRAM IMPORTS Globals, IO, Parse, RealFns, Rope, SlopeModel EXPORTS Model = BEGIN OPEN Model, Globals; <> 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]; <> parmNames: ARRAY[0..9) OF Rope.ROPE _ [ "diffcperarea", "diffcperperim", "diffresistance", "metalcperarea", "metalresistance", "polycperarea", "polyresistance", "vdd", "vinv" ]; <> 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 ]; <> 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; <> fieldNames: ARRAY[0..9) OF Rope.ROPE _ [ "cperarea", "cperwidth", "histrength", "lowstrength", "on", "rdown", "rup", "slopeparmsdown", "slopeparmsup" ]; ModelCmd: PUBLIC CmdProc = BEGIN index: INT; <> 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 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; < 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] = <> 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; <> 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; <> 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] = <> 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]; END; printSlope: PROC[esRatio, rEff, outES: REF ParmArray, maxPoints: INT] = <> 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 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; <> 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; < 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 = <> BEGIN f: Fet; r, c, tmp, rFactor: REAL; i: INT; <> stage.time _ -1.0; IF (stage.piece1Size = 0) AND (stage.piece2Size = 0) THEN BEGIN IO.PutRope[StdOut, "Crystal bug: nothing in stage!"]; RETURN; END; <> 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; <> 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.