include verilog-a r2_cmc resistor model

This commit is contained in:
dwarning 2021-01-04 18:58:09 +01:00 committed by Holger Vogt
parent b654296230
commit 08700f8147
6 changed files with 1181 additions and 8 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}