committed by
Holger Vogt
6 changed files with 1181 additions and 8 deletions
-
7configure.ac
-
250src/spicelib/devices/adms/r2_cmc/admsva/cmcModels.inc
-
898src/spicelib/devices/adms/r2_cmc/admsva/r2_cmc.va
-
2src/spicelib/devices/dev.c
-
6src/spicelib/parser/inp2r.c
-
16src/spicelib/parser/inpdomod.c
@ -0,0 +1,250 @@ |
|||
|
|||
// |
|||
// This file is the top-level declaration for the following CMC Verilog-A models: |
|||
// |
|||
// r2_cmc CMC 2-terminal resistor model |
|||
// r2_et_cmc CMC 2-terminal resistor model with self-heating |
|||
// |
|||
|
|||
// |
|||
// Physical constants and other generally useful numbers |
|||
// |
|||
|
|||
`include "discipline.h" |
|||
`define TABS_NIST2004 2.73150000e+02 // (NIST2004) 0C in K |
|||
`define QQ_NIST2004 1.60217653e-19 // (NIST2004) mag. of electronic charge (C) |
|||
`define KB_NIST2004 1.38065050e-23 // (NIST2004) Boltzmann constant (J/K) |
|||
`define oneThird 3.3333333333333333e-01 |
|||
|
|||
// |
|||
// Clipping macros, these smoothly limit to lower, upper, or both lower and upper |
|||
// limits. Rather than using a sqrt or log-exp form, which affects values |
|||
// everywhere, these use a conditional form that is continuous in function |
|||
// and derivative. If a value is not clipped then no exp() evaluation occurs. |
|||
// Smooth limiting is preferable to hard limiting (although latter can still |
|||
// be useful for enforcing parameter limits) for bias dependent quantities |
|||
// as derivatives do not become zero or have discontinuities. |
|||
// |
|||
|
|||
`define CLIPL0p1(XCLIP,X,LOWER) \ |
|||
if (X<(LOWER+0.1)) \ |
|||
XCLIP = LOWER+0.1*exp(10.0*(X-LOWER)-1.0); \ |
|||
else \ |
|||
XCLIP = X; |
|||
`define CLIPU0p1(XCLIP,X,UPPER) \ |
|||
if (X>(UPPER-0.1)) \ |
|||
XCLIP = UPPER-0.1*exp(10.0*(UPPER-X)-1.0); \ |
|||
else \ |
|||
XCLIP = X; |
|||
`define CLIPB0p1(XCLIP,X,LOWER,UPPER) \ |
|||
if (X<(LOWER+0.1)) \ |
|||
XCLIP = LOWER+0.1*exp(10.0*(X-LOWER)-1.0); \ |
|||
else if (X>(UPPER-0.1)) \ |
|||
XCLIP = UPPER-0.1*exp(10.0*(UPPER-X)-1.0); \ |
|||
else \ |
|||
XCLIP = X; |
|||
|
|||
`define CLIPL1p0(XCLIP,X,LOWER) \ |
|||
if (X<(LOWER+1.0)) \ |
|||
XCLIP = LOWER+exp(X-LOWER-1.0); \ |
|||
else \ |
|||
XCLIP = X; |
|||
`define CLIPU1p0(XCLIP,X,UPPER) \ |
|||
if (X>(UPPER-1.0)) \ |
|||
XCLIP = UPPER-exp(UPPER-X-1.0); \ |
|||
else \ |
|||
XCLIP = X; |
|||
`define CLIPB1p0(XCLIP,X,LOWER,UPPER) \ |
|||
if (X<(LOWER+1.0)) \ |
|||
XCLIP = LOWER+exp(X-LOWER-1.0); \ |
|||
else if (X>(UPPER-1.0)) \ |
|||
XCLIP = UPPER-exp(UPPER-X-1.0); \ |
|||
else \ |
|||
XCLIP = X; |
|||
|
|||
`ifdef insideADMS |
|||
`ifdef notInsideADMS |
|||
`undef notInsideADMS |
|||
`endif |
|||
`else |
|||
`define notInsideADMS |
|||
`endif |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
`ifdef not__VAMS_COMPACT_MODELING__ |
|||
`undef not__VAMS_COMPACT_MODELING__ |
|||
`endif |
|||
`else |
|||
`define not__VAMS_COMPACT_MODELING__ |
|||
`endif |
|||
|
|||
// |
|||
// Conditional definitions of macros so that the code will work with |
|||
// Verilog-A 2.1 and 2.2, and ADMS. The "des" description argument is intended to |
|||
// be a short description, the "inf" information argument is intended to be |
|||
// a detailed description (e.g. for display as part of on-line help). |
|||
// |
|||
// MPR model parameter real |
|||
// MPI model parameter integer |
|||
// IPR instance parameter real |
|||
// IPI instance parameter integer |
|||
// IPM instance parameter mFactor (multiplicity, implicit for LRM2.2) |
|||
// OPP operating point parameter, includes units and description for printing |
|||
// |
|||
// There are some issues with passing range directives with some compilers, |
|||
// so for each parameter declaration there are 5 versions: |
|||
// cc closed lower bound, closed upper bound |
|||
// co closed lower bound, open upper bound |
|||
// oc open lower bound, closed upper bound |
|||
// oo open lower bound, open upper bound |
|||
// nb no bounds |
|||
// |
|||
|
|||
//`ifdef __VAMS_COMPACT_MODELING__ |
|||
`define ALIAS(alias,parameter) aliasparam alias = parameter; |
|||
`define ERROR(str) \ |
|||
begin \ |
|||
$strobe(str); \ |
|||
$finish(1); \ |
|||
end |
|||
`define WARNING(str) $strobe(str); |
|||
`define OPP(nam,uni,des) (*units=uni desc=des*) real nam; |
|||
`define MPRcc(nam,def,uni,lwr,upr,des) (*units=uni, desc=des*) parameter real nam=def from[lwr:upr]; |
|||
`define MPRco(nam,def,uni,lwr,upr,des) (*units=uni, desc=des*) parameter real nam=def from[lwr:upr); |
|||
`define MPRoc(nam,def,uni,lwr,upr,des) (*units=uni, desc=des*) parameter real nam=def from(lwr:upr]; |
|||
`define MPRoo(nam,def,uni,lwr,upr,des) (*units=uni, desc=des*) parameter real nam=def from(lwr:upr); |
|||
`define MPRnb(nam,def,uni, des) (*units=uni, desc=des*) parameter real nam=def; |
|||
`define MPIcc(nam,def,uni,lwr,upr,des) (*units=uni, desc=des*) parameter integer nam=def from[lwr:upr]; |
|||
`define MPIco(nam,def,uni,lwr,upr,des) (*units=uni, desc=des*) parameter integer nam=def from[lwr:upr); |
|||
`define MPIoc(nam,def,uni,lwr,upr,des) (*units=uni, desc=des*) parameter integer nam=def from(lwr:upr]; |
|||
`define MPIoo(nam,def,uni,lwr,upr,des) (*units=uni, desc=des*) parameter integer nam=def from(lwr:upr); |
|||
`define MPInb(nam,def,uni, des) (*units=uni, desc=des*) parameter integer nam=def; |
|||
`define IPRcc(nam,def,uni,lwr,upr,des) (*units=uni, type="instance", desc=des*) parameter real nam=def from[lwr:upr]; |
|||
`define IPRco(nam,def,uni,lwr,upr,des) (*units=uni, type="instance", desc=des*) parameter real nam=def from[lwr:upr); |
|||
`define IPRoc(nam,def,uni,lwr,upr,des) (*units=uni, type="instance", desc=des*) parameter real nam=def from(lwr:upr]; |
|||
`define IPRoo(nam,def,uni,lwr,upr,des) (*units=uni, type="instance", desc=des*) parameter real nam=def from(lwr:upr); |
|||
`define IPRnb(nam,def,uni, des) (*units=uni, type="instance", desc=des*) parameter real nam=def; |
|||
`define IPIcc(nam,def,uni,lwr,upr,des) (*units=uni, type="instance", desc=des*) parameter integer nam=def from[lwr:upr]; |
|||
`define IPIco(nam,def,uni,lwr,upr,des) (*units=uni, type="instance", desc=des*) parameter integer nam=def from[lwr:upr); |
|||
`define IPIoc(nam,def,uni,lwr,upr,des) (*units=uni, type="instance", desc=des*) parameter integer nam=def from(lwr:upr]; |
|||
`define IPIoo(nam,def,uni,lwr,upr,des) (*units=uni, type="instance", desc=des*) parameter integer nam=def from(lwr:upr); |
|||
`define IPInb(nam,def,uni, des) (*units=uni, type="instance", desc=des*) parameter integer nam=def; |
|||
`define IPM parameter real m=1 from(0:inf); |
|||
`define TESTGIVEN(parameter) $param_given(parameter) |
|||
`define GIVEN(parameter,variable,true,false) \ |
|||
begin \ |
|||
if ($param_given(parameter)) \ |
|||
variable = true; \ |
|||
else \ |
|||
variable = false; \ |
|||
end |
|||
// `define SCALE \ |
|||
// begin \ |
|||
// if ($param_given(scale)) \ |
|||
// scaleFac = scale; \ |
|||
// else \ |
|||
// scaleFac = $simparam("scale",1.0); \ |
|||
// end |
|||
// `define SHRINKL \ |
|||
// begin \ |
|||
// if ($param_given(shrink)) \ |
|||
// shrinkL = 1.0-0.01*shrink; \ |
|||
// else \ |
|||
// shrinkL = 1.0-0.01*$simparam("shrink",0.0); \ |
|||
// end |
|||
// `define RTHRESH \ |
|||
// begin \ |
|||
// if ($param_given(rthresh)) \ |
|||
// rthrR2 = rthresh; \ |
|||
// else \ |
|||
// rthrR2 = $simparam("rthresh",1.0e-03); \ |
|||
// end |
|||
//`else // not__VAMS_COMPACT_MODELING__ |
|||
// `define ALIAS(alias,parameter) |
|||
// `ifdef insideADMS |
|||
// `define ERROR(str) \ |
|||
// begin \ |
|||
// $strobe(str); \ |
|||
// $finish(1); \ |
|||
// end |
|||
// `define WARNING(str) $strobe(str); |
|||
// `define OPP(nam,uni,des) real nam (*units=uni desc=des ask="yes"*); |
|||
// `define MPRcc(nam,def,uni,lwr,upr,des) parameter real nam=def from[lwr:upr] (*units=uni ask="yes" info=des*); |
|||
// `define MPRco(nam,def,uni,lwr,upr,des) parameter real nam=def from[lwr:upr) (*units=uni ask="yes" info=des*); |
|||
// `define MPRoc(nam,def,uni,lwr,upr,des) parameter real nam=def from(lwr:upr] (*units=uni ask="yes" info=des*); |
|||
// `define MPRoo(nam,def,uni,lwr,upr,des) parameter real nam=def from(lwr:upr) (*units=uni ask="yes" info=des*); |
|||
// `define MPRnb(nam,def,uni, des) parameter real nam=def (*units=uni ask="yes" info=des*); |
|||
// `define MPIcc(nam,def,uni,lwr,upr,des) parameter integer nam=def from[lwr:upr] (*units=uni ask="yes" info=des*); |
|||
// `define MPIco(nam,def,uni,lwr,upr,des) parameter integer nam=def from[lwr:upr) (*units=uni ask="yes" info=des*); |
|||
// `define MPIoc(nam,def,uni,lwr,upr,des) parameter integer nam=def from(lwr:upr] (*units=uni ask="yes" info=des*); |
|||
// `define MPIoo(nam,def,uni,lwr,upr,des) parameter integer nam=def from(lwr:upr) (*units=uni ask="yes" info=des*); |
|||
// `define MPInb(nam,def,uni, des) parameter integer nam=def (*units=uni ask="yes" info=des*); |
|||
// `define IPRcc(nam,def,uni,lwr,upr,des) parameter real nam=def from[lwr:upr] (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPRco(nam,def,uni,lwr,upr,des) parameter real nam=def from[lwr:upr) (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPRoc(nam,def,uni,lwr,upr,des) parameter real nam=def from(lwr:upr] (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPRoo(nam,def,uni,lwr,upr,des) parameter real nam=def from(lwr:upr) (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPRnb(nam,def,uni, des) parameter real nam=def (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPIcc(nam,def,uni,lwr,upr,des) parameter integer nam=def from[lwr:upr] (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPIco(nam,def,uni,lwr,upr,des) parameter integer nam=def from[lwr:upr) (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPIoc(nam,def,uni,lwr,upr,des) parameter integer nam=def from(lwr:upr] (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPIoo(nam,def,uni,lwr,upr,des) parameter integer nam=def from(lwr:upr) (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPInb(nam,def,uni, des) parameter integer nam=def (*units=uni type="instance" ask="yes" info=des*); |
|||
// `define IPM parameter real m=1 from(0:inf) (*units="" type="instance" ask="yes" info="multiplicity factor"*); |
|||
// `define TESTGIVEN(parameter) $given(parameter) |
|||
// `define GIVEN(parameter,variable,true,false) \ |
|||
// begin \ |
|||
// if ($given(parameter)) \ |
|||
// variable = true; \ |
|||
// else \ |
|||
// variable = false; \ |
|||
// end |
|||
// `define SCALE \ |
|||
// begin \ |
|||
// if ($given(scale)) \ |
|||
// scaleFac = scale; \ |
|||
// else \ |
|||
// scaleFac = $scale; \ |
|||
// end |
|||
// `define SHRINKL \ |
|||
// begin \ |
|||
// if ($given(shrink)) \ |
|||
// shrinkL = 1.0-0.01*shrink; \ |
|||
// else \ |
|||
// shrinkL = $shrinkl("m"); \ |
|||
// end |
|||
// `define RTHRESH rthrR2 = rthresh; |
|||
// `else // notInsideADMS |
|||
// `define ERROR(str) \ |
|||
// begin \ |
|||
// $strobe(str); \ |
|||
// $finish(1); \ |
|||
// end |
|||
// `define WARNING(str) $strobe(str); |
|||
// `define OPP(nam,uni,des) real nam; |
|||
// `define MPRcc(nam,def,uni,lwr,upr,des) parameter real nam=def from[lwr:upr]; |
|||
// `define MPRco(nam,def,uni,lwr,upr,des) parameter real nam=def from[lwr:upr); |
|||
// `define MPRoc(nam,def,uni,lwr,upr,des) parameter real nam=def from(lwr:upr]; |
|||
// `define MPRoo(nam,def,uni,lwr,upr,des) parameter real nam=def from(lwr:upr); |
|||
// `define MPRnb(nam,def,uni, des) parameter real nam=def; |
|||
// `define MPIcc(nam,def,uni,lwr,upr,des) parameter integer nam=def from[lwr:upr]; |
|||
// `define MPIco(nam,def,uni,lwr,upr,des) parameter integer nam=def from[lwr:upr); |
|||
// `define MPIoc(nam,def,uni,lwr,upr,des) parameter integer nam=def from(lwr:upr]; |
|||
// `define MPIoo(nam,def,uni,lwr,upr,des) parameter integer nam=def from(lwr:upr); |
|||
// `define MPInb(nam,def,uni, des) parameter integer nam=def; |
|||
// `define IPRcc(nam,def,uni,lwr,upr,des) parameter real nam=def from[lwr:upr]; |
|||
// `define IPRco(nam,def,uni,lwr,upr,des) parameter real nam=def from[lwr:upr); |
|||
// `define IPRoc(nam,def,uni,lwr,upr,des) parameter real nam=def from(lwr:upr]; |
|||
// `define IPRoo(nam,def,uni,lwr,upr,des) parameter real nam=def from(lwr:upr); |
|||
// `define IPRnb(nam,def,uni, des) parameter real nam=def; |
|||
// `define IPIcc(nam,def,uni,lwr,upr,des) parameter integer nam=def from[lwr:upr]; |
|||
// `define IPIco(nam,def,uni,lwr,upr,des) parameter integer nam=def from[lwr:upr); |
|||
// `define IPIoc(nam,def,uni,lwr,upr,des) parameter integer nam=def from(lwr:upr]; |
|||
// `define IPIoo(nam,def,uni,lwr,upr,des) parameter integer nam=def from(lwr:upr); |
|||
// `define IPInb(nam,def,uni, des) parameter integer nam=def; |
|||
// `define IPM parameter real m=1 from(0:inf); |
|||
// `define TESTGIVEN(parameter) 1 |
|||
// `define GIVEN(parameter,variable,true,false) variable = true; |
|||
`define SCALE scaleFac = scale; |
|||
`define SHRINKL shrinkL = 1.0-0.01*shrink; |
|||
`define RTHRESH rthrR2 = rthresh; |
|||
// `endif |
|||
//`endif |
|||
@ -0,0 +1,898 @@ |
|||
`include "cmcModels.inc" |
|||
|
|||
// |
|||
// Set up two versions of the model (which is defined in the |
|||
// file r2_cmc_core.va), an isothermal model and an electrothermal model. |
|||
// |
|||
|
|||
//`define electroThermal |
|||
|
|||
`define LEVEL 1002 |
|||
`define GFORM // if GFORM is defined an I=V*g formulation is used, else a V=I*r formulation is used |
|||
`define VERSION 1.0 |
|||
`define REVISION 0.0 |
|||
|
|||
// |
|||
// r2[_et]_cmc: Compact Model Council (CMC) 2-terminal Resistor Model |
|||
// |
|||
// This is the 2-terminal resistor model developed by the resistor |
|||
// subcommittee of the CMC. The goal was to have a standard 2-terminal |
|||
// resistor model with standard parameter names and a standard, |
|||
// numerically well behaved nonlinearity model. |
|||
// |
|||
// The nonlinearity model is that proposed by Agere Systems |
|||
// (from Kausar Banoo, Kumud Singhal, and Hermann Gummel). |
|||
// |
|||
// A self-heating (electro-thermal) version is included via conditionals. |
|||
// It is anticipated that this will be provided as a separate |
|||
// form of the model (r2_et_cmc where "et" means electro-thermal) |
|||
// and the local temperature rise terminal will be made available |
|||
// optionally, this has been requested for resistors in power |
|||
// technologies. The non-self-heating form, r2_cmc, is expected to |
|||
// be available as a new level model (the level number assigned |
|||
// depending on what level models are already available within |
|||
// a simulator, the value of 2 used here is an example). |
|||
// |
|||
|
|||
// |
|||
// Version 1.0 |
|||
// Revision 0.0 |
|||
// Date 2005 Nov 12 |
|||
// Comments Model as approved at Oct 2005 CMC meeting |
|||
// - notes from Agere systems added to documentation |
|||
// |
|||
// Version 1.0 |
|||
// Revision 0.0_preview3 |
|||
// Date 2005 Oct 08 |
|||
// Comments Updates based on second round of comments |
|||
// - electrothermal model name changed to r2_et_cmc so the |
|||
// _cmc tag would be at the end |
|||
// - top-level calling structure changed to make addition |
|||
// of other models more structured, and have all information |
|||
// directly relevant to r2[_et]_cmc in this file |
|||
// - LEVEL and other parameters moved to this file rather than |
|||
// the top-level file for the same reason, and LEVEL was |
|||
// set to the value 1002 |
|||
// - single line if statements have begin ... end added for safety |
|||
// and consistency of style |
|||
// - linear TC added for flicker noise coefficient |
|||
// - notes and documentation added that |
|||
// tc1, tc2, c1, c2, isnoisy |
|||
// should be both instance and model parameters |
|||
// - tc1e and tc2e (the effective temperature coefficients of resistance) |
|||
// were updated to include a width dependence and to |
|||
// have a length dependence that varies with c1 and c2 |
|||
// - added an instance parameter switch sw_et to enable the self-heating |
|||
// model to be turned off |
|||
// - added min and max parameters for length and width, and if |
|||
// a drawn geometry is outside these limits then a warning is issued |
|||
// - handling of tmin and tmax changed: |
|||
// specific clipping limits added (used for self-heating) |
|||
// warnings added if ambient temperature is outside the limits |
|||
// clipping of temperature to limits changed to be smooth |
|||
// - temperature coefficient of resistance clamped smoothly |
|||
// rather than having a hard limit |
|||
// |
|||
// Version 1.0 |
|||
// Revision 0.0_preview2 |
|||
// Date 2005 Sep 02 |
|||
// Comments Updates based on first round of comments |
|||
// - changed name to r2_cmc from cmc_r2 |
|||
// - fixed up improperly defined variables |
|||
// - modified some names for consistency with documentation |
|||
// - set up a top-level file that up both |
|||
// isoThermal and electroThermal versions are defined |
|||
// - set switch to resistance form to be done based on |
|||
// resistance at tnom, so the form does not change |
|||
// during a temperature sweep |
|||
// - fixed errors in LRM2.2 code |
|||
// |
|||
// Version 1.0 |
|||
// Revision 0.0_preview1 |
|||
// Date 2005 Jul 01 |
|||
// Comments Initial code for review by CMC resistor subcommittee |
|||
// |
|||
|
|||
// |
|||
// Instance parameters are: |
|||
// m multiplicity factor (number in parallel, implicit for LRM2.2) |
|||
// w design width of resistor body |
|||
// l design length of resistor body |
|||
// r resistance (per segment, total resistance is r/m) |
|||
// c1 contact at terminal 1: 0=no 1=yes |
|||
// c2 contact at terminal 2: 0=no 1=yes |
|||
// trise local temperature delta to ambient (before self-heating) |
|||
// isnoisy switch for noise: 0=no 1=yes |
|||
// |
|||
|
|||
// |
|||
// The c1 and c2 parameters control the addition of "end" effects |
|||
// to the model. If these are both zero ("no contact") then no end |
|||
// effects are added. If only one is non-zero 1/2 the end effects are |
|||
// added. If both are non-zero full end effects are added. This |
|||
// is to facilitate the implementation of multi-section models in a |
|||
// subckt. c1=c2=0 for all internal sections, c1=0,c2=1 for the |
|||
// "left" end segment, c1=1,c2=0 for the "right" end segment. |
|||
// |
|||
// The basic nonlinearity is: |
|||
// |
|||
// R=R0*(1-p2-p3+p2*sqrt(1+(q2*E)**2)+p3*cbrt(1+(q3*abs(E))**3)) |
|||
// |
|||
// where cbrt() is the cube root operation. The use |
|||
// of abs(E) leads to a singularity in higher order derivatives, |
|||
// but because of the power of the term it does not show up |
|||
// until the 4th derivative of the current. |
|||
// |
|||
// For q3*abs(E) somewhat greater than 1, the p3,q3 term |
|||
// leads a resistance factor of (1+p3*(q3*abs(E)-1)) so p3*q3 |
|||
// is in essence a first order field coefficient of |
|||
// resistance. |
|||
// For q2*E somewhat less than 1, the p2,q2 term leads to a |
|||
// resistance factor (1+0.5*p2*(q2*E)**2) so 0.5*p2*q2**2 is in essence |
|||
// a second order field coefficient of resistance. |
|||
// The bias dependent nonlinearity is done via field rather than voltage, |
|||
// to get reasonable scaling with length. |
|||
// |
|||
// There is no explicit handling of end resistances, they are assumed |
|||
// to be accounted for by xl. If there is a difference between the TC's |
|||
// of the end resistance compared to the body resistance, it can be shown that |
|||
// TC_overall=TC_body+Rend*(TC_end-TC_body)/(rsh*(L+xl)) |
|||
// therefore a 1/length term is included for the TCs to allow this effect |
|||
// to be modeled. |
|||
// |
|||
// Some Verilog-A compilers have difficulties handling the contrib type |
|||
// switch based on resistance value. Conditional switches have been |
|||
// put in this code to handle this for now. Comment out the `define GFORM |
|||
// line at the top to switch to the resistance form. |
|||
// |
|||
|
|||
// |
|||
// Usage with model: |
|||
// instanceId (n1 n2) modelName l=L w=W [trise=TRISE] [m] |
|||
// model modelName r[esistor] |
|||
// + level=assignedLevelForR2_CmcModel |
|||
// + param=value |
|||
// OR (for simulators that use model names rather than levels) |
|||
// model modelName r2_cmc |
|||
// + param=value |
|||
// (NOTE: specify any two of w,l,r and the other will be calculated). |
|||
// |
|||
// Usage without model: |
|||
// instanceId (n1 n2) r[esistor] r=value [trise=TRISE] [m] |
|||
// |
|||
// If this model is used with only r specified, then the geometry is taken |
|||
// to be w/l=1um/1um and these values are used for 1/f noise calculation. |
|||
// Note that this then means the 1/f noise is not geometry dependent, |
|||
// which is incorrect. For proper modeling of 1/f noise you |
|||
// should use the form where two of w,l,r are specified as instance parameters. |
|||
// |
|||
// The following parameters should be treated as model or instance parameters, |
|||
// with instance parameter specification over-riding model parameter specification: |
|||
// tc1 |
|||
// tc2 |
|||
// c1 |
|||
// c2 |
|||
// isnoisy |
|||
// There is no construct in Verilog-A for denoting this, but this should be |
|||
// implemented as such within a simulator. |
|||
// |
|||
|
|||
// |
|||
// Verilog-A Notes: |
|||
// |
|||
// 1. It is expected that, to be able to handle small- and zero-value resistances, |
|||
// the model implementation will transform from an I=G*V form for higher resistance |
|||
// values to a V=I*R form for lower resistance values. The switch should be based |
|||
// on zero-bias resistance, not voltage (and, for the self-heating version temperature) |
|||
// dependent resistance, to avoid changing the model formulation during simulation. |
|||
// The "G" or "R" formulation should be determined once at set-up and kept from then on. |
|||
// The current and voltage calculations are separated from noise calculations, |
|||
// to partition code for implementation efficiency. This causes errors with some |
|||
// Verilog-A compilers, as they think the contribution type can switch between |
|||
// various parts of the code. Therefore the switch is done using the macro `GFORM, |
|||
// and commented equivalent Verilog-A code is included, to indicate the intent. |
|||
// |
|||
// 2. There is no way to implement the LRM2.2 $param_given() function in |
|||
// LRM2.1 code, the concept is not part of the language. Therefore the |
|||
// model ONLY works with w,l specified as instance parameters when run |
|||
// in an LRM2.1 compliant compiler. Also, although the "m" parameter is |
|||
// known for LRM2.2, it apparently still needs to be declared explicity |
|||
// as a model parameter. |
|||
// |
|||
// 3. When testing with the R form of the model, there are some differences in |
|||
// simulation results w.r.t. the G form of the model, which was used to generate |
|||
// the reference test results. These appear to be from slight differences in convergence. |
|||
// |
|||
// Apologies for the nested conditionals. It makes the code hard to read, but is |
|||
// needed as there are different possible forms (isothermal, electrothermal; |
|||
// conductance form, resistance form) as well as different syntax for different |
|||
// language versions. |
|||
// |
|||
// There is no `ifndef XXX in Verilog-A, the "notXXX" macros are defined for convenience. |
|||
// |
|||
|
|||
`ifdef electroThermal |
|||
`ifdef notElectroThermal |
|||
`undef notElectroThermal |
|||
`endif |
|||
`else |
|||
`define notElectroThermal |
|||
`endif |
|||
|
|||
`ifdef electroThermal |
|||
module r2_et_cmc(n1,n2); |
|||
`else |
|||
module r2_cmc(n1,n2); |
|||
`endif |
|||
//`ifdef insideADMS |
|||
// (* |
|||
// info="r2_cmc two-terminal resistor model" |
|||
// version="`VERSION" |
|||
// revision="`REVISION" |
|||
// spice:prefix="r" |
|||
// spice:level="`LEVEL" |
|||
// *) |
|||
//`endif |
|||
//; |
|||
|
|||
// |
|||
// Node definitions (if the self-heating modeling is selected, the |
|||
// local temperature rise node is internal, and not external) |
|||
// |
|||
|
|||
inout n1,n2; |
|||
electrical n1; |
|||
electrical n2; |
|||
`ifdef electroThermal |
|||
electrical dt; |
|||
`endif |
|||
|
|||
// |
|||
// Branch definitions |
|||
// |
|||
|
|||
branch (n1,n2) b_r; // resistance |
|||
branch (n1,n2) b_n; // separate definition for noise, which is always a current contribution |
|||
`ifdef electroThermal |
|||
branch (dt) b_rth; // thermal resistance |
|||
branch (dt) b_ith; // thermal generation, 2nd definition is to fool floating node detection in some compilers |
|||
`endif |
|||
|
|||
// |
|||
// Instance parameters |
|||
// |
|||
|
|||
`IPM |
|||
`IPRco( w , 1.0e-06,"m" , 0.0, inf, "design width of resistor body") |
|||
`IPRco( l , 1.0e-06,"m" , 0.0, inf, "design length of resistor body") |
|||
`IPRco( r , 100.0 ,"Ohm" , 0.0, inf, "resistance (per segment, total resistance is r/m)") |
|||
`IPIcc( c1 , 1 ,"" , 0, 1, "contact at terminal 1: 0=no 1=yes") |
|||
`IPIcc( c2 , 1 ,"" , 0, 1, "contact at terminal 2: 0=no 1=yes") |
|||
`IPRnb( trise , 0.0 ,"degC" , "local temperature delta to ambient (before self-heating)") |
|||
`IPIcc( isnoisy , 1 ,"" , 0, 1, "switch for noise: 0=no and 1=yes") |
|||
`ifdef electroThermal |
|||
`IPIcc( sw_et , 1 ,"" , 0, 1, "switch for turning off self-heating: 0=exclude and 1=include") |
|||
`endif |
|||
|
|||
// |
|||
// Special model parameters, some may be simulator global parameters |
|||
// |
|||
|
|||
`MPRnb( version , `VERSION ,"" , "model version") |
|||
`MPRnb( revision, `REVISION,"" , "model revision (subversion)") |
|||
`MPRoc( scale , 1.0 ,"" , 0.0, 1.0, "scale factor for instance geometries") |
|||
`MPRco( shrink , 0.0 ,"%" , 0.0, 100.0, "shrink percentage for instance geometries") |
|||
`MPRcc( tmin ,-100.0 ,"degC" ,-250.0, 27.0, "minimum ambient temperature") |
|||
`MPRcc( tmax , 500.0 ,"degC" , 27.0,1000.0, "maximum ambient temperature") |
|||
`MPRoo( rthresh , 1.0e-03,"Ohm" , 0.0, inf, "threshold to switch to resistance form") |
|||
|
|||
// |
|||
// Model parameters |
|||
// |
|||
|
|||
`MPRnb( level , `LEVEL ,"" , "model level") |
|||
`MPRcc( tnom , 27.0 ,"degC" ,-250.0,1000.0, "nominal (reference) temperature") |
|||
`MPRoo( rsh , 100.0 ,"Ohm/sq" , 0.0, inf, "sheet resistance") |
|||
`MPRco( lmin , 0.0 ,"um" , 0.0, inf, "minimum allowed drawn length") |
|||
`MPRoo( lmax , 9.9e09 ,"um" , 0.0, inf, "maximum allowed drawn length") |
|||
`MPRco( wmin , 0.0 ,"um" , 0.0, inf, "minimum allowed drawn width") |
|||
`MPRoo( wmax , 9.9e09 ,"um" , 0.0, inf, "maximum allowed drawn width") |
|||
`MPRnb( xw , 0.0 ,"um" , "width offset (total)") |
|||
`MPRnb( xl , 0.0 ,"um" , "length offset (total)") |
|||
`MPRnb( dxle , 0.0 ,"um" , "length delta for field calculation") |
|||
`MPIcc( sw_efgeo, 0 ,"" , 0, 1, "switch for electric field geometry calculation: 0=design and 1=effective") |
|||
`MPRco( q3 , 0.0 ,"um/V" , 0.0, inf, "1/field at which the linear field coefficient activates") |
|||
`MPRco( p3 , 0.0 ,"" , 0.0, 1.0, "linear field coefficient factor: EC1=p3*q3") |
|||
`MPRco( q2 , 0.0 ,"um/V" , 0.0, inf, "1/field at which the quadratic field coefficient activates") |
|||
`MPRco( p2 , 0.0 ,"" , 0.0,1.0-p3, "quadratic field coefficient factor: EC2=0.5*p2*q2^2") |
|||
`MPRco( kfn , 0.0 ,"" , 0.0, inf, "flicker noise coefficient (unit depends on afn)") |
|||
`MPRoo( afn , 2.0 ,"" , 0.0, inf, "flicker noise current exponent") |
|||
`MPRoo( bfn , 1.0 ,"" , 0.0, inf, "flicker noise 1/f exponent") |
|||
`MPIcc( sw_fngeo, 0 ,"" , 0, 1, "switch for flicker noise geometry calculation: 0=design and 1=effective") |
|||
`MPRoo( jmax , 100.0 ,"A/um" , 0.0, inf, "maximum current density") |
|||
`MPRcc( tminclip,-100.0 ,"degC" ,-250.0, 27.0, "clip minimum temperature") |
|||
`MPRcc( tmaxclip, 500.0 ,"degC" , 27.0,1000.0, "clip maximum temperature") |
|||
`MPRnb( tc1 , 0.0 ,"/K" , "resistance linear TC") |
|||
`MPRnb( tc2 , 0.0 ,"/K^2" , "resistance quadratic TC") |
|||
`MPRnb( tc1l , 0.0 ,"um/K" , "resistance linear TC length coefficient") |
|||
`MPRnb( tc2l , 0.0 ,"um/K^2" , "resistance quadratic TC length coefficient") |
|||
`MPRnb( tc1w , 0.0 ,"um/K" , "resistance linear TC width coefficient") |
|||
`MPRnb( tc2w , 0.0 ,"um/K^2" , "resistance quadratic TC width coefficient") |
|||
`MPRnb( tc1kfn , 0.0 ,"" , "flicker noise coefficient linear TC") |
|||
`ifdef electroThermal |
|||
`MPRoo( gth0 , 1.0e+06,"W/K" , 0.0, inf, "thermal conductance fixed component") |
|||
`MPRco( gthp , 0.0 ,"W/K/um" , 0.0, inf, "thermal conductance perimeter component") |
|||
`MPRco( gtha , 0.0 ,"W/K/um^2" , 0.0, inf, "thermal conductance area component") |
|||
`MPRco( cth0 , 0.0 ,"s*W/K" , 0.0, inf, "thermal capacitance fixed component") |
|||
`MPRco( cthp , 0.0 ,"s*W/K/um" , 0.0, inf, "thermal capacitance perimeter component") |
|||
`MPRco( ctha , 0.0 ,"s*W/K/um^2", 0.0, inf, "thermal capacitance area component") |
|||
`endif |
|||
|
|||
// |
|||
// Supported aliases for parameters |
|||
// |
|||
|
|||
`ALIAS(dtemp,trise) |
|||
`ALIAS(dta,trise) |
|||
|
|||
// |
|||
// These variables will be displayed as part of operating point information. |
|||
// |
|||
|
|||
`OPP( v_OP ,"V" ,"voltage across resistor") |
|||
`OPP( i_OP ,"A" ,"current through resistor") |
|||
`OPP( power_OP ,"W" ,"dissipated power") |
|||
`OPP( leff ,"um" ,"effective electrical length in um") |
|||
`OPP( weff ,"um" ,"effective electrical width in um") |
|||
`OPP( r0_OP ,"Ohm" ,"zero-bias resistance (per segment)") |
|||
`OPP( r_dc_OP ,"Ohm" ,"DC resistance (including bias dependence and m)") |
|||
`OPP( r_ac_OP ,"Ohm" ,"AC resistance (including bias dependence and m)") |
|||
`ifdef electroThermal |
|||
`OPP( rth ,"K/W" ,"thermal resistance") |
|||
`OPP( cth ,"s*W/K","thermal capacitance") |
|||
`OPP( dt_et ,"K" ,"self-heating temperature rise") |
|||
`endif |
|||
|
|||
`ifdef notInsideADMS |
|||
analog begin : analogBlock |
|||
`endif |
|||
|
|||
real i, v, power, r0, weff_um, leff_um, r_dc, r_ac; |
|||
|
|||
real tiniK,tdevK,scaleFac,shrinkL,delt,tcr,xleff; |
|||
real lFactor,l_um,w_um,l_umForE,g0,r0_t,g0_t,kfn_t; |
|||
real sqrf,cbrf,tdevC,wn,fn,rthrR2; |
|||
real rFactor,vin,E,q2E,q3E,tc1e,tc2e; |
|||
integer GFORM; |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
`ifdef GFORM |
|||
real g_ac; |
|||
`else |
|||
real drfdv; |
|||
`endif |
|||
`else |
|||
real drfdv,g_ac; |
|||
`endif |
|||
`ifdef electroThermal |
|||
real gth,Vrth,Ith,Irth,Qcth,p_um,a_um2,dg0dt,tmp1; |
|||
`endif |
|||
|
|||
// |
|||
// Code independent of bias or instance parameters |
|||
// |
|||
|
|||
`ifdef insideADMS |
|||
analog begin |
|||
@(initial_instance) begin |
|||
`else |
|||
begin : initializeModel |
|||
`endif |
|||
if (level!=`LEVEL) begin |
|||
`ERROR("ERROR: r2 model called with incorrect level parameter") |
|||
end |
|||
`SCALE |
|||
`SHRINKL |
|||
`RTHRESH |
|||
lFactor = shrinkL*scaleFac*1.0e6; // conversion factor from instance l to um |
|||
tiniK = `TABS_NIST2004+tnom; |
|||
tdevC = $temperature+trise-`TABS_NIST2004; // device temperature |
|||
if (tdevC<tmin) begin |
|||
`WARNING("WARNING: ambient temperature is lower than allowed minimum"); |
|||
end |
|||
if (tdevC>tmax) begin |
|||
`WARNING("WARNING: ambient temperature is higher than allowed maximum"); |
|||
end |
|||
`ifdef notElectroThermal |
|||
`CLIPB1p0(tdevC,tdevC,tminclip,tmaxclip); |
|||
tdevK = tdevC+`TABS_NIST2004; |
|||
delt = tdevK-tiniK; // temperature w.r.t. tnom |
|||
kfn_t = (1+delt*tc1kfn)*kfn; |
|||
if (kfn_t<0.0) begin |
|||
kfn_t = 0.0; |
|||
end |
|||
`endif |
|||
// end // initializeModel |
|||
|
|||
// |
|||
// Code independent of bias but dependent on instance parameters |
|||
// |
|||
|
|||
//`ifdef insideADMS |
|||
// @(initial_instance) begin |
|||
//`else |
|||
// begin : initializeInstance |
|||
//`endif |
|||
if (c1&&c2) begin |
|||
xleff = xl; // contacted at both ends, use full xl |
|||
end else if (c1||c2) begin |
|||
xleff = xl*0.5; // contacted at one end, include 1/2 of xl effect |
|||
end else begin |
|||
xleff = 0.0; // not contacted |
|||
end |
|||
|
|||
// |
|||
// For geometric processing, the order of importance is taken to be |
|||
// w,l,r. The evaluation of whether a V contrib should be used, for |
|||
// low resistance, rather than the usual I contrib, is based on |
|||
// calculations at nominal temperature and zero bias, and so will |
|||
// not cause a formulation switch with bias. The cases where |
|||
// conductance or resistance are zero is handled. |
|||
// |
|||
|
|||
if (`TESTGIVEN(l)&&`TESTGIVEN(r)&&!`TESTGIVEN(w)) begin |
|||
|
|||
// |
|||
// If l and r are specified, but w is not, then calculate w |
|||
// (if w is also specified, this over-rides the specified r) |
|||
// |
|||
|
|||
if (r==0.0||l==0.0) begin |
|||
l_um = 0.0; |
|||
leff_um = 0.0; |
|||
w_um = w*lFactor; |
|||
weff_um = w_um+xw; // this could be negative, but has no effect so is not flagged as `ERROR |
|||
r0 = 0.0; |
|||
g0 = 1.0e99; // cannot set to inf |
|||
end else begin |
|||
l_um = l*lFactor; |
|||
leff_um = l_um+xleff; |
|||
if (leff_um<0.0) begin |
|||
`ERROR("ERROR: calculated effective r2_cmc resistor length is < 0.0") |
|||
end |
|||
if (leff_um>0.0) begin |
|||
weff_um = (rsh/r)*leff_um; |
|||
w_um = weff_um-xw; |
|||
if (w_um<=0.0) begin |
|||
`ERROR("ERROR: calculated design r2_cmc resistor width is <= 0.0") |
|||
end |
|||
r0 = r; |
|||
g0 = 1.0/r0; |
|||
end else begin |
|||
w_um = w*lFactor; |
|||
weff_um = w_um+xw; // this could be negative, but has no effect so is not flagged as `ERROR |
|||
r0 = 0.0; |
|||
g0 = 1.0e99; // cannot set to inf |
|||
end |
|||
end |
|||
end else if (`TESTGIVEN(r)&&!`TESTGIVEN(l)) begin |
|||
|
|||
// |
|||
// If r is specified, but l is not, calculate l based on either |
|||
// a specified or the default w (it does not matter which), |
|||
// this also handles the case of usage without a .model card |
|||
// |
|||
|
|||
if (r==0.0) begin |
|||
l_um = 0.0; |
|||
leff_um = 0.0; |
|||
w_um = w*lFactor; |
|||
weff_um = w_um+xw; // this could be negative, but has no effect so is not flagged as `ERROR |
|||
r0 = 0.0; |
|||
g0 = 1.0e99; // cannot set to inf |
|||
end else if (w==0.0) begin |
|||
w_um = 0.0; |
|||
weff_um = 0.0; |
|||
l_um = l*lFactor; |
|||
leff_um = l_um+xleff; // this could be negative, but has no effect so is not flagged as `ERROR |
|||
r0 = 1.0e99; // cannot set to inf |
|||
g0 = 0.0; |
|||
end else begin |
|||
w_um = w*lFactor; |
|||
weff_um = w_um+xw; |
|||
if (weff_um<0.0) begin |
|||
`ERROR("ERROR: calculated effective r2_cmc resistor width is < 0.0") |
|||
end |
|||
if (weff_um>0.0) begin |
|||
leff_um = (r/rsh)*weff_um; |
|||
l_um = leff_um-xleff; |
|||
if (l_um<=0.0) begin |
|||
`ERROR("ERROR: calculated design r2_cmc resistor length is <= 0.0") |
|||
end |
|||
r0 = r; |
|||
g0 = 1.0/r0; |
|||
end else begin |
|||
l_um = l*lFactor; |
|||
leff_um = l_um+xleff; // this could be negative, but has no effect so is not flagged as `ERROR |
|||
r0 = 1.0e99; // cannot set to inf |
|||
g0 = 0.0; |
|||
end |
|||
end |
|||
end else begin |
|||
|
|||
// |
|||
// For all other cases, r is calculated as a function of |
|||
// geometry, either specified or default. Either l and w |
|||
// are both specified, in which case they over-ride |
|||
// specification of r, or else r is not specified. |
|||
// |
|||
|
|||
if (w==0.0) begin |
|||
w_um = 0.0; |
|||
weff_um = 0.0; |
|||
l_um = l*lFactor; |
|||
leff_um = l_um+xleff; // this could be negative, but has no effect so is not flagged as `ERROR |
|||
r0 = 1.0e99; // cannot set to inf |
|||
g0 = 0.0; |
|||
end else if (l==0.0) begin |
|||
l_um = 0.0; |
|||
leff_um = 0.0; |
|||
w_um = w*lFactor; |
|||
weff_um = w_um+xw; // this could be negative, but has no effect so is not flagged as `ERROR |
|||
r0 = 0.0; |
|||
g0 = 1.0e99; // cannot set to inf |
|||
end else begin |
|||
w_um = w*lFactor; |
|||
weff_um = w_um+xw; |
|||
if (weff_um<0.0) begin |
|||
`ERROR("ERROR: calculated effective r2_cmc resistor width is < 0.0") |
|||
end |
|||
l_um = l*lFactor; |
|||
leff_um = l_um+xleff; |
|||
if (weff_um>0.0) begin |
|||
if (leff_um<0.0) begin |
|||
`ERROR("ERROR: calculated effective r2_cmc resistor length is < 0.0") |
|||
end |
|||
if (leff_um>0.0) begin |
|||
r0 = rsh*(leff_um/weff_um); |
|||
g0 = 1.0/r0; |
|||
end else begin |
|||
r0 = 0.0; |
|||
g0 = 1.0e99; // cannot set to inf |
|||
end |
|||
end else begin |
|||
r0 = 1.0e99; // cannot set to inf, also don't need to check if(leff_um>0.0) for this case |
|||
g0 = 0.0; |
|||
end |
|||
end |
|||
end |
|||
if (l_um<lmin) begin |
|||
`WARNING("WARNING: drawn length is smaller than allowed minimum"); |
|||
end |
|||
if (l_um>lmax) begin |
|||
`WARNING("WARNING: drawn length is greater than allowed maximum"); |
|||
end |
|||
if (w_um<wmin) begin |
|||
`WARNING("WARNING: drawn width is smaller than allowed minimum"); |
|||
end |
|||
if (w_um>wmax) begin |
|||
`WARNING("WARNING: drawn width is greater than allowed maximum"); |
|||
end |
|||
if (sw_efgeo) begin |
|||
l_umForE = leff_um+dxle; |
|||
end else begin |
|||
l_umForE = l_um+dxle; |
|||
end |
|||
if (l_umForE<=0.0&&r0>0.0&&(p2>0.0||p3>0.0)) begin |
|||
`ERROR("ERROR: calculated effective r2_cmc resistor length for E calculation is < 0.0") |
|||
end |
|||
tc1e = tc1; |
|||
tc2e = tc2; |
|||
if (leff_um>0.0) begin |
|||
if (c1&&c2) begin |
|||
tc1e = tc1e+tc1l/leff_um; |
|||
tc2e = tc2e+tc2l/leff_um; |
|||
end else if (c1||c2) begin |
|||
tc1e = tc1e+0.5*tc1l/leff_um; |
|||
tc2e = tc2e+0.5*tc2l/leff_um; |
|||
end |
|||
end |
|||
if (weff_um>0.0) begin |
|||
tc1e = tc1e+tc1w/weff_um; |
|||
tc2e = tc2e+tc2w/weff_um; |
|||
end |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
if (r0>(rthrR2/$mfactor)) begin |
|||
`else |
|||
if (r0>(rthrR2/m)) begin |
|||
`endif |
|||
GFORM = 1; |
|||
end else begin |
|||
GFORM = 0; |
|||
end |
|||
`ifdef electroThermal |
|||
if (c1&&c2) begin |
|||
p_um = 2.0*(l_um+w_um); |
|||
end else if (c1||c2) begin |
|||
p_um = 2.0*l_um+w_um; |
|||
end else begin |
|||
p_um = 2.0*l_um; |
|||
end |
|||
a_um2 = l_um*w_um; |
|||
gth = gth0+gthp*p_um+gtha*a_um2; |
|||
cth = cth0+cthp*p_um+ctha*a_um2; |
|||
`else // notElectroThermal |
|||
tcr = (1+delt*(tc1e+delt*tc2e)); |
|||
`CLIPL0p1(tcr,tcr,0.01) |
|||
r0_t = r0*tcr; |
|||
g0_t = g0/tcr; |
|||
`endif |
|||
end // initialInstance |
|||
|
|||
// |
|||
// DC bias dependent quantities |
|||
// |
|||
// Note that for the resistance form the expression for v(i) |
|||
// is implicit in v because of the voltage dependence of conductance. |
|||
// For efficiency the nonlinearity is not computed if the |
|||
// field coefficients are zero. |
|||
// |
|||
|
|||
begin : evaluateStatic |
|||
`ifdef electroThermal |
|||
Vrth = sw_et*V(b_rth); |
|||
tdevC = tdevC+Vrth; |
|||
`CLIPB1p0(tdevC,tdevC,tminclip,tmaxclip); |
|||
tdevK = tdevC+`TABS_NIST2004; |
|||
delt = tdevK-tiniK; // temperature w.r.t. tnom |
|||
tcr = (1+delt*(tc1e+delt*tc2e)); |
|||
`CLIPL0p1(tcr,tcr,0.01) |
|||
r0_t = r0*tcr; |
|||
g0_t = g0/tcr; |
|||
kfn_t = (1+delt*tc1kfn)*kfn; |
|||
if (kfn_t<0.0) begin |
|||
kfn_t = 0.0; |
|||
end |
|||
`endif |
|||
vin = V(b_r); |
|||
if (r0>0.0&&(p2>0.0||p3>0.0)) begin |
|||
E = vin/l_umForE; |
|||
q2E = q2*E; |
|||
sqrf = sqrt(1.0+q2E*q2E); |
|||
q3E = q3*abs(E); |
|||
cbrf = pow((1.0+q3E*q3E*q3E),`oneThird); |
|||
rFactor = 1.0-p2-p3+p2*sqrf+p3*cbrf; |
|||
end else |
|||
rFactor = 1.0; |
|||
r_dc = r0_t*rFactor; |
|||
`ifdef GFORM // if (GFORM) begin |
|||
v = vin; |
|||
i = v/r_dc; |
|||
`else // end else begin // RFORM |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
i = I(b_r); |
|||
`else |
|||
i = I(b_r)/m; // need per-segment value |
|||
`endif |
|||
v = i*r_dc; |
|||
`endif // end |
|||
`ifdef electroThermal |
|||
Ith = -v*i; // power generation, negative as it flows from dt to 0 |
|||
Irth = Vrth*gth; |
|||
`endif |
|||
if (weff_um>0.0) begin |
|||
if (abs(i/weff_um)>jmax) begin |
|||
`WARNING("WARNING: current density is greater than specified by jmax"); |
|||
end |
|||
end |
|||
end // evaluateStatic |
|||
|
|||
begin : evaluateDynamic |
|||
`ifdef electroThermal |
|||
Qcth = Vrth*cth; |
|||
`endif |
|||
end // evaluateDynamic |
|||
|
|||
begin : loadStatic |
|||
`ifdef GFORM // if (GFORM) begin |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
I(b_r) <+ i; |
|||
`else |
|||
I(b_r) <+ i*m; |
|||
`endif |
|||
`else // end else begin // RFORM |
|||
V(b_r) <+ v; |
|||
`endif // end |
|||
`ifdef electroThermal |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
I(b_rth) <+ Irth; |
|||
I(b_ith) <+ Ith; |
|||
`else |
|||
I(b_rth) <+ Irth*m; |
|||
I(b_ith) <+ Ith*m; |
|||
`endif |
|||
`endif |
|||
end // loadStatic |
|||
|
|||
begin : loadDynamic |
|||
`ifdef electroThermal |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
I(b_rth) <+ ddt(Qcth); |
|||
`else |
|||
I(b_rth) <+ ddt(Qcth*m); |
|||
`endif |
|||
`endif |
|||
end // loadDynamic |
|||
|
|||
// |
|||
// Noise contributions |
|||
// |
|||
|
|||
`ifdef insideADMS |
|||
@(noise) begin |
|||
`else |
|||
begin : noise |
|||
`endif |
|||
if (isnoisy&&r0>0.0&&g0>0.0) begin |
|||
wn = 4.0*`KB_NIST2004*tdevK*g0_t/rFactor; |
|||
if (sw_fngeo&&leff_um>0.0&&weff_um>0.0) begin |
|||
fn = kfn_t*pow(abs(i/weff_um),afn)*weff_um/leff_um; |
|||
end else if (l_um>0.0&&w_um>0.0) begin |
|||
fn = kfn_t*pow(abs(i/w_um),afn)*w_um/l_um; |
|||
end else begin |
|||
fn = 0.0; |
|||
end |
|||
end else begin |
|||
wn = 0.0; |
|||
fn = 0.0; |
|||
end |
|||
`ifdef not__VAMS_COMPACT_MODELING__ |
|||
wn = wn*m; |
|||
fn = fn*m; |
|||
`endif |
|||
I(b_n) <+ white_noise(wn,"white noise"); |
|||
I(b_n) <+ flicker_noise(fn,bfn,"1/f noise"); |
|||
end // noise |
|||
|
|||
// |
|||
// Useful quantities to display for OP and other purposes |
|||
// |
|||
// LRM2.2 allows use of ddx() which means explicit, hand-coded |
|||
// calculation of derivatives is not required. However for the |
|||
// electroThermal model the derivatives need to be calculated |
|||
// as the total derivative is required for display, not just |
|||
// the partial with respect to terminal voltages or branch |
|||
// currents (which is all that is available from ddx()). |
|||
// |
|||
// For: i=v*g0_t/rf(v) (where rf is a short-hand for rFactor) |
|||
// g_ac=di_dv=g0_t/rf-g0_t*v*drf_dv/rf^2=(g0_t-i*drf_dv)/rf |
|||
// |
|||
// For: v=i*r0_t*rf(v) |
|||
// r_ac=dv_di=r0_t*rf+i*r0_t*drf_dv*dv_di=ddx(v,I(b_r))+(v*drf_dv/rf)*r_ac |
|||
// therefore |
|||
// r_ac=ddx(v,I(b_r))/(1-v*drf_dv/rf) |
|||
// |
|||
// For the electroThermal conductance form model: |
|||
// i=v*g0(t)/rf(v) |
|||
// g0(t)=g0/tcr=g0/(1+delt*(tc1e+delt*tc2e)) |
|||
// delt=i*v/gth |
|||
// therefore |
|||
// ddelt_dv=i/gth+(v/gth)*di_dv |
|||
// dg0_dt=ddx(g0_t,V(dt))=g0(t)*(tc1e+2*delt*tc2e)/tcr |
|||
// di_dv=ddx(i,V(n1))+(v/rf)*dg0_dt*di_dv |
|||
// g_ac=(ddx(i,V(n1))+i*v*dg0_dt/(gth*rf))/(1-v*v*dg0_dt/(gth*rf)) |
|||
// which is what is implemented below. |
|||
// |
|||
// For the electroThermal resistance form model: |
|||
// v=i*r0(t)*rf(v) |
|||
// r0(t)=r0*tcr=r0*(1+delt*(tc1e+delt*tc2e)) |
|||
// delt=i*v/gth |
|||
// therefore |
|||
// ddelt_i=v/gth+(i/gth)*dv_di |
|||
// dr0_dt=ddx(r0_t,V(dt))=r0*(tc1e+2*delt*tc2e) |
|||
// dv_di=ddx(v,I(b_r))+i*r0*drf_dv*dv_di+i*rf*dr0_dt*ddelt_di |
|||
// r_ac=(ddx(v,I(b_r))+v*i*rf*dr0_dt/gth)/(1-v*drf_dv/rf-i*i*rf*dr0_dt/gth) |
|||
// which is what is implemented below. |
|||
// |
|||
|
|||
begin : postProcess |
|||
power = i*v; |
|||
if (r0>0.0&&g0>0.0) begin |
|||
r_dc = r0_t*rFactor; |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
`ifdef GFORM // if (GFORM) begin |
|||
g_ac = ddx(i,V(n1)); |
|||
`ifdef electroThermal |
|||
dg0dt = ddx(g0_t,V(dt)); |
|||
tmp1 = v*dg0dt/(gth*rFactor); |
|||
if ((1.0-v*tmp1)!=0.0) begin |
|||
g_ac = (g_ac+i*tmp1)/(1.0-v*tmp1); // denominator is zero in thermal runaway, cannot happen if tcr>0 |
|||
end else begin |
|||
g_ac = 1.0e99; |
|||
end |
|||
`endif |
|||
if (g_ac!=0.0) begin |
|||
r_ac = 1.0/g_ac; |
|||
end else begin |
|||
r_ac = 1.0e99; |
|||
end |
|||
`else // end else begin // RFORM |
|||
drfdv = ddx(rFactor,V(n1)); |
|||
`ifdef electroThermal |
|||
dg0dt = 1.0/ddx(r0_t,V(dt)); |
|||
tmp1 = i*rFactor/(dg0dt*gth); |
|||
if ((1.0-v*drfdv/rFactor-i*tmp1)!=0.0) begin |
|||
r_ac = (ddx(v,I(b_r))+v*tmp1)/(1.0-v*drfdv/rFactor-i*tmp1); |
|||
end else begin |
|||
r_ac = 1.0e99; |
|||
end |
|||
`else // notElectroThermal |
|||
r_ac = ddx(v,I(b_r))/(1.0-v*drfdv/rFactor); |
|||
`endif |
|||
`endif // end |
|||
`else // not__VAMS_COMPACT_MODELING__ |
|||
if ((p2>0.0||p3>0.0)) begin |
|||
if (vin>=0.0) |
|||
drfdv = (p2*q2*q2E/sqrf+p3*q3*q3E*q3E/(cbrf*cbrf))/l_umForE; |
|||
else |
|||
drfdv = (p2*q2*q2E/sqrf-p3*q3*q3E*q3E/(cbrf*cbrf))/l_umForE; |
|||
g_ac = (g0_t-i*drfdv)/rFactor; |
|||
end else |
|||
g_ac = 1.0/r_dc; |
|||
`ifdef electroThermal |
|||
dg0dt = -g0_t*(tc1e+2.0*delt*tc2e)/tcr; |
|||
tmp1 = v*dg0dt/(gth*rFactor); |
|||
if ((1.0-v*tmp1)!=0.0) begin |
|||
g_ac = (g_ac+i*tmp1)/(1.0-v*tmp1); // denominator is zero in thermal runaway, cannot happen if tcr>0 |
|||
end else begin |
|||
g_ac = 1.0e99; |
|||
end |
|||
`endif |
|||
if (g_ac!=0.0) begin |
|||
r_ac = 1.0/g_ac; |
|||
end else begin |
|||
r_ac = 1.0e99; |
|||
end |
|||
`endif |
|||
end else begin |
|||
r_dc = r0; // this is 1.0e99 if g0==0.0, cannot set to inf |
|||
r_ac = r0; // this is 1.0e99 if g0==0.0, cannot set to inf |
|||
end |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
// i = $mfactor*i; |
|||
// power = $mfactor*power; |
|||
// r_dc = r_dc/$mfactor; |
|||
// r_ac = r_ac/$mfactor; |
|||
i = 1*i; |
|||
power = 1*power; |
|||
r_dc = r_dc/1; |
|||
r_ac = r_ac/1; |
|||
`else // not__VAMS_COMPACT_MODELING__ |
|||
i = m*i; |
|||
power = m*power; |
|||
r_dc = r_dc/m; |
|||
r_ac = r_ac/m; |
|||
`endif |
|||
`ifdef electroThermal |
|||
dt_et = Vrth; |
|||
`ifdef __VAMS_COMPACT_MODELING__ |
|||
// rth = 1.0/(gth*$mfactor); |
|||
// cth = cth*$mfactor; |
|||
rth = 1.0/(gth*1); |
|||
cth = cth*1; |
|||
`else // not__VAMS_COMPACT_MODELING__ |
|||
rth = 1.0/(gth*m); |
|||
cth = cth*m; |
|||
`endif |
|||
`endif |
|||
power_OP = power; |
|||
v_OP = v; |
|||
i_OP = i; |
|||
r0_OP = r0; |
|||
weff = weff_um; |
|||
leff = leff_um; |
|||
r_dc_OP = r_dc; |
|||
r_ac_OP = r_ac; |
|||
end // postProcess |
|||
|
|||
end // analog |
|||
endmodule |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue