From 08700f8147bd62bb5a9f7cea8103fde8bef78444 Mon Sep 17 00:00:00 2001 From: dwarning Date: Mon, 4 Jan 2021 18:58:09 +0100 Subject: [PATCH] include verilog-a r2_cmc resistor model --- configure.ac | 7 +- .../devices/adms/r2_cmc/admsva/cmcModels.inc | 250 +++++ .../devices/adms/r2_cmc/admsva/r2_cmc.va | 898 ++++++++++++++++++ src/spicelib/devices/dev.c | 2 + src/spicelib/parser/inp2r.c | 6 +- src/spicelib/parser/inpdomod.c | 26 +- 6 files changed, 1181 insertions(+), 8 deletions(-) create mode 100644 src/spicelib/devices/adms/r2_cmc/admsva/cmcModels.inc create mode 100644 src/spicelib/devices/adms/r2_cmc/admsva/r2_cmc.va diff --git a/configure.ac b/configure.ac index 9c11148e1..4242a55fb 100644 --- a/configure.ac +++ b/configure.ac @@ -1102,7 +1102,8 @@ if test "x$enable_adms" = xyes ; then adms/hicum0 \ adms/mextram \ adms/psp102 \ - adms/psp103 " + adms/psp103 \ + adms/r2_cmc " # The makefiles for adms (to be added to AC_CONFIG_FILES by ./autogen.sh --adms) #VLAMKF src/spicelib/devices/adms/bsimbulk/Makefile @@ -1112,6 +1113,7 @@ if test "x$enable_adms" = xyes ; then #VLAMKF src/spicelib/devices/adms/mextram/Makefile #VLAMKF src/spicelib/devices/adms/psp102/Makefile #VLAMKF src/spicelib/devices/adms/psp103/Makefile +#VLAMKF src/spicelib/devices/adms/r2_cmc/Makefile NOTVLADEVDIR="" @@ -1121,7 +1123,8 @@ if test "x$enable_adms" = xyes ; then spicelib/devices/adms/hicum0/libhicum0.la \ spicelib/devices/adms/mextram/libbjt504t.la \ spicelib/devices/adms/psp102/libpsp102.la \ - spicelib/devices/adms/psp103/libpsp103.la " + spicelib/devices/adms/psp103/libpsp103.la \ + spicelib/devices/adms/r2_cmc/libr2_cmc.la " else diff --git a/src/spicelib/devices/adms/r2_cmc/admsva/cmcModels.inc b/src/spicelib/devices/adms/r2_cmc/admsva/cmcModels.inc new file mode 100644 index 000000000..9993f0576 --- /dev/null +++ b/src/spicelib/devices/adms/r2_cmc/admsva/cmcModels.inc @@ -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 diff --git a/src/spicelib/devices/adms/r2_cmc/admsva/r2_cmc.va b/src/spicelib/devices/adms/r2_cmc/admsva/r2_cmc.va new file mode 100644 index 000000000..c225268ec --- /dev/null +++ b/src/spicelib/devices/adms/r2_cmc/admsva/r2_cmc.va @@ -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 (tdevCtmax) 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_umlmax) begin + `WARNING("WARNING: drawn length is greater than allowed maximum"); + end + if (w_umwmax) 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 diff --git a/src/spicelib/devices/dev.c b/src/spicelib/devices/dev.c index 6da4e4b3a..688550265 100644 --- a/src/spicelib/devices/dev.c +++ b/src/spicelib/devices/dev.c @@ -133,6 +133,7 @@ extern struct coreInfo_t coreInfo; /* cmexport.c */ #include "adms/psp103/psp103itf.h" #include "adms/bsimbulk/bsimbulkitf.h" #include "adms/bsimcmg/bsimcmgitf.h" +#include "adms/r2_cmc/r2_cmcitf.h" #endif #ifdef CIDER /* Numerical devices (Cider integration) */ @@ -217,6 +218,7 @@ static SPICEdev *(*static_devices[])(void) = { (SPICEdev *(*)(void)) get_psp103_info, (SPICEdev *(*)(void)) get_bsimbulk_info, (SPICEdev *(*)(void)) get_bsimcmg_info, + (SPICEdev *(*)(void)) get_r2_cmc_info, #endif #ifdef NDEV diff --git a/src/spicelib/parser/inp2r.c b/src/spicelib/parser/inp2r.c index c4972f3fa..7bdb6e239 100644 --- a/src/spicelib/parser/inp2r.c +++ b/src/spicelib/parser/inp2r.c @@ -51,7 +51,11 @@ void INP2R(CKTcircuit *ckt, INPtables * tab, struct card *current) #endif if (mytype < 0) { - if ((mytype = INPtypelook("Resistor")) < 0) { + if ((mytype = INPtypelook("Resistor")) < 0 +#ifdef ADMS + || (mytype = INPtypelook("r2_cmc")) < 0 +#endif + ){ LITERR("Device type Resistor not supported by this binary\n"); return; } diff --git a/src/spicelib/parser/inpdomod.c b/src/spicelib/parser/inpdomod.c index 9d0404e85..f4a30ce35 100644 --- a/src/spicelib/parser/inpdomod.c +++ b/src/spicelib/parser/inpdomod.c @@ -469,11 +469,27 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab) #endif /* -------- Check if model is a resistor --------- */ else if (strcmp(type_name, "r") == 0) { - type = INPtypelook("Resistor"); - if (type < 0) { - err = - INPmkTemp - ("Device type Resistor not available in this binary\n"); + err = INPfindLev(line,&lev); + switch(lev) { + case 0: + case 1: + default: + type = INPtypelook("Resistor"); + if (type < 0) { + err = + INPmkTemp + ("Device type Resistor not available in this binary\n"); + } + break; +#ifdef ADMS + case 2: + type = INPtypelook("r2_cmc"); + if (type < 0) { + err = INPmkTemp( + "Device type R2_CMC not available in this binary\n"); + } + break; +#endif } INPmakeMod(modname, type, image); }