Merge branch 'pre-master-45' into bt_dev

This commit is contained in:
Brian Taylor 2025-07-15 13:27:12 -07:00
commit 11d560ed64
111 changed files with 12565 additions and 7182 deletions

192
README.SEEgenerator Normal file
View File

@ -0,0 +1,192 @@
SEE (single event effects) generator
The SEE generator generates current pulses, which resemble the
charge generation and flow causes by a penetrating particle.
How to use it:
Select LET and charge collection depth cdepth, define them as parameters.
Identify all nodes of a circuit netlist which are pn junctions,
and thus are sensitive to pulses.
Set up the SEEgenerator by adding for example
* charge collection depth (in µm)
.param d = 1
* LET (linear energy transfer) in MeV*cm²/mg
.param let = 12
aseegen1 NULL mon [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1
.model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='d')
to the netlist.
Each sensitive node from the (flattend) netlist may be added to the output vector of assegen1
(in brackets [...]), together with its reference node, for example GND for NMOS, nwell potential
for PMOS. This procedure is currently to be done manually, a semi-automated setup using
a GUI is in preparation.
Instead of NULL, one may give a control signal to aseegen1, to start the pulse sequence.
'mon' is a monitoring output, showing each pulse as a voltage equivalent to the current.
After a transient simulation, plotting the data output versus a non-radiated device
may reveal the SEE influence.
Several examples are gieven in ./src/axamples/xspice/see: inverters, SRAM cell, opamp,
also as loop with varying LET to detect the threshold.
As literature please see for example
Ygor Quadros de Aguiar, Frédéric Wrobel. Jean-Luc Autran, Rubén García Alía
Single-Event Effects, from Space to Accelerator Environments
Springer 2025
Detailed description (will be added to the manual):
NAME_TABLE:
C_Function_Name: cm_seegen
Spice_Model_Name: seegen
Description: "single event effect generator"
PORT_TABLE:
Port_Name: ctrl mon
Description: "control input" "monitor"
Direction: in out
Default_Type: v v
Allowed_Types: [v,vd,i,id] [v]
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PORT_TABLE:
Port_Name: out
Description: "output"
Direction: out
Default_Type: i
Allowed_Types: [i,id]
Vector: yes
Vector_Bounds: [1 -]
Null_Allowed: no
PARAMETER_TABLE:
Parameter_Name: tfall trise
Description: "pulse fall time" "pulse rise time"
Data_Type: real real
Default_Value: 500e-12 20e-12
Limits: - -
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: tdelay inull
Description: "pulse delay" "max current"
Data_Type: real real
Default_Value: 0 0
Limits: - -
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: tperiod ctrlthres
Description: "pulse repetition" "control voltage threshold"
Data_Type: real real
Default_Value: 0 0.5
Limits: - -
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: let cdepth
Description: "lin energy transfer" "charge collection depth"
Data_Type: real real
Default_Value: 10 1
Limits: - -
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
PARAMETER_TABLE:
Parameter_Name: angle perlim
Description: "particle angle" "pulse repetition"
Data_Type: real boolean
Default_Value: 0 TRUE
Limits: [0 1.57079] -
Vector: no no
Vector_Bounds: - -
Null_Allowed: yes yes
STATIC_VAR_TABLE:
Static_Var_Name: last_t_value
Data_Type: pointer
Vector: no
Description: "next pulse start time"
STATIC_VAR_TABLE:
Static_Var_Name: pulse_number
Data_Type: pointer
Vector: no
Description: "number of pulse"
STATIC_VAR_TABLE:
Static_Var_Name: last_ctrl
Data_Type: pointer
Vector: no
Description: "last control value"
Description
This code model generates "double exponentially" formed current pulses according to
i(t) = inull * (exp(-(t-tdelay)/tfall) - (exp(-(t-tdelay)/trise) for t > tdelay
i(t) = 0 for t < tdelay
with inull given as parameter input or (if not given), calculated as
inull = 1.035e-14 * let/cos(angle) * cdepth / (tfall - trise)
with data for silicon, cdepth in µm, let in MeV*cm²/mg, angle in radians.
Minimum is one pulse output (a node pair, or a single node with the other grounded).
Several output node pairs may be defined per code model instance. Parameter tperiod
may then be used to create pulses in sequence. Per default only one sequence is running,
with one pulse for each node.
Parameter perlim, set to FALSE, allows running and repeating the sequence until
the end of the simulation. The first pulse is issued in the first
node pair of the node list in the vector [], the second (after time tperiod has elapsed),
is injected by the second node (pair) of the list and so on. When the sequence is repeated,
again the output starts pulsing at port (node pair) number 1.
The control input ctrl (voltage or current) may be used
to start or repeat the whole sequence, depending on the circuit status. A rising voltage
at ctrl, when crossing the threshold given by ctrlthres, will initiate the sequence (including
tdelay and tperiod). If set to NULL, the pulse (sequence) will start immediately after tdelay.
'mon' is a monitoring output, showing each pulse as a voltage equivalent to the current. It
may be used just for plotting, or for re-triggering an action.
This model will work in transient analysis.
Example ngspice usage (with control)
aseegen1 ctrl mon [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1
.model seemod1 seegen (tdelay = 8n tperiod=25n)
Example ngspice usage (without control, ctrl replaced by NULL, parameters as offered by default)
aseegen2 NULL mon [%id(n1 m1) %id(n5 n6) %id(n6 n7) %i(isingle) ] seemod2
.model seemod2 seegen (tdelay = 0 tperiod=0 ctrlthres=0.5 inull=0 tfall=500p trise=20p perlim=FALSE)

View File

@ -14,6 +14,19 @@ run
** evaluate '0.9*v(2)' in control language command
let vint = 0.9*v(2)
meas tran yeval2 FIND v(2) WHEN v(1)= vint
unlet vint
* new expression evaluation
meas tran yeval3 FIND v(2) WHEN v(1)= 0.9*v(2)
* standard meas with val being a number:
meas tran tdiff1 TRIG v(1) VAL=0.5 RISE=1 TARG v(1) VAL=0.5 RISE=3
* expression evaluation with vector of length 1 only:
let onevec = 1
meas tran tdiff2 TRIG v(1) VAL=onevec-0.5 RISE=1 TARG v(1) VAL=onevec/2 RISE=3
plot V(1) v(2)
.endc

View File

@ -0,0 +1,77 @@
** CMOS comparator ***
* Figure 27.12
* Baker: "CMOS: Circuit Design, Layout, and Simulation", Wiley, 2005
.param VCC = 5
.option scale=1u
.tran 9.5p 1600n
VDD VDD 0 DC {VCC}
Vp vp 0 DC 0 PULSE {VCC/2-0.1} {VCC/2+0.1} 30n 1n 1n 350n 700n
Vctrl ct 0 PULSE {VCC/2-0.2} {VCC/2+0.2} 270n 1n 1n 5n 350n
vm vm 0 DC {VCC/2}
X1 vbiasn vbiasp vdd bias
M1 n1 vp vss 0 N_1u L=1 W=10
M2 n2 vm vss 0 N_1u L=1 W=10
M3a vss vbiasn 0 0 N_1u L=2 W=20
M31 n1 n1 vdd vdd P_1u L=1 W=20
M41 n2 n2 vdd vdd P_1u L=1 W=20
M3 vop n1 vdd vdd P_1u L=1 W=20
M4 vom n2 vdd vdd P_1u L=1 W=20
M5 vop vop vc 0 N_1u L=1 W=10
M6 vop vom vc 0 N_1u L=1 W=10
M7 vom vop vc 0 N_1u L=1 W=10
M8 vom vom vc 0 N_1u L=1 W=10
Mc vc vc 0 0 N_1u L=10 W=10
M1P vopb vp vpp vdd P_1u L=1 W=20
M2P vomb vm vpp vdd P_1u L=1 W=20
M3p vpp vbiasp vdd vdd P_1u L=2 W=20
M4n vopb vopb 0 0 N_1u L=1 W=10
M5n n2 vopb 0 0 N_1u L=1 W=10
M6n vomb vomb 0 0 N_1u L=1 W=10
M7n n1 vomb 0 0 N_1u L=1 W=10
M1D vdp vbiasp vdd vdd P_1u L=1 W=20
M2D nd1 vom vdp vdd P_1u L=1 W=20
M3D vdo vop vdp vdd P_1u L=1 W=20
M4D nd1 nd1 0 0 N_1u L=1 W=10
M5D vdo nd1 0 0 N_1u L=1 W=10
MIN out vdo 0 0 N_1u L=1 W=10
MIP out vdo vdd vdd P_1u L=1 W=20
.subckt bias vbiasn vbiasp VDD
M1 Vbiasn Vbiasn 0 0 N_1u L=2 W=10
M2 Vbiasp Vbiasn Vr 0 N_1u L=2 W=40
M3 Vbiasn Vbiasp VDD VDD P_1u L=2 W=30
M4 Vbiasp Vbiasp VDD VDD P_1u L=2 W=30
Rbias Vr 0 6.5k
MSU1 Vsur Vbiasn 0 0 N_1u L=2 W=10
MSU2 Vsur Vsur VDD VDD P_1u L=100 W=10
MSU3 Vbiasp Vsur Vbiasn 0 N_1u L=1 W=10
.ends
.include cmosedu_models.txt
.param d = 1
.param let = 20
.param tfall = 500p trise = 100p ; tau in exponent for pulse
aseegen2 ct mon [ %id(vdd vbiasp) %id(vdd vop) %id(vdd vom) %id(vdd vopb) %id(vdd vpp) %id(vdd vomb) %id(vdd vdp) %id(vdd nd1)
+ %i(vbiasn) %i(x1.vr) %i(x1.vsur) %i(n1) %i(vss) %i(n2) %i(vc) %i(vdo) %i(out) ] seemod2
.model seemod2 seegen (tdelay = 25n tperiod=19n tfall='tfall' trise='trise' let='let' cdepth='d' perlim=TRUE ctrlthres= {VCC/2})
.control
run
rusage time
set xbrushwidth=2
plot mon
plot out vp ct mon*5000+6
.endc
.end

View File

@ -0,0 +1,147 @@
*
* Long channel models from CMOS Circuit Design, Layout, and Simulation,
* Level=3 models VDD=5V, see CMOSedu.com
*
.MODEL N_1u NMOS LEVEL = 3
+ TOX = 200E-10 NSUB = 1E17 GAMMA = 0.5
+ PHI = 0.7 VTO = 0.8 DELTA = 3.0
+ UO = 650 ETA = 3.0E-6 THETA = 0.1
+ KP = 120E-6 VMAX = 1E5 KAPPA = 0.3
+ RSH = 0 NFS = 1E12 TPG = 1
+ XJ = 500E-9 LD = 100E-9
+ CGDO = 200E-12 CGSO = 200E-12 CGBO = 1E-10
+ CJ = 400E-6 PB = 1 MJ = 0.5
+ CJSW = 300E-12 MJSW = 0.5
*
.MODEL P_1u PMOS LEVEL = 3
+ TOX = 200E-10 NSUB = 1E17 GAMMA = 0.6
+ PHI = 0.7 VTO = -0.9 DELTA = 0.1
+ UO = 250 ETA = 0 THETA = 0.1
+ KP = 40E-6 VMAX = 5E4 KAPPA = 1
+ RSH = 0 NFS = 1E12 TPG = -1
+ XJ = 500E-9 LD = 100E-9
+ CGDO = 200E-12 CGSO = 200E-12 CGBO = 1E-10
+ CJ = 400E-6 PB = 1 MJ = 0.5
+ CJSW = 300E-12 MJSW = 0.5
*
*
* Short channel models from CMOS Circuit Design, Layout, and Simulation,
* 50nm BSIM4 models VDD=1V, see CMOSedu.com
*
.model N_50n nmos level = 54
+binunit = 1 paramchk= 1 mobmod = 0
+capmod = 2 igcmod = 1 igbmod = 1 geomod = 0
+diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1
+permod = 1 acnqsmod= 0 trnqsmod= 0
+tnom = 27 toxe = 1.4e-009 toxp = 7e-010 toxm = 1.4e-009
+epsrox = 3.9 wint = 5e-009 lint = 1.2e-008
+ll = 0 wl = 0 lln = 1 wln = 1
+lw = 0 ww = 0 lwn = 1 wwn = 1
+lwl = 0 wwl = 0 xpart = 0 toxref = 1.4e-009
+vth0 = 0.22 k1 = 0.35 k2 = 0.05 k3 = 0
+k3b = 0 w0 = 2.5e-006 dvt0 = 2.8 dvt1 = 0.52
+dvt2 = -0.032 dvt0w = 0 dvt1w = 0 dvt2w = 0
+dsub = 2 minv = 0.05 voffl = 0 dvtp0 = 1e-007
+dvtp1 = 0.05 lpe0 = 5.75e-008 lpeb = 2.3e-010 xj = 2e-008
+ngate = 5e+020 ndep = 2.8e+018 nsd = 1e+020 phin = 0
+cdsc = 0.0002 cdscb = 0 cdscd = 0 cit = 0
+voff = -0.15 nfactor = 1.2 eta0 = 0.15 etab = 0
+vfb = -0.55 u0 = 0.032 ua = 1.6e-010 ub = 1.1e-017
+uc = -3e-011 vsat = 1.1e+005 a0 = 2 ags = 1e-020
+a1 = 0 a2 = 1 b0 = -1e-020 b1 = 0
+keta = 0.04 dwg = 0 dwb = 0 pclm = 0.18
+pdiblc1 = 0.028 pdiblc2 = 0.022 pdiblcb = -0.005 drout = 0.45
+pvag = 1e-020 delta = 0.01 pscbe1 = 8.14e+008 pscbe2 = 1e-007
+fprout = 0.2 pdits = 0.2 pditsd = 0.23 pditsl = 2.3e+006
+rsh = 3 rdsw = 150 rsw = 150 rdw = 150
+rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 0
+prwb = 6.8e-011 wr = 1 alpha0 = 0.074 alpha1 = 0.005
+beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002
+egidl = 0.8
+aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002
+nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004
+eigbinv = 1.1 nigbinv = 3 aigc = 0.017 bigc = 0.0028
+cigc = 0.002 aigsd = 0.017 bigsd = 0.0028 cigsd = 0.002
+nigc = 1 poxedge = 1 pigcd = 1 ntox = 1
+xrcrg1 = 12 xrcrg2 = 5
+cgso = 6.238e-010 cgdo = 6.238e-010 cgbo = 2.56e-011 cgdl = 2.495e-10
+cgsl = 2.495e-10 ckappas = 0.02 ckappad = 0.02 acde = 1
+moin = 15 noff = 0.9 voffcv = 0.02
+kt1 = -0.21 kt1l = 0.0 kt2 = -0.042 ute = -1.5
+ua1 = 1e-009 ub1 = -3.5e-019 uc1 = 0 prt = 0
+at = 53000
+fnoimod = 1 tnoimod = 0
+jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1
+ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1
+jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1
+ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1
+pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1
+cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 5e-010
+mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5
+pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1
+cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001
+tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001
+xtis = 3 xtid = 3
+dmcg = 0e-006 dmci = 0e-006 dmdg = 0e-006 dmcgt = 0e-007
+dwj = 0e-008 xgw = 0e-007 xgl = 0e-008
+rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15
+rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1
*
.model P_50n pmos level = 54
+binunit = 1 paramchk= 1 mobmod = 0
+capmod = 2 igcmod = 1 igbmod = 1 geomod = 0
+diomod = 1 rdsmod = 0 rbodymod= 1 rgatemod= 1
+permod = 1 acnqsmod= 0 trnqsmod= 0
+tnom = 27 toxe = 1.4e-009 toxp = 7e-010 toxm = 1.4e-009
+epsrox = 3.9 wint = 5e-009 lint = 1.2e-008
+ll = 0 wl = 0 lln = 1 wln = 1
+lw = 0 ww = 0 lwn = 1 wwn = 1
+lwl = 0 wwl = 0 xpart = 0 toxref = 1.4e-009
+vth0 = -0.22 k1 = 0.39 k2 = 0.05 k3 = 0
+k3b = 0 w0 = 2.5e-006 dvt0 = 3.9 dvt1 = 0.635
+dvt2 = -0.032 dvt0w = 0 dvt1w = 0 dvt2w = 0
+dsub = 0.7 minv = 0.05 voffl = 0 dvtp0 = 0.5e-008
+dvtp1 = 0.05 lpe0 = 5.75e-008 lpeb = 2.3e-010 xj = 2e-008
+ngate = 5e+020 ndep = 2.8e+018 nsd = 1e+020 phin = 0
+cdsc = 0.000258 cdscb = 0 cdscd = 6.1e-008 cit = 0
+voff = -0.15 nfactor = 2 eta0 = 0.15 etab = 0
+vfb = 0.55 u0 = 0.0095 ua = 1.6e-009 ub = 8e-018
+uc = 4.6e-013 vsat = 90000 a0 = 1.2 ags = 1e-020
+a1 = 0 a2 = 1 b0 = -1e-020 b1 = 0
+keta = -0.047 dwg = 0 dwb = 0 pclm = 0.55
+pdiblc1 = 0.03 pdiblc2 = 0.0055 pdiblcb = 3.4e-008 drout = 0.56
+pvag = 1e-020 delta = 0.014 pscbe1 = 8.14e+008 pscbe2 = 9.58e-007
+fprout = 0.2 pdits = 0.2 pditsd = 0.23 pditsl = 2.3e+006
+rsh = 3 rdsw = 250 rsw = 160 rdw = 160
+rdswmin = 0 rdwmin = 0 rswmin = 0 prwg = 3.22e-008
+prwb = 6.8e-011 wr = 1 alpha0 = 0.074 alpha1 = 0.005
+beta0 = 30 agidl = 0.0002 bgidl = 2.1e+009 cgidl = 0.0002
+egidl = 0.8
+aigbacc = 0.012 bigbacc = 0.0028 cigbacc = 0.002
+nigbacc = 1 aigbinv = 0.014 bigbinv = 0.004 cigbinv = 0.004
+eigbinv = 1.1 nigbinv = 3 aigc = 0.69 bigc = 0.0012
+cigc = 0.0008 aigsd = 0.0087 bigsd = 0.0012 cigsd = 0.0008
+nigc = 1 poxedge = 1 pigcd = 1 ntox = 1
+xrcrg1 = 12 xrcrg2 = 5
+cgso = 7.43e-010 cgdo = 7.43e-010 cgbo = 2.56e-011 cgdl = 1e-014
+cgsl = 1e-014 ckappas = 0.5 ckappad = 0.5 acde = 1
+moin = 15 noff = 0.9 voffcv = 0.02
+kt1 = -0.19 kt1l = 0 kt2 = -0.052 ute = -1.5
+ua1 = -1e-009 ub1 = 2e-018 uc1 = 0 prt = 0
+at = 33000
+fnoimod = 1 tnoimod = 0
+jss = 0.0001 jsws = 1e-011 jswgs = 1e-010 njs = 1
+ijthsfwd= 0.01 ijthsrev= 0.001 bvs = 10 xjbvs = 1
+jsd = 0.0001 jswd = 1e-011 jswgd = 1e-010 njd = 1
+ijthdfwd= 0.01 ijthdrev= 0.001 bvd = 10 xjbvd = 1
+pbs = 1 cjs = 0.0005 mjs = 0.5 pbsws = 1
+cjsws = 5e-010 mjsws = 0.33 pbswgs = 1 cjswgs = 5e-010
+mjswgs = 0.33 pbd = 1 cjd = 0.0005 mjd = 0.5
+pbswd = 1 cjswd = 5e-010 mjswd = 0.33 pbswgd = 1
+cjswgd = 5e-010 mjswgd = 0.33 tpb = 0.005 tcj = 0.001
+tpbsw = 0.005 tcjsw = 0.001 tpbswg = 0.005 tcjswg = 0.001
+xtis = 3 xtid = 3
+dmcg = 0e-006 dmci = 0e-006 dmdg = 0e-006 dmcgt = 0e-007
+dwj = 0e-008 xgw = 0e-007 xgl = 0e-008
+rshg = 0.4 gbmin = 1e-010 rbpb = 5 rbpd = 15
+rbps = 15 rbdb = 15 rbsb = 15 ngcon = 1

View File

@ -0,0 +1,33 @@
.title KiCad schematic
.include "cmos_sub.mod"
.include "seegen4.mod"
V1 Vcc 0 DC 3.3
XU1 VGP2 VGP4P8 Vbias VSN4N8 seegen4
XMN9 Vbias Vbias 0 0 NCH W=5u L=1.4u
V5 in+ 0 DC 1.65
R1 out in- 100k
R2 in in- 20k
V4 in 0 DC 1.65 SIN( 1.65 100m 20k 0 0 0 ) AC 1
XMN3 out Vbias 0 0 NCH W=17.4u L=1.4u
C2 out 0 2p
XMP2 out VGP2 Vcc Vcc PCH W=14.5u L=1.4u
C1 VGP2 out 1.2p
XMP4 VGP4P8 VGP4P8 Vcc Vcc PCH W=2.8u L=1.4u
I1 Vcc Vbias 12u
XMN4 VGP4P8 in- VSN4N8 0 NCH W=2.8u L=1.4u
XMN8 VGP2 in+ VSN4N8 0 NCH W=2.8u L=1.4u
XMN2 VSN4N8 Vbias 0 0 NCH W=5u L=1.4u
XMP8 VGP2 VGP4P8 Vcc Vcc PCH W=2.8u L=1.4u
.control
set xbrushwidth=2
tran 20n 2m
plot v(VGP4P8) v(xu1.mon)*5000+3
plot in out
ac dec 10 1 1Meg
plot db(out)
.endc
.end

View File

@ -0,0 +1,13 @@
* subcircuit model file
.include modelcard.nmos
.include modelcard.pmos
.subckt NCH D G S B W=1 L=1
MN1 D G S B N1 W={W} L={L} AS={3*L*W} AD={3*L*W} PS={6*L+W} PD={6*L+W}
.ends
.subckt PCH D G S B W=1 L=1
MP1 D G S B P1 W={W} L={L} AS={3*L*W} AD={3*L*W} PS={6*L+W} PD={6*L+W}
.ends

View File

@ -0,0 +1,46 @@
*model = bsim3v3
*Berkeley Spice Compatibility
*http://bsim.berkeley.edu/BSIM4/BSIM3/ftpv330.zip
* Lmin= .35 Lmax= 20 Wmin= .6 Wmax= 20
.model N1 NMOS
+Level= 8
+version=3.3.0
+Tnom=27.0
+Acnqsmod=1 elm=3
+Capmod=3
+Nch= 2.498E+17 Tox=9E-09 Xj=1.00000E-07
+Lint=9.36e-8 Wint=1.47e-7
+Lintnoi=1e-9
+Vth0= .6322 K1= .756 K2= -3.83e-2 K3= -2.612
+Dvt0= 2.812 Dvt1= 0.462 Dvt2=-9.17e-2
+Nlx= 3.52291E-08 W0= 1.163e-6
+K3b= 2.233
+Vsat= 86301.58 Ua= 6.47e-9 Ub= 4.23e-18 Uc=-4.706281E-11
+Rdsw= 650 U0= 388.3203 wr=1
+A0= .3496967 Ags=.1 B0=0.546 B1= 1
+Dwg = -6.0E-09 Dwb = -3.56E-09 Prwb = -.213
+Keta=-3.605872E-02 A1= 2.778747E-02 A2= .9
+Voff=-6.735529E-02 NFactor= 1.139926 Cit= 1.622527E-04
+Cdsc=-2.147181E-05
+Cdscb= 0 Dvt0w = 0 Dvt1w = 0 Dvt2w = 0
+Cdscd = 0 Prwg = 0
+Eta0= 1.0281729E-02 Etab=-5.042203E-03
+Dsub= .31871233
+Pclm= 1.114846 Pdiblc1= 2.45357E-03 Pdiblc2= 6.406289E-03
+Drout= .31871233 Pscbe1= 5000000 Pscbe2= 5E-09 Pdiblcb = -.234
+Pvag= 0 delta=0.01
+ Wl = 0 Ww = -1.420242E-09 Wwl = 0
+ Wln = 0 Wwn = .2613948 Ll = 1.300902E-10
+ Lw = 0 Lwl = 0 Lln = .316394
+ Lwn = 0
+kt1=-.3 kt2=-.051
+At= 22400
+Ute=-1.48
+Ua1= 3.31E-10 Ub1= 2.61E-19 Uc1= -3.42e-10
+Kt1l=0 Kt1=-0.1 Prt=764.3

View File

@ -0,0 +1,38 @@
*model = bsim3v3
*Berkeley Spice Compatibility
*http://bsim.berkeley.edu/BSIM4/BSIM3/ftpv330.zip
* Lmin= .35 Lmax= 20 Wmin= .6 Wmax= 20
.model P1 PMOS
+Level= 8
+version=3.3.0
+Tnom=27.0
+Acnqsmod=1 elm=3
+Nch= 3.533024E+17 Tox=9E-09 Xj=1.00000E-07
+Lint=6.23e-8 Wint=1.22e-7
+Lintnoi=1e-9
+Vth0=-.6732829 K1= .8362093 K2=-8.606622E-02 K3= 1.82
+Dvt0= 1.903801 Dvt1= .5333922 Dvt2=-.1862677
+Nlx= 1.28e-8 W0= 2.1e-6
+K3b= -0.24 Prwg=-0.001 Prwb=-0.323
+Vsat= 103503.2 Ua= 1.39995E-09 Ub= 1.e-19 Uc=-2.73e-11
+ Rdsw= 460 U0= 138.7609
+A0= .4716551 Ags=0.12
+Keta=-1.871516E-03 A1= .3417965 A2= 0.83
+Voff=-.074182 NFactor= 1.54389 Cit=-1.015667E-03
+Cdsc= 8.937517E-04
+Cdscb= 1.45e-4 Cdscd=1.04e-4
+ Dvt0w=0.232 Dvt1w=4.5e6 Dvt2w=-0.0023
+Eta0= 6.024776E-02 Etab=-4.64593E-03
+Dsub= .23222404
+Pclm= .989 Pdiblc1= 2.07418E-02 Pdiblc2= 1.33813E-3
+Drout= .3222404 Pscbe1= 118000 Pscbe2= 1E-09
+Pvag= 0
+kt1= -0.25 kt2= -0.032 prt=64.5
+At= 33000
+Ute= -1.5
+Ua1= 4.312e-9 Ub1= 6.65e-19 Uc1= 0
+Kt1l=0

View File

@ -0,0 +1,10 @@
* SEE generator model
.subckt seegen4 n1 n2 n3 n4
.param tochar = 2e-13
.param tfall = 500p trise=50p
.param Inull = 'tochar/(tfall-trise)'
* Eponential current source without control input
* only NMOS nodes with reference GND (substrate).
aseegen1 NULL mon [%i(n1) %i(n2) %i(n3) %i(n4)] seemod1
.model seemod1 seegen (tdelay = 0.62m tperiod=0.01m inull='Inull' perlim=FALSE)
.ends

View File

@ -0,0 +1,45 @@
* IHP Open PDK
* simple inverter
* Path to the PDK
*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice"
.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt
*.include lib_out1.lib
.param vdd = 1.2
.param deltat=11n
* the voltage sources:
Vdd vd gnd DC 'vdd'
V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n)
* Eponential current source
Iset out 0 EXP(0 2.5m 'deltat' 10p 'deltat' 500p)
*Cset out 0 10f
Xnot1 in vdd vss out not1
Vmeasvss vss 0 0
Vmeasvdd vd vdd 0
.subckt not1 a vdd vss z
xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* simulation command:
.tran 100ps 50ns ; 0 10p
.options method=gear
.control
run
rusage
*set nolegend
set xbrushwidth=3
plot i(Vmeasvss) i(Vmeasvdd)
plot in out
.endc
.end

View File

@ -0,0 +1,61 @@
* IHP Open PDK
* simple SRAM cell, exponential current pulses
* Path to the PDK
*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice"
.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt
*.include lib_out1.lib
.param vdd = 1.2
.param deltat=11n deltat2=27n
.param tochar = 1e-13
.param talpha = 500p tbeta=10p
.param Inull = 'tochar/(talpha-tbeta)'
* the voltage sources:
Vdd vd gnd DC 'vdd'
Vwl wl 0 0 PULSE 0 'vdd' 45n 1n 1n 7n 1
Vbl bl 0 'vdd'
Vbln bln 0 0
*V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n)
* Eponential current source without control input
aseegen1 NULL mon [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1
.model seemod1 seegen (tdelay = 11n tperiod=25n inull='Inull')
Xnot1 n1 vdd vss n2 not1
Xnot2 n2 vdd vss n1 not1
xmo02 n2 wl bl vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
xmo01 n1 wl bln vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
Vmeasvss vss 0 0
Vmeasvdd vd vdd 0
Vm1 m1 0 0
Vm2 m2 0 0
.subckt not1 a vdd vss z
xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* starting condition for SRAM cell
.ic v(n2)=0 v(n1)='vdd'
* simulation command:
.tran 100ps 100ns ; 0 10p
.options method=gear
.control
run
rusage
*set nolegend
set xbrushwidth=3
plot i(Vmeasvss) i(Vmeasvdd)
plot n1 n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8
.endc
.end

View File

@ -0,0 +1,60 @@
* Simple SRAM cell in a subcircuit, double exponential current pulses
* control volate
* IHP Open PDK
* Path to the PDK
.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt
.param vdd = 1.2
.param deltat=11n deltat2=25n
.param tochar = 1e-13
.param talpha = 500p tbeta=20p
.param Inull = 'tochar/(talpha-tbeta)'
* the voltage sources:
Vdd vd gnd DC 'vdd'
Vwl wl 0 0 PULSE 0 'vdd' 50n 1n 1n 7n 1
Vbl bl 0 'vdd'
Vbln bln 0 0
Vctrl ctrl 0 pulse (0 1 10n 1n 1n 1 1)
* Exponential current source with control input
aseegen1 ctrl mon [%id(n1 m1) %id(n2 m2) %id(n1 m1) %id(n2 m2)] seemod1
.model seemod1 seegen (tdelay = 8n tperiod=25n)
Xnot1 n1 vdd vss n2 not1
Xnot2 n2 vdd vss n1 not1
xmo02 n2 wl bl vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
xmo01 n1 wl bln vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
Vmeasvss vss 0 0
Vmeasvdd vd vdd 0
Vm1 m1 0 0
Vm2 m2 0 0
.subckt not1 a vdd vss z
xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* starting condition for SRAM cell
.ic v(n2)=0 v(n1)='vdd'
* simulation command:
.tran 100ps 120ns
.options method=gear
.control
pre_osdi C:\Spice64\lib\ngspice\psp103_nqs.osdi
run
rusage
*set nolegend
set xbrushwidth=3
plot i(Vmeasvss) i(Vmeasvdd)
plot n1 n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8
.endc
.end

View File

@ -0,0 +1,69 @@
* Simple SRAM cell in a subcircuit, double exponential current pulses
* IHP Open PDK
* Path to the PDK
.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt
.param vdd = 1.2
.param deltat=11n deltat2=27n
*.param tochar = 1e-13 ; tochar dependency on LET not yet defined
.param tfall = 500p trise=20p ; tau in exponent for pulse
.param let = 11
.param cdepth = 0.9
*.param Inull = 'tochar/(tfall-trise)'
* the voltage sources:
Vdd vd gnd DC 'vdd'
Vwl wl 0 0 PULSE 0 'vdd' 45n 1n 1n 7n 1
Vbl1 bl1 0 'vdd'
Vbl2 bl2 0 0
**** SEE generator without control input, double exponential current sources
aseegen1 NULL mon [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1
.model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='cdepth' tfall='tfall' trise='trise')
* alternative syntax, if no current measurement required and reference nodes are GND
*aseegen1 NULL mon [%i(xcell.n1) %i(xcell.n2) %i(xcell.n1) %i(xcell.n2)] seemod1
**** the SRAM cell
Xcell bl1 bl2 wl vdd vss srcell
.subckt srcell bl1 bl2 wl vdd vss
Xnot1 n1 vdd vss n2 not1
Xnot2 n2 vdd vss n1 not1
xmo02 n2 wl bl1 vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
xmo01 n1 wl bl2 vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
.ends
**** Current measurements
Vmeasvss vss 0 0
Vmeasvdd vd vdd 0
Vm1 m1 0 0
Vm2 m2 0 0
**** Inverter cell
.subckt not1 a vdd vss z
xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* starting condition for SRAM cell
.ic v(xcell.n2)=0 v(xcell.n1)='vdd'
* simulation command:
.tran 100ps 120ns
*.options method=gear
.control
pre_osdi C:\Spice64\lib\ngspice\psp103_nqs.osdi
run
rusage
*set nolegend
set xbrushwidth=3
plot i(Vmeasvss) i(Vmeasvdd)
plot xcell.n1 xcell.n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8
.endc
.end

View File

@ -0,0 +1,81 @@
* Simple SRAM cell in a subcircuit, double exponential current pulses
* total charge is varied.
* IHP Open PDK
* Path to the PDK
.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt
.param vdd = 1.2
*.param tochar = 1e-13 ; tochar dependency on LET not yet defined
.param d = 1
.param let = 8
.param tochar = 1.035e-14 * let * d
.csparam let = 'let' ; send param value to .control section
.param tfall = 500p trise = 100p ; tau in exponent for pulse
.param Inull = 'tochar/(tfall-trise)'
* the voltage sources:
Vdd vd gnd DC 'vdd'
Vwl wl 0 0 PULSE 0 'vdd' 45n 1n 1n 7n 1
Vbl1 bl1 0 'vdd'
Vbl2 bl2 0 0
**** SEE generator without control input, double exponential current sources
aseegen1 NULL mon [%id(xcell.n1 m1) %id(xcell.n2 m2) %id(xcell.n1 m1) %id(xcell.n2 m2)] seemod1
.model seemod1 seegen (tdelay = 11n tperiod=25n tfall='tfall' trise='trise' let='let' cdepth='d')
* alternative syntax, if no current measurement required and reference nodes are GND
*aseegen1 NULL mon [%i(xcell.n1) %i(xcell.n2) %i(xcell.n1) %i(xcell.n2)] seemod1
**** the SRAM cell
Xcell bl1 bl2 wl vdd vss srcell
.subckt srcell bl1 bl2 wl vdd vss
Xnot1 n1 vdd vss n2 not1
Xnot2 n2 vdd vss n1 not1
xmo02 n2 wl bl1 vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
xmo01 n1 wl bl2 vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
.ends
**** Current measurements
Vmeasvss vss 0 0
Vmeasvdd vd vdd 0
Vm1 m1 0 0
Vm2 m2 0 0
**** Inverter cell
.subckt not1 a vdd vss z
xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* starting condition for SRAM cell
.ic v(xcell.n2)=0 v(xcell.n1)='vdd'
* simulation command:
.tran 100ps 120ns
*.options method=gear
.options noinit
.control
pre_osdi C:\Spice64\lib\ngspice\psp103_nqs.osdi
set xbrushwidth=3
let newlet = let
repeat 5
print newlet
run
plot xcell.n1 xcell.n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8 ylimit -1 10
let newlet = newlet + 1
alterparam let = $&newlet
reset
end
rusage
.endc
.end

View File

@ -0,0 +1,64 @@
* IHP Open PDK
* simple SRAM cell, exponential current pulses
* Path to the PDK
*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice"
.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt
*.include lib_out1.lib
.param vdd = 1.2
.param deltat=11n deltat2=27n
.param tochar = 1e-13
.param talpha = 500p tbeta=10p
.param Inull = 'tochar/(talpha-tbeta)'
* the voltage sources:
Vdd vd gnd DC 'vdd'
Vwl wl 0 0 PULSE 0 'vdd' 45n 1n 1n 7n 1
Vbl bl 0 'vdd'
Vbln bln 0 0
*V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10n)
* Eponential current source
Iset1 n1 m1 EXP(0 'Inull' 'deltat' 'tbeta' 'deltat' 'talpha')
Iset2 n2 m2 EXP(0 'Inull' 'deltat2' 'tbeta' 'deltat2' 'talpha')
Iset3 n1 m1 EXP(0 'Inull' 'deltat+50n' 'tbeta' 'deltat+50n' 'talpha')
Iset4 n2 m2 EXP(0 'Inull' 'deltat2+50n' 'tbeta' 'deltat2+50n' 'talpha')
*Cset out 0 10f
Xnot1 n1 vdd vss n2 not1
Xnot2 n2 vdd vss n1 not1
xmo02 n2 wl bl vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
xmo01 n1 wl bln vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
Vmeasvss vss 0 0
Vmeasvdd vd vdd 0
Vm1 m1 0 0
Vm2 m2 0 0
.subckt not1 a vdd vss z
xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* starting condition for SRAM cell
.ic v(n2)=0 v(n1)='vdd'
* simulation command:
.tran 100ps 100ns ; 0 10p
.options method=gear
.control
run
rusage
*set nolegend
set xbrushwidth=3
plot i(Vmeasvss) i(Vmeasvdd)
plot n1 n2+2 wl+4 i(vm1)*10000+6 i(vm2)*10000+8
.endc
.end

View File

@ -0,0 +1,47 @@
* simple inverter, IHP Open PDK
* Path to the PDK
*.include "D:\Spice_general\skywater-pdk\libraries\sky130_fd_pr\latest\models\corners/tt.spice"
.lib "D:\Spice_general\IHP-Open-PDK\ihp-sg13g2\libs.tech\ngspice\models\cornerMOSlv.lib" mos_tt
*.include lib_out1.lib
.param vdd = 1.2
.param deltat=11n deltat2=27n
* the voltage sources:
Vdd vd gnd DC 'vdd'
V1 in gnd pulse(0 'vdd' 0p 200p 100p 5n 10.1n)
* Eponential current source
Iset1 out1 0 EXP(0 250u 'deltat' 10p 'deltat' 500p)
Iset2 out1 0 EXP(0 250u 'deltat2' 10p 'deltat2' 500p)
*Cset out 0 10f
Xnot1 in vdd vss out1 not1
Xnot2 out1 vdd vss out2 not1
Vmeasvss vss 0 0
Vmeasvdd vd vdd 0
.subckt not1 a vdd vss z
xm01 z a vdd vdd sg13_lv_pmos l=0.15u w=0.99u as=0.26235p ad=0.26235p ps=2.51u pd=2.51u
xm02 z a vss vss sg13_lv_nmos l=0.15u w=0.495u as=0.131175p ad=0.131175p ps=1.52u pd=1.52u
c3 a vss 0.384f
c2 z vss 0.576f
.ends
* simulation command:
.tran 100ps 50ns ; 0 10p
.options method=gear
.control
run
rusage
*set nolegend
set xbrushwidth=3
plot i(Vmeasvss) i(Vmeasvdd)
plot in out1+2 out2+4
.endc
.end

View File

@ -0,0 +1,41 @@
* Repeat loop, double exponential current pulses
.param let = 10.5 cdepth = 1.2
.csparam let = 'let'
.param tfall = 500p trise = 20p ; tau in exponent for pulse
R1 n1 0 1e4
R2 n2 0 1e4
R3 n3 0 1e4
R4 n4 0 1e4
**** SEE generator without control input, double exponential current sources
aseegen1 NULL mon [%id(n1 0) %id(n2 0) %id(n3 0) %id(n4 0)] seemod1
.model seemod1 seegen (tdelay = 11n tperiod=25n let='let' cdepth='cdepth' trise='trise' tfall='tfall')
* alternative syntax, if no current measurement required and reference nodes are GND
*aseegen1 NULL mon [%i(n1) %i(n2) %i(n3) %i(n4)] seemod1
* simulation command:
.tran 100ps 120ns
*.options method=gear
.control
set xbrushwidth=3
*run
*plot n1 n2+2 n3+4 n4+6
let newlet = let
repeat 10
run
plot n1 n2+2 n3+4 n4+6 ylimit -3 7
let newlet = newlet - 0.5
alterparam let = $&newlet
reset
end
rusage
.endc
.end

View File

@ -0,0 +1,22 @@
Test of seegen code model
aseegen1 NULL mon [%id(n1 p1) %id(n2 p2) %id(n3 p3)] seemod1
.model seemod1 seegen (tdelay = 5n tperiod=4.5n)
Rsee1 n1 0 1
Vmeas1 p1 0 0
Rsee2 n2 0 1
Vmeas2 p2 0 0
Rsee3 n3 0 1
Vmeas3 p3 0 0
.control
tran 10p 35n
rusage time
set xbrushwidth=3
plot i(Vmeas1) i(Vmeas2)+200u i(Vmeas3)+400u
.endc
.end

View File

@ -0,0 +1,23 @@
SET pulse test
.param alpha = 100p beta = 500p deltat = 1n
* Arbitrary currnt source with expression
Bset1 1 0 I = ternary_fcn(TIME < 'deltat', 0, 2.5m * (exp(-(TIME-'deltat')/'alpha')-exp(-(TIME-'deltat')/'beta')))
R1 1 11 1
Vmeas 11 0 0
* Eponential current source
Iset 2 0 EXP(0 -2.5m 'deltat' 'alpha' 'deltat' 'beta')
R2 2 22 1
Vmeas2 22 0 0
.control
tran 1p 10n
set xbrushwidth=2
plot I(Vmeas)-I(Vmeas2)
plot I(Vmeas) I(Vmeas2)
.endc
.end

View File

@ -0,0 +1,18 @@
* Coupled lines SP
V1 p1 0 dc 0 ac 1 portnum 1 z0 50
V2 p2 0 dc 0 ac 1 portnum 2 z0 50
V3 p3 0 dc 0 ac 1 portnum 3 z0 50
V4 p4 0 dc 0 ac 1 portnum 4 z0 50
A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) CPLINE1
.MODEL CPLINE1 CPLINE(ze=84.48 zo=53.99 l=25e-3 ere=3.34 ero=2.829 ao=0 ae=0)
.control
sp lin 100 0.2e9 4.2e9
plot abs(s_1_1) abs(s_3_1) abs(s_2_1) abs(s_4_1)
plot abs(s_2_1)
.endc

View File

@ -0,0 +1,23 @@
* Coupled lines SP
V1 1 0 PULSE(0 1 1n 10p 10p 980p)
R2 p1 1 0.1
R1 p4 0 50.0
R3 p3 0 50.0
R4 p2 0 50.0
A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) %vd(p1 0) %vd(p2 0) %vd(p3 0) %vd(p4 0) CPLINE1
.MODEL CPLINE1 CPLINE(ze=100 zo=50 l=100e-3 ere=1 ero=1 ao=0 ae=0)
.control
tran 10p 5n
let v2 = -v(p2)
let v3 = -v(p3)
plot v(1) v(p2) v(p3) v(p4)
.endc

View File

@ -0,0 +1,18 @@
* Coupled lines SP
V1 p1 0 dc 0 ac 1 portnum 1 z0 50
V2 p2 0 dc 0 ac 1 portnum 2 z0 50
V3 p3 0 dc 0 ac 1 portnum 3 z0 50
V4 p4 0 dc 0 ac 1 portnum 4 z0 50
A1 %hd(p1 0) %hd(p2 0) %hd(p3 0) %hd(p4 0) %vd(p1 0) %vd(p2 0) %vd(p3 0) %vd(p4 0) CPMLIN1
.MODEL CPMLIN1 CPMLIN(w=1e-3 l=20e-3 s=0.3e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d1=0.15e-6 model=0 disp=0)
.control
sp lin 100 0.2e9 4.2e9
plot abs(s_1_1) abs(s_3_1) abs(s_2_1) abs(s_4_1)
plot abs(s_3_1)
.endc

View File

@ -0,0 +1,22 @@
* MLIN test
V1 1 0 AC 1 DC 1
R1 in 1 50.0
R2 out 0 1000.1
A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) MLIN1
.MODEL MLIN1 MLIN(w=1e-3 l=10e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d=0.15e-6 model=0 disp=0)
.control
op
print all
ac LIN 200 1e9 12e9
let z = v(in)/-i(v1)
let y = imag(z)
let r = real(z)
plot abs(z) ylog
plot y r
.endc

View File

@ -0,0 +1,25 @@
* MLIN test
V1 1 4 PULSE(0 1 1n 10p 10p 980p)
V3 4 0 DC 1
R1 out 2 20.0
V2 2 0 0
R2 in 1 1m
*R3 in ins 1e12
*R4 out outs 1e12
A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) MLIN1
.MODEL MLIN1 MLIN(w=1e-3 l=50e-3 er=9.8 h=1e-3 t=35e-6 tand=1e-3 rho=0.022e-6 d1=0.15e-6 model=0 disp=0 tranmodel=1)
*A1 %hd(in 0) %hd(out 0) %vd(in 0) %vd(out 0) TLIN1
*.MODEL TLIN1 TLINE(l=100e-3 z=50.0 a=0.0)
.control
*op
*print all
tran 10p 5n
plot v(in) v(out)
plot -i(v1) i(V2)
.endc

View File

@ -293,7 +293,11 @@ com_iplot(wordlist *wl)
d = TMALLOC(struct dbcomm, 1);
d->db_analysis = NULL;
d->db_number = debugnumber++;
#ifdef XSPICE
d->db_iteration = event_auto_incr ? DB_AUTO_OFFSET : DB_NORMAL;
#else
d->db_iteration = DB_NORMAL;
#endif
d->db_op = initial_steps; // Field re-use
d->db_value1 = window; // Field re-use

View File

@ -64,7 +64,7 @@ is_arith_char2(char c)
return c != '\0' && strchr("*/<>?:|&^!%\\", c);
}
static bool
bool
str_has_arith_char2(char* s)
{
if (*s == '+' || *s == '-')
@ -717,6 +717,9 @@ measure_at(
value = get_value(meas, d, i); //d->v_compdata[i].cx_real;
else
value = d->v_realdata[i];
if (dScale->v_compdata) // .sp, s-param.
svalue = dScale->v_compdata[i].cx_real;
else // fft
svalue = dScale->v_realdata[i];
} else {
value = d->v_realdata[i];

View File

@ -1779,7 +1779,7 @@ com_alterparam(wordlist *wl)
/* alterparam subcktname pname=vpval
Parameters from within subcircuit are no longer .param lines, but have been added to
the .subckt line as pname=paval and to the x line as pval. pval in the x line takes
precedence when subciruit is called, so has to be replaced here.
precedence when subcircuit is called, so has to be replaced here.
Find subcircuit with subcktname.
After params: Count the number of parameters (notok) until parameter pname is found.
When found, search for x-line with subcktname.

View File

@ -332,7 +332,7 @@ void inp_probe(struct card* deck)
/* special for KiCad: add shunt resistor if thisnode contains 'unconnected' */
if (*instname == 'x' && strstr(thisnode, "unconnected")) {
/* nn makes the resistor name unique for a device with multiple unconnected nodes */
char *rline = tprintf("R%s%d %s 0 1e15", thisnode, nn++, thisnode);
char *rline = tprintf("r%s%d %s 0 1e15", thisnode, nn++, thisnode);
card = insert_new_line(card, rline, 0, card->linenum_orig, card->linesource);
}
char* nodesaves = tprintf("%s:%s#branch", instname, nodename);
@ -398,7 +398,7 @@ void inp_probe(struct card* deck)
if (!strnode2) {
}
else {
newline = tprintf("Ediff%d_nodes vd_%s:%s 0 %s %s 1", ee, strnode1, strnode2, strnode1, strnode2);
newline = tprintf("ediff%d_nodes vd_%s:%s 0 %s %s 1", ee, strnode1, strnode2, strnode1, strnode2);
char* nodesaves = tprintf("vd_%s:%s", strnode1, strnode2);
allsaves = wl_cons(nodesaves, allsaves);
@ -434,7 +434,7 @@ void inp_probe(struct card* deck)
tfree(strnode2);
continue;
}
newline = tprintf("Ediff%d_%s vd_%s 0 %s %s 1", ee, instname1, instname1, strnode1, strnode2);
newline = tprintf("ediff%d_%s vd_%s 0 %s %s 1", ee, instname1, instname1, strnode1, strnode2);
char* nodesaves = tprintf("vd_%s", instname1);
allsaves = wl_cons(nodesaves, allsaves);
@ -590,7 +590,7 @@ void inp_probe(struct card* deck)
}
nodename2 = get_terminal_name(instname2, node2, instances);
}
char *newline = tprintf("Ediff%d_%s_%s vd_%s:%s_%s:%s 0 %s %s 1", ee, instname1, instname2, instname1, nodename1, instname2, nodename2, strnode1, strnode2);
char *newline = tprintf("ediff%d_%s_%s vd_%s:%s_%s:%s 0 %s %s 1", ee, instname1, instname2, instname1, nodename1, instname2, nodename2, strnode1, strnode2);
char* nodesaves = tprintf("vd_%s:%s_%s:%s", instname1, nodename1, instname2, nodename2);
allsaves = wl_cons(nodesaves, allsaves);
tmpcard1 = insert_new_line(tmpcard1, newline, 0, tmpcard1->linenum_orig, tmpcard1->linesource);
@ -712,7 +712,7 @@ void inp_probe(struct card* deck)
}
nodename2 = get_terminal_name(instname1, node2, instances);
}
char* newline = tprintf("Ediff%d_%s vd_%s:%s:%s 0 %s %s 1", ee, instname1, instname1, nodename1, nodename2, strnode1, strnode2);
char* newline = tprintf("ediff%d_%s vd_%s:%s:%s 0 %s %s 1", ee, instname1, instname1, nodename1, nodename2, strnode1, strnode2);
char* nodesaves = tprintf("vd_%s:%s:%s", instname1, nodename1, nodename2);
allsaves = wl_cons(nodesaves, allsaves);
tmpcard1 = insert_new_line(tmpcard1, newline, 0, tmpcard1->linenum_orig, tmpcard1->linesource);
@ -1335,22 +1335,22 @@ static int setallvsources(struct card *tmpcard, NGHASHPTR instances, char *instn
DS_CREATE(Bpowersave, 200);
if (power) {
/* For example: Bq1Vref q1Vref 0 V = 1/3*( */
/* For example: bq1vref q1vref 0 v = 1/3*( */
char numbuf[3];
sadd(&BVrefline, "Bprobe_int_");
sadd(&BVrefline, "bprobe_int_");
sadd(&BVrefline, instname);
sadd(&BVrefline, "Vref ");
sadd(&BVrefline, "vref ");
sadd(&BVrefline, instname);
sadd(&BVrefline, "probe_int_Vref 0 V = 1/");
sadd(&BVrefline, "probe_int_vref 0 v = 1/");
sadd(&BVrefline, itoa10(numnodes, numbuf));
sadd(&BVrefline, "*(");
/* For example: Bq1power q1:power 0 V = */
sadd(&Bpowerline, "Bprobe_int_");
/* For example: bq1power q1:power 0 v = */
sadd(&Bpowerline, "bprobe_int_");
sadd(&Bpowerline, instname);
sadd(&Bpowerline, "power ");
sadd(&Bpowerline, instname);
cadd(&Bpowerline, ':');
sadd(&Bpowerline, "power 0 V = 0+"); /*FIXME 0+ required to suppress adding {} and numparam failure*/
sadd(&Bpowerline, "power 0 v = 0+"); /*FIXME 0+ required to suppress adding {} and numparam failure*/
/* For example: q1:power */
sadd(&Bpowersave, instname);
cadd(&Bpowersave, ':');
@ -1414,20 +1414,20 @@ static int setallvsources(struct card *tmpcard, NGHASHPTR instances, char *instn
if (power) {
/* For example V(1)+V(2)+V(3)*/
if (nodenum == 1)
sadd(&BVrefline, "V(");
sadd(&BVrefline, "v(");
else
sadd(&BVrefline, "+V(");
sadd(&BVrefline, "+v(");
sadd(&BVrefline, newnode);
cadd(&BVrefline, ')');
/*For example: (V(node1)-V(q1probe_int_Vref))*node1#branch+(V(node2)-V(q1Vref))*node2#branch */
if (nodenum == 1)
sadd(&Bpowerline, "(V(");
sadd(&Bpowerline, "(v(");
else
sadd(&Bpowerline, "+(V(");
sadd(&Bpowerline, "+(v(");
sadd(&Bpowerline, newnode);
sadd(&Bpowerline, ")-V(");
sadd(&Bpowerline, ")-v(");
sadd(&Bpowerline, instname);
sadd(&Bpowerline, "probe_int_Vref))*i(vcurr_");
sadd(&Bpowerline, "probe_int_vref))*i(vcurr_");
sadd(&Bpowerline, instname);
sadd(&Bpowerline, ":probe_int_");
sadd(&Bpowerline, nodename1);

View File

@ -147,6 +147,7 @@ static void inp_compat(struct card *deck);
static void inp_bsource_compat(struct card *deck);
static bool inp_temper_compat(struct card *card);
static void inp_meas_current(struct card *card);
static void inp_meas_control(struct card *card);
static void inp_dot_if(struct card *deck);
static char *inp_modify_exp(char *expression);
static struct func_temper *inp_new_func(char *funcname, char *funcbody,
@ -1138,12 +1139,12 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name,
inp_fix_agauss_in_param(working, statfcn[ii]);
inp_fix_temper_in_param(working);
// tprint(working);
inp_expand_macros_in_deck(NULL, working);
inp_fix_param_values(working);
inp_reorder_params(subckt_w_params, cc);
// tprint(working);
/* Special handling for large PDKs: We need to know W and L of
transistor subcircuits by checking their x invocation */
inp_get_w_l_x(working);
@ -1179,6 +1180,7 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name,
inp_repair_dc_ps(working);
}
bool expr_w_temper = FALSE;
if (!newcompat.s3) {
/* Do all the compatibility stuff here */
working = cc->nextcard;
@ -1190,6 +1192,8 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name,
inp_bsource_compat(working);
inp_dot_if(working);
expr_w_temper = inp_temper_compat(working);
/* check for expressions in meas command */
inp_meas_control(working);
}
if (expr_w_temper_p)
*expr_w_temper_p = expr_w_temper;
@ -3641,10 +3645,11 @@ static char *inp_fix_subckt(struct names *subckt_w_params, char *s)
char *equal, *beg, *buffer, *ptr1, *ptr2, *new_str;
equal = strchr(s, '=');
if (equal &&
(!strstr(s, "params:") || !isspace_c(s[-1]))) {
/* get subckt name (ptr1 will point to name) */
if (equal) {
char* paramstr = strstr(s, "params:");
if (!paramstr || !isspace_c(paramstr[-1])) {
/* get subckt name (ptr1 will point to name) */
ptr1 = skip_token(s);
for (ptr2 = ptr1; *ptr2 && !isspace_c(*ptr2) && !isquote(*ptr2);
ptr2++)
@ -3710,6 +3715,7 @@ static char *inp_fix_subckt(struct names *subckt_w_params, char *s)
s = buffer;
}
}
return s;
}
@ -7698,6 +7704,10 @@ void tprint(struct card *t)
npr++;
/*debug: print into file*/
FILE *fd = fopen(outfile, "w");
if (!fd) {
fprintf(stderr, "Warning: cannot open debug output file tprint-outxx.txt\n");
return;
}
for (tmp = t; tmp; tmp = tmp->nextcard)
if (*(tmp->line) != '*')
fprintf(fd, "%6d %6d %s\n", tmp->linenum_orig, tmp->linenum,
@ -9047,7 +9057,8 @@ static void rem_mfg_from_models(struct card *deck)
}
}
start = search_plain_identifier(curr_line, "type");
if (start && start[4] == '=') {
/* still retain type=0, type=1, type=+1, or type=-1 */
if (start && start[4] == '=' && !isdigit_c(start[5]) && !((start[5] == '-' || start[5] == '+') && isdigit_c(start[6]))) {
end = nexttok(start);
if (*end == '\0')
*start = '\0';
@ -9745,6 +9756,71 @@ int add_to_sourcepath(const char* filepath, const char* path)
return 0;
}
/* if there is an expression in FIND ... WHEN etc in a .control section,
use a vector with this expression:
meas tran yeval2 FIND v(2) WHEN v(1)= 0.9*v(2)
will become
let vexprint1 = 0.9*v(2)
meas tran yeval2 FIND v(2) WHEN v(1)=vexprint1
unlet vint
*/
static void inp_meas_control(struct card* card)
{
int is_control = 0;
static int replaceno = 1;
struct card* prevcard;
for (; card; prevcard = card, card = card->nextcard) {
char* equal_ptr = NULL;
char* curr_line = card->line;
char* newcurrline = card->line;
int currlinenumber = card->linenum_orig;
/* only commands inside .control ... .endc */
if (ciprefix(".control", curr_line)) {
is_control++;
continue;
}
else if (ciprefix(".endc", curr_line)) {
is_control--;
continue;
}
else if (is_control < 1) {
continue;
}
curr_line = skip_ws(curr_line);
if (ciprefix("meas", curr_line) && (equal_ptr = find_assignment(curr_line)) != NULL) {
curr_line = equal_ptr + 1;
while (*curr_line != '\0' && equal_ptr) {
char* token = gettok(&curr_line);
if (str_has_arith_char(token)) {
char* newtok = tprintf("=vexprint%d", replaceno++);
char* begstr = copy_substring(newcurrline, equal_ptr);
char* endstr = copy(curr_line);
char* newline = tprintf("%s%s %s", begstr, newtok, endstr);
char* letline = tprintf("let %s=%s", newtok + 1, token);
char* unletline = tprintf("unlet %s", newtok + 1);
tfree(newtok);
tfree(begstr);
tfree(endstr);
prevcard = insert_new_line(prevcard, letline, 0, currlinenumber, card->linesource);
card = prevcard->nextcard;
tfree(card->line);
card->line = newline;
newcurrline = curr_line = card->line;
card = insert_new_line(card, unletline, 0, currlinenumber, card->linesource);
}
tfree(token);
/* next equal sign in line */
equal_ptr = find_assignment(curr_line);
if (equal_ptr)
curr_line = equal_ptr + 1;
}
}
}
}
#if defined(_WIN32)

View File

@ -1329,10 +1329,10 @@ void gr_iplot(struct plot *plot)
hit = 0;
for (db = dbs; db; db = db->db_next) {
if (db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL) {
#ifdef XSPICE
if (db->db_iteration > 0) {
double event_node_offset = 0, event_node_spacing;
struct dvec *v;
#ifdef XSPICE
double event_node_offset = 0, event_node_spacing;
/* First call: set up event nodes spacing. */
@ -1348,7 +1348,7 @@ void gr_iplot(struct plot *plot)
} else {
event_node_spacing = 0;
}
#endif
/* Find any XSPICE event nodes in the node
* list and set up plotting. There is a parallel path
* for pushing new event values into their corresponding
@ -1357,8 +1357,10 @@ void gr_iplot(struct plot *plot)
for (dc = db; dc; dc = dc->db_also) {
struct dbcomm *dd;
char *offp, save_sign;
int dup = 0;
#ifdef XSPICE
char *offp, save_sign;
#endif
if (dc->db_nodename1 == NULL)
continue;
@ -1374,6 +1376,7 @@ void gr_iplot(struct plot *plot)
if (dup)
continue;
#ifdef XSPICE
/* Check for a nodename that is an expression. */
offp = strchr(dc->db_nodename1, '+');
@ -1383,7 +1386,7 @@ void gr_iplot(struct plot *plot)
save_sign = *offp;
*offp = '\0'; // Trim to bare name.
}
#endif
v = vec_fromplot(dc->db_nodename1, plot);
if (v) {
dc->db_nodename2 = (char *)v; // Save link to vector.
@ -1393,6 +1396,7 @@ void gr_iplot(struct plot *plot)
dc->db_nodename1, plot->pl_name);
}
#ifdef XSPICE
if (v && (v->v_flags & VF_EVENT_NODE)) {
/* Ask event simulator to call back with new values. */
@ -1443,10 +1447,11 @@ void gr_iplot(struct plot *plot)
"Offset (%s) ignored for analog node %s\n",
offp, dc->db_nodename1);
}
#endif
}
db->db_iteration = 0;
}
#endif
if (db->db_graphid) {
GRAPH *gr;

View File

@ -55,6 +55,7 @@ CDHW*/
#include "ngspice/iferrmsg.h"
#include "ngspice/ifsim.h"
#include "ngspice/hash.h"
#include "ngspice/devdefs.h"
#include "circuits.h"
#include "spiceif.h"
@ -1621,6 +1622,10 @@ void com_snload(wordlist *wl)
_foo(ckt->CKTstat, STATistics, 1);
ckt->CKTstat->STATdevNum = NULL;
_foo(ckt->CKTstat->STATdevNum, STATdevList, -1);
ckt->CKTstat->devCounts = NULL;
_foo(ckt->CKTstat->devCounts, size_t, DEVmaxnum + 1);
ckt->CKTstat->devTimes = NULL;
_foo(ckt->CKTstat->devTimes, double, DEVmaxnum + 1);
#ifdef XSPICE
_foo(ckt->evt, Evt_Ckt_Data_t, 1);
@ -1776,6 +1781,8 @@ void com_snsave(wordlist *wl)
/* Finally the stats */
_foo(ckt->CKTstat, STATistics, 1);
_foo(ckt->CKTstat->STATdevNum, STATdevList, 1);
_foo(ckt->CKTstat->devCounts, size_t, DEVmaxnum + 1);
_foo(ckt->CKTstat->devTimes, double, DEVmaxnum + 1);
#ifdef XSPICE
/* FIXME struct ckt->evt->data and others are not stored

View File

@ -583,18 +583,11 @@ doit(struct card *deck, wordlist *modnames) {
scale = 1;
error = 0;
/* Second pass: do the replacements.
Check if binning is used for .model inside of the subcircuit.
Reduce .model lines to the one with appropriate w and l.
(Inspired by Skywater PDK with excessive use of binning (161 bins)
in the subcircuit referencing a MOS device) */
/* Second pass: do the replacements. */
do { /* while (!error && numpasses-- && gotone) */
struct card *c = deck;
struct card *prev_of_c = NULL;
bool foundmodel = FALSE;
gotone = FALSE;
for (; c; prev_of_c = c, c = c->nextcard) {
if (ciprefix(invoke, c->line)) { /* found reference to .subckt (i.e. component with refdes X) */
@ -604,13 +597,16 @@ doit(struct card *deck, wordlist *modnames) {
gotone = TRUE;
t = tofree = s = copy(c->line); /* s & t hold copy of component line */
/* scname contains the refdes Xname */
/* make scname point to first non-whitepace chars after refdes invocation
* e.g. if invocation is Xreference, *scname = reference
*/
tofree2 = scname = gettok(&s);
/*scname += strlen(invoke); */
while ((*scname == ' ') || (*scname == '\t') || (*scname == ':'))
scname++;
/* Now set s to point to last non-space chars in the x line (i.e.
* the name of the model invoked)
/* Now set s to point to last non-space chars in line (i.e.
* the name of the model invoked
*/
while (*s)
s++;
@ -621,47 +617,38 @@ doit(struct card *deck, wordlist *modnames) {
s--;
s++;
/* Iterate through .subckt list and look for .subckt name
corresponding to the subckt name extracted from the x line */
/* iterate through .subckt list and look for .subckt name invoked */
for (sss = subs; sss; sss = sss->su_next)
if (eq(sss->su_name, s))
break;
/* At this point,
* c is the card with the x line.
* scname points to the netname of the x line involved.
* s is the subckt name extracted from the x line.
* sss points to the subcircuit referenced by the x line
* sss->su_def is the contents of the subcircuit.
/* At this point, sss points to the .subckt invoked,
* and scname points to the netnames
* involved.
*/
/* If no .subckt is found, don't complain -- this might be an
* instance of a subckt that is defined above at higher level.
*/
if (sss) {
// tprint(sss->su_def);
/* copy of the contents between .subckt and .ends */
struct card *su_deck = inp_deckcopy(sss->su_def);
/* If we have modern PDKs, we have to reduce the amount of memory required.
We try to reduce the models to the one really used.
Otherwise su_deck is full of unused binning models.
c->w > 0 and c->l > 0 point to an x line with given w and l
(typically a call to a MOS device). */
Otherwise su_deck is full of unused binning models.*/
if ((newcompat.hs || newcompat.spe) && c->w > 0 && c->l > 0) {
/* extract wmin, wmax, lmin, lmax */
struct card* enter_su_deck = su_deck;
struct card* new_deck = su_deck;
struct card* prev = NULL;
while (su_deck) {
/* find a .model line */
if (!ciprefix(".model", su_deck->line)) {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
/* check if line contains wmin, wmax, lmin, lmax
if available, extract its values,
if not, go to next line */
char* curr_line = su_deck->line;
float fwmin, fwmax, flmin, flmax;
char *wmin = strstr(curr_line, " wmin=");
@ -729,39 +716,32 @@ doit(struct card *deck, wordlist *modnames) {
su_deck = su_deck->nextcard;
continue;
}
/* check if x line's w and l are withing the limites of wmin, wmax, lmin, lmax */
float csl = (float)scale * c->l;
/* scale by nf */
float csw = (float)scale * c->w / c->nf;
/*fprintf(stdout, "Debug: nf = %f\n", c->nf);*/
if (csl >= flmin && csl < flmax && csw >= fwmin && csw < fwmax) {
/* if within the limits, use the current .model card */
/* use the current .model card */
prev = su_deck;
su_deck = su_deck->nextcard;
foundmodel = TRUE;
continue;
}
else {
/* if not within the limits,
delete the .model line not fitting the device */
struct card* tmpcard = su_deck->nextcard;
line_free_x(prev->nextcard, FALSE);
su_deck = prev->nextcard = tmpcard;
}
}
/* go back to the first card of su_deck */
su_deck = enter_su_deck;
su_deck = new_deck;
}
if (!foundmodel && (newcompat.hs || newcompat.spe) && c->w > 0 && c->l > 0) {
fprintf(stderr, "\nError: Could not find a model\n"
" for device %s in transistor subcircuit %s\n", scname, sss->su_name);
fprintf(stderr, " with w = %.3g and l = %.3g\n\n", c->w, c->l);
if (!su_deck) {
fprintf(stderr, "\nError: Could not find a model for device %s in subcircuit %s\n",
scname, sss->su_name);
controlled_exit(1);
}
foundmodel = FALSE;
struct card *rest_of_c = c->nextcard;
/* Now we have to replace this line with the
@ -802,8 +782,8 @@ doit(struct card *deck, wordlist *modnames) {
tfree(tofree);
tfree(tofree2);
} /* if (ciprefix(invoke, c->line)) */
} /* for (; c; prev_of_c = c, c = c->nextcard) */
}
}
} while (!error && numpasses-- && gotone);

View File

@ -3,9 +3,8 @@ clone_folder: c:\projects\cppduals
clone_depth: 3
image:
#- Visual Studio 2013
#- Visual Studio 2015
- Visual Studio 2017
#- Visual Studio 2022
configuration:
- Release
@ -14,12 +13,10 @@ configuration:
# Do not build feature branch with open Pull Requests
skip_branch_with_pr: true
# skip unsupported combinations
init:
- echo %APPVEYOR_BUILD_WORKER_IMAGE%
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" ( set generator="Visual Studio 12 2013" )
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" ( set generator="Visual Studio 14 2015" )
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( set generator="Visual Studio 15 2017" )
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2022" ( set generator="Visual Studio 17 2022" )
- echo %generator%
before_build:

View File

@ -1,5 +1,4 @@
#image: ubuntu:19.04
image: fedora:30
image: fedora:41
variables:
GIT_DEPTH: 3
@ -9,79 +8,105 @@ stages:
- build
- test
- cover
- publish
before_script:
#- apt-get update --yes
#- apt-get install --yes cmake g++ git doxygen lcov graphviz
- dnf install -y gcc-c++ make cmake git doxygen lcov graphviz
- pages
- upload
- release
build:
stage: build
# variables:
# CC: clang
# CXX: clang++
script:
- dnf install -y gcc-c++ make cmake git doxygen lcov graphviz
- echo $CXX
- cmake -Bbuild -H. -DCPPDUALS_TESTING=ON
- gcc -march=native -dM -E - </dev/null | grep -i sse
- cmake -Bbuild -H. -DCPPDUALS_TESTING=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
- cmake --build build
- cmake -Bbuild-latest -H. -DCPPDUALS_TESTING=ON -DCPPDUALS_EIGEN_LATEST=ON
- cmake --build build-latest
artifacts:
expire_in: 1 week
paths:
- build
- build-latest
- build/
only:
- merge_requests
- master
test:
stage: test
script:
- dnf install -y gcc-c++ make cmake git doxygen lcov graphviz
- cmake --build build --target test
- cmake --build build-latest --target test
dependencies:
- build
only:
- merge_requests
- master
cover:
stage: cover
script:
- cmake -Bbuild-cov -H. -DCODE_COVERAGE=ON -DCPPDUALS_TESTING=ON
- dnf install -y gcc-c++ make cmake git doxygen lcov graphviz
- cmake -Bbuild-cov -H. -DCPPDUALS_TESTING=ON -DCPPDUALS_CODE_COVERAGE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
- cmake --build build-cov --target cov
- cmake --build build-cov --target cov-html
coverage: '/Total:|\w*\d+\.\d+/'
coverage: "/Total:|\\w*\\d+\\.\\d+/"
artifacts:
expire_in: 1 day
expire_in: 1 week
paths:
- build-cov
- build-cov/
only:
- merge_requests
pages:
script:
- cmake -Bbuild -H. -DCODE_COVERAGE=ON -DCPPDUALS_TESTING=ON
- cmake --build build --target cppduals_docs
- cmake --build build --target cov-html
- mv build/docs public/
- mv build/coverage public/
coverage: '/Total:|\w*\d+\.\d+/'
- dnf install -y gcc-c++ make cmake git doxygen lcov graphviz
- cmake -Bbuild-cov -H. -DCODE_COVERAGE=ON -DCPPDUALS_TESTING=ON
- cmake --build build-cov --target cov-html
- cmake --build build-cov --target cppduals_docs
- mv build-cov/coverage public/
- mv build-cov/docs public/
coverage: "/Total:|\\w*\\d+\\.\\d+/"
artifacts:
paths:
- public
- public/
only:
- master
publish:
stage: publish
dependencies:
- build
environment:
name: publish
only:
- /^v\d+\.\d+\.\d+$/
except:
- branches
before_script:
- dnf install -y python3-requests
variables:
# Package version can only contain numbers (0-9), and dots (.).
# Must be in the format of X.Y.Z, i.e. should match /\A\d+\.\d+\.\d+\z/ regular expresion.
# See https://docs.gitlab.com/ee/user/packages/generic_packages/#publish-a-package-file
PACKAGE_VERSION: $CI_COMMIT_TAG
PACKAGE_REGISTRY_URL: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/release/${PACKAGE_VERSION}"
HEADER_ONLY_PACKAGE: "cppduals-h-${CI_COMMIT_TAG#v}.tgz"
upload:
stage: upload
image: curlimages/curl:latest
rules:
- if: $CI_COMMIT_TAG
script:
# - ln -s cppduals-h-${CI_BUILD_TAG#v} .
# - tar czvhf cppduals-h-${CI_BUILD_TAG#v}.tgz cppduals-h-${CI_BUILD_TAG#v}/duals cppduals-h-${CI_BUILD_TAG#v}/CMakeLists.txt
- tar czvf cppduals-h-${CI_BUILD_TAG#v}.tgz duals CMakeLists.txt
- ./doc/gitlab-release --message "Release ${CI_BUILD_TAG}" cppduals-h-${CI_BUILD_TAG#v}.tgz
- |
tar czvf ${HEADER_ONLY_PACKAGE} duals/
curl --header "JOB-TOKEN: ${CI_JOB_TOKEN}" \
--upload-file ${HEADER_ONLY_PACKAGE} \
${PACKAGE_REGISTRY_URL}/${HEADER_ONLY_PACKAGE}
release:
# Caution, as of 2021-02-02 these assets links require a login, see:
# https://gitlab.com/gitlab-org/gitlab/-/issues/299384
stage: release
image: registry.gitlab.com/gitlab-org/release-cli:latest
rules:
- if: $CI_COMMIT_TAG
script:
- |
release-cli create \
--name "Release $CI_COMMIT_TAG" \
--tag-name $CI_COMMIT_TAG \
--assets-link "{\"name\":\"${HEADER_ONLY_PACKAGE}\",\"url\":\"${PACKAGE_REGISTRY_URL}/${HEADER_ONLY_PACKAGE}\"}"
sast:
variables:
SAST_DEFAULT_ANALYZERS: flawfinder
stage: test
include:
- template: Security/SAST.gitlab-ci.yml

View File

@ -1,14 +1,17 @@
#
# CMake for cppduals
#
cmake_minimum_required (VERSION 3.1)
cmake_minimum_required (VERSION 3.14)
project (cppduals
VERSION 0.3.1
VERSION 0.6.2
LANGUAGES C CXX
)
include (GNUInstallDirs)
set (CMAKE_CXX_STANDARD 11 CACHE STRING "Which C++ standard to test against.")
if (NOT CMAKE_CXX_STANDARD)
set (CMAKE_CXX_STANDARD 17 CACHE STRING "Which C++ standard to test against.")
endif()
message (STATUS "CXX_STANDARD: ${CMAKE_CXX_STANDARD}")
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set (CMAKE_DISABLE_IN_SOURCE_BUILD ON)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
@ -38,11 +41,11 @@ if (CPPDUALS_STANDALONE AND
message (STATUS "No install prefix specified; using '${CMAKE_INSTALL_PREFIX}'")
endif ()
set_property (CACHE CMAKE_CXX_STANDARD PROPERTY STRINGS 11 14 17 20)
#set_property (CACHE CMAKE_CXX_STANDARD PROPERTY STRINGS 11 14 17 20)
set_property (CACHE CMAKE_CXX_STANDARD PROPERTY STRINGS 20)
option (CPPDUALS_TESTING "Enable testing" OFF)
option (CPPDUALS_BENCHMARK "Enable benchmarking" OFF)
option (CPPDUALS_EIGEN_LATEST "Eigen latest" OFF)
option (CPPDUALS_USE_LIBCXX "When testing use flags for libc++" OFF)
set (EIGEN3_INCLUDE_DIRS "" CACHE PATH "Path to Eigen includes" )
@ -91,7 +94,7 @@ add_library (cppduals::duals ALIAS cppduals_duals)
#
if (CPPDUALS_TESTING)
cmake_minimum_required (VERSION 3.10) # need gtest_discover_tests
cmake_minimum_required (VERSION 3.14) # need gtest_discover_tests
file (MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/thirdparty")
# generator name
@ -109,7 +112,6 @@ if (CPPDUALS_TESTING)
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
"-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
"-DCPPDUALS_BENCHMARK=${CPPDUALS_BENCHMARK}"
"-DCPPDUALS_EIGEN_LATEST=${CPPDUALS_EIGEN_LATEST}"
"-DCPPDUALS_USE_LIBCXX=${CPPDUALS_USE_LIBCXX}"
"${PROJECT_SOURCE_DIR}/thirdparty"
RESULT_VARIABLE DEPS_CONFIG_RESULT
@ -144,18 +146,27 @@ endif ()
# Code Coverage Configuration
#
add_library (cppduals_coverage_config INTERFACE)
option (CODE_COVERAGE "Enable coverage reporting" OFF)
if (CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
option (CPPDUALS_CODE_COVERAGE "Enable coverage reporting" OFF)
if (CPPDUALS_CODE_COVERAGE AND NOT CPPDUALS_TESTING)
message(FATAL_ERROR "CPPDUALS_CODE_COVERAGE requires CPPDUALS_TESTING to be enabled")
endif()
if (CPPDUALS_CODE_COVERAGE)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
message(STATUS "Enabling coverage reporting")
# Add required flags (GCC & LLVM/Clang)
target_compile_options (cppduals_coverage_config INTERFACE
-O0 # no optimization
-g # generate debug info
--coverage # sets all required flags
-fprofile-arcs
-ftest-coverage
)
target_link_options (cppduals_coverage_config INTERFACE
--coverage
)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.13)
target_link_options (cppduals_coverage_config INTERFACE --coverage)
else()
target_link_libraries (cppduals_coverage_config INTERFACE --coverage)
# error out if coverage is enabled but compiler is not supported
message(FATAL_ERROR "Coverage reporting is disabled for unknown compilers.")
endif ()
endif ()
@ -221,3 +232,8 @@ if (ETAGS)
COMMAND ${ETAGS} --language=c++ --append `find ${PROJECT_BINARY_DIR}/thirdparty/eigenX/src/eigenX -type f`
)
endif (ETAGS)
#
# Packaging
#
include (CPack)

View File

@ -96,25 +96,6 @@ to specify library dependencies:
target_link_libraries (your_target PRIVATE cppduals::duals)
```
Older versions of CMake can achieve a similar result using the ``ExternalProject``
family of commands and modifying the global preprocessor search path:
```cmake
include(ExternalProject)
# Have CMake download the library headers only
set (CPPDUALS_TAG v0.4.1)
set (CPPDUALS_MD5 7efe49496b8d0e3d3ffbcd3c68f542f3)
ExternalProject_Add (cppduals
URL https://gitlab.com/tesch1/cppduals/-/archive/${CPPDUALS_TAG}/cppduals-${CPPDUALS_TAG}.tar.bz2
URL_HASH MD5=${CPPDUALS_MD5}
CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" )
# Make include directory globally visible
ExternalProject_Get_Property (cppduals source_dir)
include_directories (${source_dir}/)
```
Alternatively, `cppduals` supports installation and discovery via the
`find_package` utility. First, download and install the library to a
location of your choosing:
@ -299,6 +280,50 @@ thus licensed under [MPL-2](http://www.mozilla.org/MPL/2.0/FAQ.html) .
ChangeLog
=========
v0.6.0
======
- target at least c++17.
- tested with eigen 3.3.7 & 3.3.8.
- rearrange how we're (illegally using/abusing) std:: by moving many implementation details
into duals::detail tricks - makes everything work with LIBCPP on osx now (as of Sequoia 15.2).
- upgrade google test & benchmark libraries.
- update to more modern cmake, at least 3.14 required now.
- dont try to use Eigen's .exp() with duals, not supported.
Known Issues
- fmt library support is very out of date - should update to support std::format.
- coverage is not working.
- SSE/AVX not working - open to fixes but dont have a machine to test on at the moment.
v0.5.4
======
- upgrade google test library
v0.5.3
======
- fix some problem with pow()
v0.5.2
======
- change optional libfmt print support to fmt 7.1.3 (from 6.x)
- change default build standard to c++14.
v0.5.1
======
- packaging cleanup
v0.5.0
======
- added ARM NEON support. tested on apple M1 - note apple's BLAS gemm
is ~2x faster than Eigen-generated matrix mul :(
- fixed atan2 and pow
v0.4.1
======
@ -351,4 +376,4 @@ Todo
- Add multi-variate differentiation capability.
- Non-x86_64 (CUDA/AltiVec/HIP/NEON/...) vectorization.
- Higher-order derivatives.
- finish NEON (is why clang failing on osx? or just make it faster!)

View File

@ -10,6 +10,7 @@
#ifndef EIGEN_DUAL_SSE_H
#define EIGEN_DUAL_SSE_H
#include <pmmintrin.h> // SSE3
namespace Eigen {
@ -150,17 +151,9 @@ template<> EIGEN_STRONG_INLINE void prefetch<duals::dual<float> >(const duals::d
template<> EIGEN_STRONG_INLINE duals::dual<float> pfirst<Packet2df>(const Packet2df& a)
{
#if EIGEN_GNUC_AT_MOST(4,3)
// Workaround gcc 4.2 ICE - this is not performance wise ideal, but who cares...
// This workaround also fix invalid code generation with gcc 4.3
EIGEN_ALIGN16 duals::dual<float> res[2];
_mm_store_ps((float*)res, a.v);
return res[0];
#else
duals::dual<float> res;
_mm_storel_pi((__m64*)&res, a.v);
return res;
#endif
}
template<> EIGEN_STRONG_INLINE Packet2df preverse(const Packet2df& a)

File diff suppressed because it is too large Load Diff

View File

@ -141,7 +141,6 @@ namespace Eigen {
template<typename T>
struct NumTraits<duals::dual<T> > : GenericNumTraits<T>
{
typedef typename NumTraits<T>::Real ReallyReal;
typedef duals::dual<T> Real;
typedef duals::dual<T> Literal;
typedef duals::dual<T> Nested;
@ -159,13 +158,13 @@ struct NumTraits<duals::dual<T> > : GenericNumTraits<T>
EIGEN_DEVICE_FUNC
static inline Real epsilon() { return Real(NumTraits<T>::epsilon()); }
EIGEN_DEVICE_FUNC
static inline ReallyReal dummy_precision() { return NumTraits<T>::dummy_precision(); }
static inline Real dummy_precision() { return NumTraits<T>::dummy_precision(); }
EIGEN_DEVICE_FUNC
static inline ReallyReal highest() { return NumTraits<T>::highest(); }
static inline Real highest() { return NumTraits<T>::highest(); }
EIGEN_DEVICE_FUNC
static inline ReallyReal lowest() { return NumTraits<T>::lowest(); }
static inline Real lowest() { return NumTraits<T>::lowest(); }
EIGEN_DEVICE_FUNC
static inline ReallyReal digits10() { return NumTraits<T>::digits10(); }
static inline int digits10() { return NumTraits<T>::digits10(); }
};
#if !defined(CPPDUALS_NO_EIGEN_PROMOTION)
@ -218,6 +217,20 @@ using duals::dconj;
namespace internal {
#if 0
// For MatrixExponential.h to treat duals::dual<T> as a known type and compile it
template<typename T> struct is_exp_known_type;
template<typename MatrixType, typename T> struct matrix_exp_computeUV;
template<typename T> struct is_exp_known_type<duals::dual<T>> : is_exp_known_type<T> {};
template <typename MatrixType, typename T>
struct matrix_exp_computeUV<MatrixType, duals::dual<T> > : matrix_exp_computeUV<MatrixType, T>
{
typedef typename NumTraits<typename traits<MatrixType>::Scalar>::Real RealScalar;
};
#endif
#if 1
// this is used by the packet math for SSE to copy raw duals around.
template<typename T>
struct real_impl<duals::dual<T> >
{
@ -251,6 +264,43 @@ struct real_ref_retval<duals::dual<Scalar>>
typedef typename NumTraits<Scalar>::Real & type;
};
#else ////
template<typename T>
struct real_impl<duals::dual<T> >
{
typedef duals::dual<T> RealScalar;
EIGEN_DEVICE_FUNC
static inline RealScalar run(const duals::dual<T>& x)
{
return x;
}
};
template<typename Scalar>
struct real_ref_impl<duals::dual<Scalar>>
{
typedef typename NumTraits<duals::dual<Scalar> >::Real RealScalar;
EIGEN_DEVICE_FUNC
static inline RealScalar & run(duals::dual<Scalar> & x)
{
return reinterpret_cast<RealScalar*>(&x)[0];
}
EIGEN_DEVICE_FUNC
static inline const RealScalar & run(const duals::dual<Scalar> & x)
{
return reinterpret_cast<const RealScalar *>(&x)[0];
}
};
template<typename Scalar>
struct real_ref_retval<duals::dual<Scalar>>
{
typedef typename NumTraits<duals::dual<Scalar>>::Real & type;
};
#endif /// 0
template<typename T> struct scalar_random_op<duals::dual<T>>
{
EIGEN_EMPTY_STRUCT_CTOR(scalar_random_op)
@ -384,7 +434,8 @@ template<typename RealScalar,bool Conj> struct dconj_helper<RealScalar, duals::d
#elif defined(EIGEN_VECTORIZE_ALTIVEC) || defined(EIGEN_VECTORIZE_VSX)
// #include "duals/arch/AltiVec/Dual.h" // TODO
#elif defined EIGEN_VECTORIZE_NEON
//#include "duals/arch/NEON/Dual.h" // TODO
#include "duals/arch/NEON/Dual.h"
#include "duals/arch/NEON/ComplexDual.h"
#elif defined EIGEN_VECTORIZE_ZVECTOR
// #include "duals/arch/ZVector/Dual.h" // TODO
#endif

View File

@ -10,47 +10,53 @@
# Public License v. 2.0. If a copy of the MPL was not distributed
# with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
# gtest_discover_tests requires 3.10
cmake_minimum_required (VERSION 3.10)
# Configure google-test as a downloadable library.
include (GoogleTest)
cmake_minimum_required (VERSION 3.14)
if (WIN32)
add_definitions (-D_USE_MATH_DEFINES)
endif ()
include_directories ("${CMAKE_SOURCE_DIR}")
include_directories ("${DEPS_ROOT}/include")
include_directories ("${EIGEN3_INCLUDE_DIRS}")
#include_directories ("${MPFR_INCLUDES}")
include_directories ("${EXPOKIT_INCLUDE_DIR}")
set (IOFORMAT "IOFormat(FullPrecision, DontAlignCols, \", \", \"\\$<SEMICOLON>\\n\", \"\", \"\", \"[\", \"]\")")
add_definitions (-DEIGEN_DEFAULT_IO_FORMAT=${IOFORMAT})
#add_definitions (-DEIGEN_DEFAULT_IO_FORMAT=EIGEN_IO_FORMAT_OCTAVE)
#
# Correctness & Coverage
#
if (NOT MSVC)
set (OPT_FLAGS "-O2")
set (OPT_FLAGS "-O3;-msse3")
set (OPT_FLAGS "-O3;-mavx2;-mfma")
set (OPT_FLAGS "-O3;-march=native")
message ("OSX_ARCHITECTURES: ${CMAKE_SYSTEM_PROCESSOR}")
set (OSX_ARCHITECTURES "arm64;x86_64")
if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
set (X86 TRUE)
else ()
set (OPT_FLAGS "/arch:IA32")
set (OPT_FLAGS "/arch:SSE")
set (OPT_FLAGS "/arch:SSE2")
set (OPT_FLAGS "/arch:AVX2")
set (X86 FALSE)
endif ()
# Set optimization flags only if coverage is not enabled
if (NOT CPPDUALS_CODE_COVERAGE)
if (X86)
if (NOT MSVC)
set (OPT_FLAGS "-O3;-march=native")
else ()
set (OPT_FLAGS "/arch:AVX2")
endif ()
else ()
set (OPT_FLAGS "-O3")
endif ()
else()
if (X86)
if (NOT MSVC)
set (OPT_FLAGS "-mavx2")
else ()
set (OPT_FLAGS "/arch:AVX2")
endif ()
else ()
set (OPT_FLAGS "")
endif ()
endif ()
#set (OPT_FLAGS "${OPT_FLAGS};-fsanitize=address;-fno-omit-frame-pointer")
set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_VECTORIZE_CDUAL")
#set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE")
#set (OPT_FLAGS "${OPT_FLAGS};-DEIGEN_DONT_VECTORIZE")
set (ALL_TESTS
test_dual test_funcs test_eigen test_packets
test_dual test_cdual test_funcs test_eigen test_packets
test_vectorize test_solve test_expm test_1 test_fmt
example
)
@ -70,33 +76,30 @@ foreach (TEST_ ${ALL_TESTS})
add_executable (${TEST} ${TEST_}.cpp)
set (PHASE_FLAGS ${OPT_FLAGS} -DPHASE_${PHASE})
string (REPLACE ";" ", " L2 "${CMAKE_CXX_FLAGS}")
string (REPLACE ";" ", " L2 "${OPT_FLAGS};${CMAKE_CXX_FLAGS}")
target_compile_options (${TEST} PUBLIC ${PHASE_FLAGS})
target_compile_definitions (${TEST} PRIVATE "OPT_FLAGS=${L2}")
target_link_libraries (${TEST} gtest_main cppduals_coverage_config)
#target_link_libraries (${TEST} -lasan)
add_dependencies (${TEST} eigenX expokitX)
# Link with coverage config first to ensure flags are used
target_link_libraries (${TEST}
cppduals_coverage_config # Link coverage first
gtest_main
eigen
expokit
)
gtest_discover_tests (${TEST} TEST_LIST ${TEST}_targets)
set_tests_properties (${${TEST}_targets} PROPERTIES TIMEOUT 10)
# -ftest-coverage
endforeach (PHASE)
endforeach (TEST_)
# special for fmt
target_compile_features (test_fmt_1 PUBLIC cxx_std_14)
target_link_libraries (test_fmt_1 fmt::fmt)
if (CPPDUALS_BENCHMARK)
#
# Benchmarks
#
message ("searching: ${DEPS_ROOT} for google benchmark libs")
find_library (BENCHMARK_LIBRARY benchmark PATHS ${DEPS_ROOT}/lib)
find_library (BENCHMARKM_LIBRARY benchmark_main PATHS ${DEPS_ROOT}/lib)
#find_library (PTHREAD_LIBRARY pthread)
message ("BENCHMARK_LIBRARY: ${BENCHMARK_LIBRARY}")
include_directories ("${BENCHMARK_INC_DIR}")
if (Boost_FOUND AND NO)
add_definitions (-DHAVE_BOOST=1)
include_directories ("${Boost_INCLUDE_DIRS}")
@ -110,11 +113,14 @@ if (CPPDUALS_BENCHMARK)
set (BLA_STATIC OFF)
endif (NOT BLA_STATIC)
set (BLA_VENDOR OpenBLAS)
endif (NOT APPLE AND NOT BLA_VENDOR)
endif ()
find_package (BLAS REQUIRED)
#find_package (LAPACK REQUIRED)
add_definitions (-DHAVE_BLAS)
#add_definitions (-DEIGEN_USE_BLAS)
if (APPLE)
add_definitions (-DACCELERATE_NEW_LAPACK -DACCELERATE_LAPACK_ILP64)
endif ()
# find lapacke.h cblas.h
set (CBLAS_HINTS ${BLAS_DIR} ${LAPACK_DIR} /usr /usr/local /opt /opt/local)
@ -124,18 +130,21 @@ if (CPPDUALS_BENCHMARK)
/opt
/opt/local
/usr/local/opt
/System/Library/Frameworks)
/System/Library/Frameworks
${BLAS_LIBRARIES}
)
# Finds the include directories for lapacke.h
find_path (LAPACKE_INCLUDE_DIRS
NAMES lapacke.h
REQUIRED
NAMES lapacke.h clapack.h
HINTS ${CBLAS_HINTS}
PATH_SUFFIXES
include inc include/x86_64 include/x64
openblas/include
# Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Versions/Current/Headers
openblas/include openblas
Frameworks/vecLib.framework/Headers
PATHS ${CBLAS_PATHS}
DOC "LAPACK(E) include header lapacke.h")
DOC "LAPACK(E) include header lapacke.h/clapack.h")
mark_as_advanced (LAPACKE_INCLUDE_DIRS)
if (LAPACKE_INCLUDE_DIRS)
include_directories (${LAPACKE_INCLUDE_DIRS})
@ -145,12 +154,13 @@ if (CPPDUALS_BENCHMARK)
# Finds the include directories for cblas*.h
find_path (CBLAS_INCLUDE_DIRS
REQUIRED
NAMES cblas.h cblas_openblas.h cblas-openblas.h
HINTS ${CBLAS_HINTS}
PATH_SUFFIXES
include inc include/x86_64 include/x64
openblas/include
# Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Versions/Current/Headers
openblas/include openblas
Frameworks/vecLib.framework/Headers
PATHS ${CBLAS_PATHS}
DOC "BLAS include header cblas.h")
mark_as_advanced (CBLAS_INCLUDE_DIRS)
@ -161,80 +171,168 @@ if (CPPDUALS_BENCHMARK)
break()
endif (EXISTS "${CBLAS_INCLUDE_DIRS}/${cblas}")
endforeach (cblas)
message ("Found BLAS : ${BLAS_LIBRARIES}")
message ("Found cBLAS : ${CBLAS_INCLUDE_DIRS}")
message ("Found lapacke : ${LAPACKE_INCLUDE_DIRS}")
set (OPT_FLAGS "")
set (BMK_FLAGS "")
if (NOT MSVC)
#set (OPT_FLAGS "-O3;-mavx")
#set (OPT_FLAGS "-O3;-march=native;-fopenmp")
set (OPT_FLAGS "-O3;-msse3;-fopenmp")
set (OPT_FLAGS "-O3")
set (OPT_FLAGS "-O3;-msse3")
set (OPT_FLAGS "-O3;-march=native;-funroll-loops")
set (OPT_FLAGS "-O3;-msse3;-mavx2;-mfma")
set (OPT_FLAGS "-O3;-march=native")
#set (OPT_FLAGS "${OPT_FLAGS};-save-temps;-fverbose-asm")
#set (BMK_FLAGS "-O3;-mavx")
#set (BMK_FLAGS "-O3;-march=native;-fopenmp")
if (X86)
set (BMK_FLAGS "-msse3;-fopenmp")
set (BMK_FLAGS "-msse3")
set (BMK_FLAGS "-march=native;-funroll-loops")
set (BMK_FLAGS "-msse3;-mavx2;-mfma")
else ()
set (OPT_FLAGS "/arch:IA32")
set (OPT_FLAGS "/arch:SSE")
set (OPT_FLAGS "/arch:SSE2")
set (OPT_FLAGS "/arch:AVX2")
set (BMK_FLAGS "-march=native")
endif ()
#set (BMK_FLAGS "-O3;${BMK_FLAGS}")
#set (BMK_FLAGS "${BMK_FLAGS};-save-temps;-fverbose-asm")
else ()
set (BMK_FLAGS "/arch:IA32")
set (BMK_FLAGS "/arch:SSE")
set (BMK_FLAGS "/arch:SSE2")
set (BMK_FLAGS "/arch:AVX2")
endif ()
#set (OPT_FLAGS "${OPT_FLAGS};-DEIGEN_DONT_VECTORIZE")
#set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE")
#set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE_CDUAL")
#set (BMK_FLAGS "${BMK_FLAGS};-DEIGEN_DONT_VECTORIZE")
#set (BMK_FLAGS "${BMK_FLAGS};-DCPPDUALS_DONT_VECTORIZE")
#set (BMK_FLAGS "${BMK_FLAGS};-DCPPDUALS_DONT_VECTORIZE_CDUAL")
foreach (BENCH bench_dual bench_eigen bench_gemm bench_example bench_fmt)
add_executable (${BENCH} ${BENCH}.cpp)
target_compile_options (${BENCH} PUBLIC ${OPT_FLAGS})
foreach (VECTORIZE YES NO)
foreach (BENCH bench_dual bench_eigen bench_exp bench_gemm bench_example bench_fmt)
if (NOT VECTORIZE)
set (BENCHE ${BENCH})
else ()
set (BENCHE ${BENCH}_novec)
endif ()
add_executable (${BENCHE} ${BENCH}.cpp)
target_compile_options (${BENCHE} PUBLIC ${BMK_FLAGS})
if (NOT VECTORIZE)
target_compile_options (${BENCHE} PUBLIC "-DEIGEN_DONT_VECTORIZE")
endif()
#set_target_properties (${BENCH} PROPERTIES LINK_FLAGS -fopenmp)
#target_link_options (${BENCH} PUBLIC ${OPT_FLAGS})
string (REPLACE ";" ", " L2 "${OPT_FLAGS} ${CMAKE_CXX_FLAGS}")
target_compile_definitions (${BENCH} PRIVATE "OPT_FLAGS=${L2}")
add_dependencies (${BENCH} benchmarkX eigenX expokitX)
target_link_libraries (${BENCH} ${BENCHMARK_LIBRARY} -lpthread ${BLAS_LIBRARIES})
endforeach (BENCH)
#target_link_options (${BENCH} PUBLIC ${BMK_FLAGS})
string (REPLACE ";" ", " L2 "${BMK_FLAGS} ${CMAKE_CXX_FLAGS}")
target_compile_definitions (${BENCHE} PRIVATE "BMK_FLAGS=${L2}")
target_link_libraries (${BENCHE} benchmark::benchmark ${BLAS_LIBRARIES} eigen expokit)
endforeach ()
endforeach ()
target_link_libraries (bench_fmt fmt::fmt)
target_link_libraries (bench_fmt_novec fmt::fmt)
endif (CPPDUALS_BENCHMARK)
add_executable (sandbox sandbox.cpp)
add_dependencies (sandbox eigenX expokitX ) # mpfrX mprealX
#target_compile_options (sandbox PUBLIC ${OPT_FLAGS})
#target_compile_options (sandbox PUBLIC ${BMK_FLAGS})
target_compile_options (sandbox PUBLIC -DCPPDUALS_VECTORIZE_CDUAL)
if (MSVC)
if (X86)
target_compile_options (sandbox PUBLIC /arch:AVX2)
endif ()
else ()
if (X86)
target_compile_options (sandbox PUBLIC -O1 -msse3 -mavx2 -mfma)
else ()
target_compile_options (sandbox PUBLIC -O1 ) # -mfpu=neon
endif ()
endif ()
set_target_properties (sandbox PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
target_link_libraries (sandbox PUBLIC cppduals_coverage_config)
target_link_libraries (sandbox PUBLIC cppduals_coverage_config eigen expokit)
#
# Generate coverage reports
#
if (CODE_COVERAGE)
if (CPPDUALS_CODE_COVERAGE)
# Find required tools
get_filename_component(CMAKE_CXX_COMPILER_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY)
set(GENHTML_PATH ${CMAKE_CXX_COMPILER_DIR}/genhtml)
if(NOT EXISTS ${GENHTML_PATH})
find_program(GENHTML_PATH genhtml REQUIRED)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Clang
# often in the same directory as clang - search there too
get_filename_component(CMAKE_CXX_COMPILER_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY)
set(LLVM_COV_PATH ${CMAKE_CXX_COMPILER_DIR}/llvm-cov)
set(LLVM_PROFDATA_PATH ${CMAKE_CXX_COMPILER_DIR}/llvm-profdata)
if(NOT EXISTS ${LLVM_COV_PATH})
find_program(LLVM_COV_PATH llvm-cov REQUIRED)
endif()
if(NOT EXISTS ${LLVM_PROFDATA_PATH})
find_program(LLVM_PROFDATA_PATH llvm-profdata REQUIRED)
endif()
add_custom_target(cov
DEPENDS ${ALL_TEST_BINS}
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test
COMMAND $<TARGET_FILE:sandbox>
COMMAND lcov --capture --directory . --output-file coverage.info
COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info
COMMAND lcov --remove coverage.info '*/thirdparty/*' --output-file coverage.info
COMMAND lcov --remove coverage.info '*/googletest/*' --output-file coverage.info
COMMAND lcov --list coverage.info
COMMAND ${CMAKE_COMMAND} -E remove_directory coverage/profraw
COMMAND ${CMAKE_COMMAND} -E make_directory coverage/profraw
COMMAND ${CMAKE_COMMAND} --build . --target test "LLVM_PROFILE_FILE=coverage/profraw/%p.profraw"
COMMAND ${LLVM_PROFDATA_PATH} merge -sparse coverage/profraw/*.profraw -o coverage/coverage.profdata
COMMAND ${LLVM_COV_PATH} show
-instr-profile=coverage/coverage.profdata
-format=html -output-dir=coverage/html
-show-line-counts-or-regions
-show-instantiation-summary
${ALL_TEST_BINS}
COMMAND ${LLVM_COV_PATH} report
-instr-profile=coverage/coverage.profdata
${ALL_TEST_BINS}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
# GCC
set(LCOV_PATH ${CMAKE_CXX_COMPILER_DIR}/lcov)
if(NOT EXISTS ${LCOV_PATH})
find_program(LCOV_PATH lcov REQUIRED)
endif()
# Extract GCC version number and use matching gcov version
execute_process(
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(GCOV_PATH ${CMAKE_CXX_COMPILER_DIR}/gcov-${GCC_VERSION})
if(NOT EXISTS ${GCOV_PATH})
find_program(GCOV_PATH gcov-${GCC_VERSION} REQUIRED)
endif()
add_custom_target(cov
DEPENDS ${ALL_TEST_BINS}
COMMAND ${CMAKE_COMMAND} -E make_directory coverage
COMMAND ${LCOV_PATH} --directory . --zerocounters
# Add initial capture before running tests
COMMAND ${LCOV_PATH} --directory . --capture --initial --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.base --ignore-errors inconsistent
# Run tests and capture coverage data
COMMAND ctest --output-on-failure
COMMAND ${LCOV_PATH} --directory . --capture --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info --ignore-errors inconsistent
# Combine baseline and test coverage data
COMMAND ${LCOV_PATH} --add-tracefile coverage/coverage.base --add-tracefile coverage/coverage.info --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.total
# Only look at the coverage of the tests and duals library
COMMAND ${LCOV_PATH} --extract coverage/coverage.total '*/tests/*' '*/duals/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info
# Remove unwanted paths
#COMMAND ${LCOV_PATH} --remove coverage/coverage.total '/usr/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info
#COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/thirdparty/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info
#COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/googletest/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info
# Add --ignore-errors empty to prevent failure on empty coverage data
COMMAND ${LCOV_PATH} --list coverage/coverage.info --ignore-errors empty --gcov-tool ${GCOV_PATH}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
else()
message(FATAL_ERROR "No coverage tool found for ${CMAKE_CXX_COMPILER_ID}")
endif()
add_custom_target(cov-html
DEPENDS cov
COMMAND rm -rf ../coverage
COMMAND genhtml --ignore-errors source coverage.info --legend --title "make cov"
--output-directory=../coverage
COMMAND echo "output in coverage/index.html"
COMMAND ${CMAKE_COMMAND} -E remove_directory coverage/html
COMMAND ${GENHTML_PATH} --ignore-errors source coverage/coverage.info --legend --title "cppduals coverage"
--output-directory=coverage/html
COMMAND ${CMAKE_COMMAND} -E echo "Coverage report generated at coverage/html/index.html"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif ()

View File

@ -11,13 +11,13 @@
// (c)2019 Michael Tesch. tesch1@gmail.com
//
#include <duals/dual_eigen>
#include <iostream>
#include <fstream>
#include <complex>
#include <memory>
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Core>
#include <Eigen/Dense>
@ -31,67 +31,6 @@ using namespace duals;
template< class T > struct type_identity { typedef T type; };
namespace Eigen {
namespace internal {
template<typename T> struct is_exp_known_type;
template<typename T> struct is_exp_known_type<std::complex<T>> : is_exp_known_type<T> {};
#if 0
template <typename RealScalar> struct MatrixExponentialScalingOp;
template <typename RealScalar>
struct MatrixExponentialScalingOp<duals::dual<RealScalar>>
{
MatrixExponentialScalingOp(int squarings) : m_squarings(squarings) { }
inline const duals::dual<RealScalar> operator() (const duals::dual<RealScalar> & x) const
{
using std::ldexp;
return ldexp(x, -m_squarings);
}
typedef std::complex<duals::dual<RealScalar>> ComplexScalar;
inline const ComplexScalar operator() (const ComplexScalar& x) const
{
using std::ldexp;
return ComplexScalar(ldexp(x.real(), -m_squarings), ldexp(x.imag(), -m_squarings));
}
private:
int m_squarings;
};
#endif
}}
#include <unsupported/Eigen/MatrixFunctions>
namespace Eigen {
namespace internal {
template <typename MatrixType, typename T>
struct matrix_exp_computeUV<MatrixType, duals::dual<T> >
{
typedef typename NumTraits<typename traits<MatrixType>::Scalar>::Real RealScalar;
template <typename ArgType>
static void run(const ArgType& arg, MatrixType& U, MatrixType& V, int& squarings)
{
using std::frexp;
using std::pow;
const RealScalar l1norm = arg.cwiseAbs().colwise().sum().maxCoeff();
squarings = 0;
if (l1norm < 1.495585217958292e-002) {
matrix_exp_pade3(arg, U, V);
} else if (l1norm < 2.539398330063230e-001) {
matrix_exp_pade5(arg, U, V);
} else if (l1norm < 9.504178996162932e-001) {
matrix_exp_pade7(arg, U, V);
} else if (l1norm < 2.097847961257068e+000) {
matrix_exp_pade9(arg, U, V);
} else {
const RealScalar maxnorm = 5.371920351148152;
frexp(l1norm / maxnorm, &squarings);
if (squarings < 0) squarings = 0;
MatrixType A = arg.unaryExpr(MatrixExponentialScalingOp<RealScalar>(squarings));
matrix_exp_pade13(A, U, V);
}
}
};
}}
/* encode the type into an integer for benchmark output */
template<typename Tp> struct type_num { /* should fail */ };
template<> struct type_num<float> { static constexpr int id = 1; };
@ -271,87 +210,6 @@ template <class Rt, class U> void B_MatVec(benchmark::State& state) {
state.SetComplexityN(state.range(0));
}
template <class Rt> void B_Expm(benchmark::State& state)
{
int N = state.range(0);
//Rt S(1);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> B = MatrixX<Rt>::Zero(N, N);
//A = S * A / A.norm();
for (auto _ : state) {
B = A.exp();
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
template <class Rt> void B_ExpPadm(benchmark::State& state)
{
int N = state.range(0);
//Rt S(1);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> B = MatrixX<Rt>::Zero(N, N);
//A = S * A / A.norm();
for (auto _ : state) {
B = eexpokit::padm(A);
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
template <class Rt> void B_ExpExpv(benchmark::State& state)
{
int N = state.range(0);
//Rt S(1);
MatrixX<Rt> A = MatrixX<Rt>::Zero(N, N);
MatrixX<Rt> b = MatrixX<Rt>::Ones(N, 1);
MatrixX<Rt> c = MatrixX<Rt>::Zero(N, 1);
//A = S * A / A.norm();
// sparse random fill
for (int i = 0; i < 4*N; i++)
A((int)duals::randos::random(0.,N-1.),
(int)duals::randos::random(0.,N-1.)) = duals::randos::random2<Rt>();
for (auto _ : state) {
auto ret = eexpokit::expv(1,A,b);
if (ret.err > 1) {
std::ofstream f("fail.m");
f << "A=" << A.format(eexpokit::OctaveFmt) << "\n";
break;
}
// c = ret.w
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
template <class Rt> void B_ExpChbv(benchmark::State& state)
{
int N = state.range(0);
//Rt S(1);
MatrixX<Rt> A = MatrixX<Rt>::Random(N, N);
MatrixX<Rt> b = MatrixX<Rt>::Zero(N, 1);
MatrixX<Rt> c = MatrixX<Rt>::Zero(N, 1);
//A = S * A / A.norm();
for (auto _ : state) {
c = eexpokit::chbv(A,b);
benchmark::ClobberMemory();
}
state.counters["type"] = type_num<Rt>::id;
state.SetComplexityN(state.range(0));
}
#define MAKE_BM_SIMPLE(TYPE1,TYPE2,NF) \
BENCHMARK_TEMPLATE(B_VecVecAdd, TYPE1,TYPE2) V_RANGE(4,NF); \
BENCHMARK_TEMPLATE(B_VecVecSub, TYPE1,TYPE2) V_RANGE(4,NF); \
@ -359,11 +217,7 @@ template <class Rt> void B_ExpChbv(benchmark::State& state)
BENCHMARK_TEMPLATE(B_VecVecDiv, TYPE1,TYPE2) V_RANGE(4,NF); \
BENCHMARK_TEMPLATE(B_MatVec, TYPE1,TYPE2) V_RANGE(4,NF); \
BENCHMARK_TEMPLATE(B_MatMat, TYPE1,TYPE2) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_MatDiv, TYPE1,TYPE2) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_Expm, TYPE1) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_ExpPadm, TYPE1) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_ExpChbv, TYPE1) V_RANGE(1,NF); \
BENCHMARK_TEMPLATE(B_ExpExpv, TYPE1) V_RANGE(1,NF)
BENCHMARK_TEMPLATE(B_MatDiv, TYPE1,TYPE2) V_RANGE(1,NF)
#define MAKE_BENCHMARKS(TYPE1,TYPE2,NF) \
MAKE_BM_SIMPLE(TYPE1,TYPE2,NF)
@ -389,7 +243,7 @@ MAKE_BM_SIMPLE(cduald, cduald,4);
int main(int argc, char** argv)
{
#ifndef EIGEN_VECTORIZE
static_assert(false, "no vectorization?");
//static_assert(false, "no vectorization?");
#endif
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";

View File

@ -6,12 +6,14 @@
//
// (c)2019 Michael Tesch. tesch1@gmail.com
//
#include <duals/dual>
#if defined(__APPLE__) && defined(__clang__)
#include <Accelerate/Accelerate.h>
#else
#ifdef EIGEN_LAPACKE
#if defined(EIGEN_LAPACKE) || defined(__APPLE__)
#include <Eigen/src/misc/lapacke.h>
#else
#include <lapacke.h>
@ -24,13 +26,13 @@ extern "C" {
}
#endif // defined(__APPLE__) && defined(__clang__)
#include <duals/dual_eigen>
#include <iostream>
#include <fstream>
#include <complex>
#include <memory>
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Core>
#include <Eigen/Dense>
@ -80,6 +82,59 @@ template <class T, class U> void B_MatMat(benchmark::State& state) {
state.SetComplexityN(state.range(0));
}
// Helper templates to select correct BLAS routine
template <typename U>
struct blas_gemm;
#define TRANSPOSE(X) ((X) ? CblasTrans : CblasNoTrans)
template <>
struct blas_gemm<float> {
static void call(bool tA, bool tB, int m, int n, int k, float alpha, float *A,
int lda, float *B, int ldb, float beta, float *C, int ldc)
{
cblas_sgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), m, n, k, alpha, A,
lda, B, ldb, beta, C, ldc);
}
};
template <>
struct blas_gemm<double> {
static void call(bool tA, bool tB, int m, int n, int k, double alpha,
double *A, int lda, double *B, int ldb, double beta,
double *C, int ldc)
{
cblas_dgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), m, n, k, alpha, A,
lda, B, ldb, beta, C, ldc);
}
};
template <>
struct blas_gemm<std::complex<float>> {
static void call(bool tA, bool tB, int m, int n, int k,
std::complex<float> alpha, std::complex<float> *A, int lda,
std::complex<float> *B, int ldb, std::complex<float> beta,
std::complex<float> *C, int ldc)
{
cblas_cgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), m, n, k, &alpha, A,
lda, B, ldb, &beta, C, ldc);
}
};
template <>
struct blas_gemm<std::complex<double>> {
static void call(bool tA, bool tB, int m, int n, int k,
std::complex<double> alpha, std::complex<double> *A, int lda,
std::complex<double> *B, int ldb, std::complex<double> beta,
std::complex<double> *C, int ldc)
{
cblas_zgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB), m, n, k, &alpha, A,
lda, B, ldb, &beta, C, ldc);
}
};
#undef TRANSPOSE
template <class T, typename std::enable_if<!duals::is_dual<T>::value>::type* = nullptr>
void matrix_multiplcation(T *A, int Awidth, int Aheight,
T *B, int Bwidth, int Bheight,
@ -99,31 +154,12 @@ void matrix_multiplcation(T *A, int Awidth, int Aheight,
assert(A_width == B_height);
int lda = tA ? m : k;
int ldb = tB ? k : n;
#define TRANSPOSE(X) ((X) ? CblasTrans : CblasNoTrans)
// http://www.netlib.org/lapack/explore-html/d7/d2b/dgemm_8f.html
if (!is_complex<T>::value) {
if (sizeof(T) == sizeof(float))
cblas_sgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB),
m, n, k, 1.0, (float *)A, lda, (float *)B, ldb,
std::real(beta), (float *)AB, n);
else
cblas_dgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB),
m, n, k, 1.0, (double *)A, lda, (double *)B, ldb,
std::real(beta), (double *)AB, n);
}
else {
std::complex<float> alphaf(1,0);
std::complex<double> alpha(1,0);
if (Eigen::NumTraits<T>::digits10() < 10)
cblas_cgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB),
m, n, k, &alphaf, A, lda, B, ldb, &beta, AB, n);
else
cblas_zgemm(CblasColMajor, TRANSPOSE(tA), TRANSPOSE(tB),
m, n, k, &alpha, A, lda, B, ldb, &beta, AB, n);
}
#undef TRANSPOSE
// Call the appropriate BLAS routine based on type T
blas_gemm<T>::call(tA, tB, m, n, k, T(1), A, lda, B, ldb, beta, AB, n);
}
template <class T, typename std::enable_if<duals::is_dual<T>::value>::type* = nullptr>
void matrix_multiplcation(T *A, int Awidth, int Aheight,
T *B, int Bwidth, int Bheight,
@ -232,10 +268,10 @@ MAKE_BM_SIMPLE(cduald, cduald,4);
int main(int argc, char** argv)
{
#ifndef EIGEN_VECTORIZE
static_assert(false, "no vectorization?");
//static_assert(false, "no vectorization?");
#endif
#ifndef NDEBUG
static_assert(false, "NDEBUG to benchmark?");
//static_assert(false, "NDEBUG to benchmark?");
#endif
std::cout << "OPT_FLAGS=" << QUOTE(OPT_FLAGS) << "\n";
std::cout << "INSTRUCTIONSET=" << Eigen::SimdInstructionSetsInUse() << "\n";

View File

@ -12,12 +12,12 @@
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include <duals/dual_eigen>
#include <math.h>
#include <iostream>
#include <iomanip>
#include "type_name.hpp"
#include <duals/dual_eigen>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <unsupported/Eigen/MatrixFunctions>
@ -60,13 +60,45 @@ template <class T>
struct common_type<Rando<T>,T> { typedef Rando<T> type; };
}
#if 0
#if EIGEN_ARCH_ARM64
int main(int argc, char * argv[])
{
emtx<cduald,50> A,B,C;
//emtx<complexd,50> A,B,C;
C = A * B;
//
using namespace Eigen::internal;
float32x4_t a, b, v3;
float32x2_t f2;
float32x4x2_t yy;
float ff[] = {1., 2., 3., 4.};
duals::dual<double> x;
const uint64x2_t maskq = {0, (uint64_t)-1};
const uint64x2_t imaskq = {(uint64_t)-1, 0};
std::cout << "a:" << std::hex << maskq[0] << "\n";
std::cout << "b:" << maskq[1] << "\n";
std::cout << "v3=" << v3[0] << ", " << v3[1] << ", " << v3[2] << ", " << v3[3] << "\n";
std::cout << "f2=" << f2[0] << ", " << f2[1] << "\n";
std::cout << ff[0] << ", " << ff[1] << ", " << ff[2] << ", " << ff[3] << "\n";
#ifdef __ARM_NEON
std::cout << "__ARM_NEON:" << __ARM_NEON << "\n";
#endif
#ifdef __ARM_NEON_FP
std::cout << "__ARM_NEON_FP:" << __ARM_NEON_FP << "\n";
#endif
#ifdef __ARM_ARCH
std::cout << "__ARM_ARCH:" << __ARM_ARCH << "\n";
#endif
#ifdef __ARM_BIG_ENDIAN
std::cout << "__ARM_BIG_ENDIAN:" << __ARM_BIG_ENDIAN << "\n";
#endif
return 0;
}
#elif 0

View File

@ -81,9 +81,7 @@ expm4(const Eigen::EigenBase<DerivedA> & A_,
R.setIdentity();
R += B;
ReturnT S = B;
int ni = 0;
for (int ii = 2; ii < maxt; ii++) {
ni++;
S = Real(1.0/ii) * S * B;
R += S;
auto Sn = S.norm();

View File

@ -18,6 +18,7 @@
#include <duals/dual>
#include <complex>
#include <iomanip>
#include "gtest/gtest.h"
using duals::dualf;
@ -58,7 +59,7 @@ TEST(template_, dual_traits) {
// depth
EXPECT_EQ(dual_traits<float>::depth, 0);
EXPECT_EQ(dual_traits<complexf>::depth, 0);
EXPECT_EQ(dual_traits<cdualf>::depth, 0);
EXPECT_EQ(dual_traits<cdualf>::depth, 1);
EXPECT_EQ(dual_traits<dualf>::depth, 1);
EXPECT_EQ(dual_traits<hyperdualf>::depth, 2);
}
@ -186,6 +187,8 @@ TEST(template_, common_type) {
_EXPECT_TRUE(std::is_same<decltype(cd*cd), cdualf>);
_EXPECT_TRUE(std::is_same<decltype(cd*d), cdualf>);
_EXPECT_TRUE(std::is_same<decltype(d*cd), cdualf>);
_EXPECT_TRUE(std::is_same<decltype(cd*a), cdualf>);
_EXPECT_TRUE(std::is_same<decltype(a*cd), cdualf>);
_EXPECT_TRUE(std::is_same<decltype(cd*1), cdualf>);
_EXPECT_TRUE(std::is_same<decltype(1*cd), cdualf>);
@ -328,6 +331,7 @@ TEST(members, rpart) {
EXPECT_EQ(z.rpart(), 4);
EXPECT_EQ(z.dpart(), 3);
}
TEST(members, dpart) {
EXPECT_EQ(dpart(3), 0);
dualf z(2,3);
@ -555,6 +559,15 @@ TEST(comparison, ge) {
EXPECT_FALSE(1 >= a);
}
#if 0
TEST(simple_ops, add) {
// https://gitlab.com/tesch1/cppduals/-/issues/11
duals::dual<std::complex<double>> x;
x = x+std::complex<double>(1., 2.);
duals::dual<std::complex<double>> y = sqrt(x+std::complex<double>(1., 2.));
}
#endif
TEST(compound_assign, same_type) {
// OP=
dualf x = 2 + 4_e;
@ -977,25 +990,6 @@ TEST(non_class, random2) {
EXPECT_NE(c2.dpart(), 0);
EXPECT_NE(c1.rpart(), c2.rpart());
EXPECT_NE(c1.dpart(), c2.dpart());
// cdualf
cdualf d1 = duals::randos::random2<cdualf>();
cdualf d2 = duals::randos::random2<cdualf>();
EXPECT_NE(d1.real().rpart(), 0);
EXPECT_NE(d1.real().dpart(), 0);
EXPECT_NE(d1.imag().rpart(), 0);
EXPECT_NE(d1.imag().dpart(), 0);
EXPECT_NE(d2.real().rpart(), 0);
EXPECT_NE(d2.real().dpart(), 0);
EXPECT_NE(d2.imag().rpart(), 0);
EXPECT_NE(d2.imag().dpart(), 0);
EXPECT_NE(d1.real().rpart(), d2.real().rpart());
EXPECT_NE(d1.real().dpart(), d2.real().dpart());
EXPECT_NE(d1.imag().rpart(), d2.imag().rpart());
EXPECT_NE(d1.imag().dpart(), d2.imag().dpart());
}
TEST(smoke, funcs) {
@ -1097,6 +1091,17 @@ TEST(complex, mixing) {
// complex<dual> * real -> complex<dual>
// complex<real> * dual -> complex<dual> ?
// pow_dual_complex
B = pow(1_ef, C);
// pow_complex_dual
B = pow(C, 1_ef);
// pow_dual_dual
B = pow(1_ef, 2_ef);
// pow_dual_scalar
B = pow(1_ef, 2);
// pow_scalar_dual
B = pow(2, 1_ef);
}
int main(int argc, char **argv)

View File

@ -16,11 +16,12 @@
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include "type_name.hpp"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
#include <unsupported/Eigen/MatrixFunctions>
//#include <unsupported/Eigen/AutoDiff>
#include "eexpokit/padm.hpp"
@ -39,10 +40,13 @@ using duals::is_complex;
using duals::dual_traits;
using namespace duals::literals;
typedef std::complex<double> complexd;
typedef long double ldouble;
typedef std::complex<float> complexf;
typedef std::complex<duald> cduald;
typedef std::complex<double> complexd;
typedef std::complex<long double> complexld;
typedef std::complex<dualf> cdualf;
typedef std::complex<duald> cduald;
typedef std::complex<dualld> cdualld;
template <class eT, int N=Eigen::Dynamic, int K = N> using emtx = Eigen::Matrix<eT, N, K>;
template <class eT> using smtx = Eigen::SparseMatrix<eT>;
@ -60,49 +64,6 @@ template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
EXPECT_NEAR(rpart(A), rpart(B),tol); \
EXPECT_NEAR(dpart(A), dpart(B),tol)
/// Simple taylor series, truncated when |S| is "small enough"
template <class DerivedA, typename ReturnT = typename DerivedA::PlainObject>
ReturnT
expm4(const Eigen::EigenBase<DerivedA> & A_,
typename DerivedA::RealScalar mn = std::numeric_limits<typename DerivedA::RealScalar>::epsilon() * 1000)
{
//std::cerr << "do PO:" << type_name<typename DerivedA::PlainObject>() << "\n";
typedef typename DerivedA::RealScalar Real;
using std::isfinite;
const DerivedA & A = A_.derived();
int maxt = std::numeric_limits<Real>::digits;
int s = log2(rpart(A.derived().norm())) + 1;
s = std::max(0, s);
auto B = A * pow(Real(2), -s);
ReturnT R(A.rows(), A.cols());
R.setIdentity();
R += B;
ReturnT S = B;
for (int ii = 2; ii < maxt; ii++) {
S = S * B * Real(1.0/ii);
R += S;
auto Sn = S.norm();
if (!isfinite(Sn)) {
std::cout << "expm() non-finite norm:" << Sn << " at " << ii << "\n";
std::cout << " |R| = " << R.norm() << " s=" << s << "\n"
<< " |A| = " << rpart(A.real().norm()) << "\n"
<< " |A/2^s|=" << rpart(A.real().norm()/pow(2,s)) << "\n";
break;
}
// converged yet?
if (Sn < mn)
break;
if (ii == maxt - 1) {
std::cout << "expm() didn't converge in " << maxt << " |S| = " << Sn << "\n";
throw std::invalid_argument("no converge");
}
}
for (; s; s--)
R = R * R;
return R;
}
TEST(Eigen, NumTraits) {
//::testing::StaticAssertTypeEq<Eigen::NumTraits<duals::dual<float>>::Real, float>();
@ -448,11 +409,12 @@ TEST(measure, norm) {
b = 3;
Rt d(1);
MatrixD x;
x << d;
x.array() = d;
MatrixD a = (MatrixD() << 1,2,3, 4,5+5_ef,6, 7,8,9).finished();
//typename MatrixD::Index index;
EXPECT_EQ(a.sum(), 45 + 5_ef);
EXPECT_EQ(x.sum(), 9);
EXPECT_NEAR(rpart(a.norm()), 16.8819430161341337282, 1e-5);
EXPECT_NEAR(rpart(a.mean()), 5, 1e-5);
EXPECT_NEAR(dpart(a.mean()), 0.555555555555555, 1e-5);
@ -510,31 +472,49 @@ TEST(dpart, matrix) {
EXPECT_EQ((dpart(AA) - CC).norm(),0);
}
TEST(func, expm) {
typedef float T;
typedef dual<T> dualt;
typedef std::complex<dual<T>> cdualt;
#define NN 3
#define N2 6
emtx<dualt, NN> a,b;
a = emtx<dualt, NN>::Random();
a.array() += 1.1 + 2.2_ef;
a.setZero();
a = eexpokit::padm(a);
EXPECT_LT((a - emtx<dualt, NN>::Identity()).norm(), 1e-6) << "a=" << a << "\n";
a *= 1+2_e;
EXPECT_LT((a - emtx<dualt, NN>::Identity()).norm(), 1e-6) << "a=" << a << "\n";
TEST(eigen, exp_typechecks) {
typedef emtx<dualf,3> Mat;
typedef emtx<duald,3> Matd;
EXPECT_FALSE(Eigen::internal::is_exp_known_type<typename Mat::Scalar>::value);
EXPECT_FALSE(Eigen::internal::is_exp_known_type<typename Matd::Scalar>::value);
emtx<cdualt, NN> c;
//b = a + 1_e * emtx<cdualf, 3>::Random();
c.setZero();
c = c.exp();
//c = expm4(c);
EXPECT_LT((c - emtx<cdualf, NN>::Identity()).norm(), 1e-6) << "b=" << b << "\n";
#undef NN
#undef N2
typedef emtx<cdualf,3> Matc;
typedef emtx<cduald,3> Matcd;
EXPECT_FALSE(Eigen::internal::is_exp_known_type<typename Matc::Scalar>::value);
EXPECT_FALSE(Eigen::internal::is_exp_known_type<typename Matcd::Scalar>::value);
}
const bool _exp = true;
const bool _padm = false;
#define TEST_EXP(SCALAR_T, SIDE, EXP_OR_PADM) \
TEST(func, exp_##SCALAR_T##_##SIDE##EXP_OR_PADM) { \
emtx<SCALAR_T, SIDE> a,b; \
a = emtx<SCALAR_T, SIDE>::Random(); \
a.setZero(); \
if (EXP_OR_PADM == _exp) a = a.exp(); \
else a = eexpokit::padm(a); \
EXPECT_LT((a - emtx<SCALAR_T, SIDE>::Identity()).norm(), 1e-6) << "a=" << a << "\n"; \
}
#define TEST_EXP_SIZES(SCALAR_T, EXP_OR_PADM) \
TEST_EXP(SCALAR_T, 3, EXP_OR_PADM) \
TEST_EXP(SCALAR_T, 4, EXP_OR_PADM) \
TEST_EXP(SCALAR_T, 17, EXP_OR_PADM)
#define TEST_EXP_SIZES_EOP(SCALAR_T) \
TEST_EXP_SIZES(SCALAR_T, _padm) \
TEST_EXP_SIZES(SCALAR_T, _exp)
// just make sure padm is working
TEST_EXP_SIZES_EOP(float)
TEST_EXP_SIZES_EOP(double)
TEST_EXP_SIZES_EOP(ldouble)
TEST_EXP_SIZES_EOP(complexf)
TEST_EXP_SIZES_EOP(complexd)
TEST_EXP_SIZES_EOP(complexld)
/* testing engine */
#define QUOTE(...) STRFY(__VA_ARGS__)
#define STRFY(...) #__VA_ARGS__

View File

@ -16,8 +16,8 @@
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include "type_name.hpp"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
@ -104,7 +104,7 @@ expm4(const Eigen::EigenBase<DerivedA> & A_,
return R;
}
template <class T, int NN = 30, class DT = dual<T> >
template <class T, int NN = 30, class DT = dual<T>, int N2 = 2*NN>
void dexpm() {
//typedef std::complex<float> T;
//typedef std::complex<dual<T>> dualt;
@ -167,8 +167,6 @@ void dexpm() {
<< "eA2=" << eA2.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
EXPECT_LT((dA1 - dA2).norm(), tol) << "dA1=" << dA1.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n"
<< "dA2=" << dA2.block(0,0,std::min(4,NN),std::min(4,NN)) << "\n";
#undef NN
#undef N2
}
#if defined(PHASE_1)

View File

@ -14,6 +14,7 @@
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include <fmt/format.h>
//#include <fmt/std.h>
#define CPPDUALS_LIBFMT
#define CPPDUALS_LIBFMT_COMPLEX
#include <duals/dual>
@ -29,79 +30,131 @@ typedef std::complex<dualf> cdualf;
using namespace duals::literals;
using namespace std::complex_literals;
TEST(libfmt, float_) {
std::string s = fmt::format("{:.1f}", 2.f);
EXPECT_EQ(s, "2.0");
}
TEST(libfmt, double_) {
std::string s = fmt::format("{:.1f}", 2.);
EXPECT_EQ(s, "2.0");
}
TEST(libfmt, complex_) {
std::string s = fmt::format("{}", 2.f + 3if);
std::string s = fmt::format("{:.1f}", 2.f + 3if);
EXPECT_EQ(s, "(2.0+3.0if)");
s = fmt::format("{:.2f}", 2.f + 3if);
EXPECT_EQ(s, "(2.00+3.00if)");
}
TEST(libfmt, complex_el) {
std::string s = fmt::format("{}", 2.l + 3il);
EXPECT_EQ(s, "(2.0+3.0il)");
EXPECT_EQ(s, "(2+3il)");
}
TEST(libfmt, complex_flags) {
std::string s;
s = fmt::format("{}", 2. + 3i);
EXPECT_EQ(s, "(2.0+3.0i)");
EXPECT_EQ(s, "(2+3i)");
}
TEST(libfmt, complex_flags_dollar) {
std::string s;
s = fmt::format("{:$}", 2. + 3i);
EXPECT_EQ(s, "(2.0+3.0i)");
EXPECT_EQ(s, "(2+3i)");
}
TEST(libfmt, complex_flags_star) {
std::string s;
s = fmt::format("{:*}", 2. + 3i);
EXPECT_EQ(s, "(2+3*i)");
}
TEST(libfmt, complex_flags_star_f) {
std::string s;
s = fmt::format("{:*.1f}", 2. + 3i);
EXPECT_EQ(s, "(2.0+3.0*i)");
}
TEST(libfmt, complex_flags_comma) {
std::string s;
s = fmt::format("{:,.1f}", 2. + 3i);
EXPECT_EQ(s, "(2.0,3.0)");
s = fmt::format("{:,}", 2. + 3i);
EXPECT_EQ(s, "(2.0,3.0)");
EXPECT_EQ(s, "(2,3)");
}
TEST(libfmt, complex_flags_a) {
std::string s;
// + +
s = fmt::format("{:$+}", 2. + 3i);
EXPECT_EQ(s, "(+2+3i)");
s = fmt::format("{:$+.1f}", 2. + 3i);
EXPECT_EQ(s, "(+2.0+3.0i)");
s = fmt::format("{:*+}", 2. + 3i);
EXPECT_EQ(s, "(+2.0+3.0*i)");
EXPECT_EQ(s, "(+2+3*i)");
s = fmt::format("{:,+}", 2. + 3i);
EXPECT_EQ(s, "(+2.0,+3.0)");
EXPECT_EQ(s, "(+2,+3)");
}
TEST(libfmt, complex_flags_b) {
std::string s;
// + -
s = fmt::format("{:$+}", 2. - 3i);
EXPECT_EQ(s, "(+2.0-3.0i)");
EXPECT_EQ(s, "(+2-3i)");
s = fmt::format("{:*+}", 2. - 3i);
EXPECT_EQ(s, "(+2.0-3.0*i)");
EXPECT_EQ(s, "(+2-3*i)");
s = fmt::format("{:,+}", 2. - 3i);
EXPECT_EQ(s, "(+2,-3)");
s = fmt::format("{:,+.1f}", 2. - 3i);
EXPECT_EQ(s, "(+2.0,-3.0)");
}
TEST(libfmt, complex_all_real) {
std::string s;
s = fmt::format("{}", 2. + 0i);
EXPECT_EQ(s, "(2)");
s = fmt::format("{:.1f}", 2. + 0i);
EXPECT_EQ(s, "(2.0)");
s = fmt::format("{:*}", 2. + 0i);
EXPECT_EQ(s, "(2.0)");
EXPECT_EQ(s, "(2)");
s = fmt::format("{:,}", 2. + 0i);
EXPECT_EQ(s, "(2,0)");
s = fmt::format("{:,.1f}", 2. + 0i);
EXPECT_EQ(s, "(2.0,0.0)");
}
TEST(libfmt, complex_all_imag) {
std::string s;
s = fmt::format("{}", 0. + 3i);
EXPECT_EQ(s, "(3i)");
s = fmt::format("{:.1f}", 0. + 3i);
EXPECT_EQ(s, "(3.0i)");
s = fmt::format("{:*}", 0. + 3i);
EXPECT_EQ(s, "(3.0*i)");
EXPECT_EQ(s, "(3*i)");
s = fmt::format("{:,}", 0. + 3i);
EXPECT_EQ(s, "(0.0,3.0)");
EXPECT_EQ(s, "(0,3)");
}
TEST(libfmt, complex_plus) {
std::string s = fmt::format("{:+}", 1. + 3i);
EXPECT_EQ(s, "(+1+3i)");
s = fmt::format("{:+.1f}", 1. + 3i);
EXPECT_EQ(s, "(+1.0+3.0i)");
s = fmt::format("{:+}", 1. - 3i);
EXPECT_EQ(s, "(+1.0-3.0i)");
EXPECT_EQ(s, "(+1-3i)");
}
TEST(libfmt, complex_g) {
std::string s = fmt::format("{:g}", 2.f + 3if);
@ -118,67 +171,102 @@ TEST(libfmt, complex_gel) {
TEST(libfmt, dual_) {
std::string s = fmt::format("{}", 2 + 3_ef);
EXPECT_EQ(s, "(2+3_ef)");
s = fmt::format("{:.1f}", 2 + 3_ef);
EXPECT_EQ(s, "(2.0+3.0_ef)");
}
TEST(libfmt, dual_el) {
std::string s = fmt::format("{}", 2 + 3_el);
EXPECT_EQ(s, "(2+3_el)");
s = fmt::format("{:.1f}", 2 + 3_el);
EXPECT_EQ(s, "(2.0+3.0_el)");
}
TEST(libfmt, dual_flags) {
std::string s;
s = fmt::format("{}", 2. + 3_e);
EXPECT_EQ(s, "(2.0+3.0_e)");
EXPECT_EQ(s, "(2+3_e)");
s = fmt::format("{:$}", 2. + 3_e);
EXPECT_EQ(s, "(2+3_e)");
s = fmt::format("{:$.1f}", 2. + 3_e);
EXPECT_EQ(s, "(2.0+3.0_e)");
s = fmt::format("{:*}", 2. + 3_e);
EXPECT_EQ(s, "(2.0+3.0*e)");
EXPECT_EQ(s, "(2+3*e)");
s = fmt::format("{:,}", 2. + 3_e);
EXPECT_EQ(s, "(2,3)");
s = fmt::format("{:,.1f}", 2. + 3_e);
EXPECT_EQ(s, "(2.0,3.0)");
// + +
s = fmt::format("{:$+}", 2. + 3_e);
EXPECT_EQ(s, "(+2.0+3.0_e)");
EXPECT_EQ(s, "(+2+3_e)");
s = fmt::format("{:*+}", 2. + 3_e);
EXPECT_EQ(s, "(+2+3*e)");
s = fmt::format("{:*+.1f}", 2. + 3_e);
EXPECT_EQ(s, "(+2.0+3.0*e)");
s = fmt::format("{:,+}", 2. + 3_e);
EXPECT_EQ(s, "(+2.0,+3.0)");
EXPECT_EQ(s, "(+2,+3)");
// + -
s = fmt::format("{:$+}", 2. - 3_e);
EXPECT_EQ(s, "(+2.0-3.0_e)");
EXPECT_EQ(s, "(+2-3_e)");
s = fmt::format("{:*+}", 2. - 3_e);
EXPECT_EQ(s, "(+2-3*e)");
s = fmt::format("{:*+.1f}", 2. - 3_e);
EXPECT_EQ(s, "(+2.0-3.0*e)");
s = fmt::format("{:,+}", 2. - 3_e);
EXPECT_EQ(s, "(+2.0,-3.0)");
EXPECT_EQ(s, "(+2,-3)");
s = fmt::format("{:,+}", 2. + 3_e);
EXPECT_EQ(s, "(+2,+3)");
}
TEST(libfmt, dual_all_real) {
std::string s;
s = fmt::format("{}", 2 + 0_e);
EXPECT_EQ(s, "(2.0)");
EXPECT_EQ(s, "(2)");
s = fmt::format("{:*}", 2 + 0_e);
EXPECT_EQ(s, "(2.0)");
EXPECT_EQ(s, "(2)");
s = fmt::format("{:,}", 2 + 0_e);
EXPECT_EQ(s, "(2.0,0.0)");
EXPECT_EQ(s, "(2,0)");
}
TEST(libfmt, dual_all_dual) {
std::string s;
s = fmt::format("a{}b", 0 + 3_e);
EXPECT_EQ(s, "a(3_e)b");
s = fmt::format("a{:.1f}b", 0 + 3_e);
EXPECT_EQ(s, "a(3.0_e)b");
s = fmt::format("a{:*}b", 0 + 3_e);
EXPECT_EQ(s, "a(3.0*e)b");
EXPECT_EQ(s, "a(3*e)b");
s = fmt::format("a{:,}b", 0 + 3_e);
EXPECT_EQ(s, "a(0,3)b");
s = fmt::format("a{:,.1f}b", 0 + 3_e);
EXPECT_EQ(s, "a(0.0,3.0)b");
}
TEST(libfmt, dual_plus) {
std::string s = fmt::format("{:+}", 1. + 3_e);
EXPECT_EQ(s, "(+1+3_e)");
s = fmt::format("{:+.1f}", 1. + 3_e);
EXPECT_EQ(s, "(+1.0+3.0_e)");
s = fmt::format("{:+}", 1. - 3_e);
EXPECT_EQ(s, "(+1-3_e)");
}
TEST(libfmt, dual_g) {
std::string s = fmt::format("{:g}", 2 + 3_ef);
EXPECT_EQ(s, "(2+3_ef)");
@ -194,6 +282,12 @@ TEST(libfmt, dual_gel) {
std::string s = fmt::format("{:g}", 2 + 3_el);
EXPECT_EQ(s, "(2+3_el)");
}
TEST(libfmt, dual_cd) {
std::string s = fmt::format("{}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)");
}
TEST(libfmt, dual_cgt) {
std::string s = fmt::format("{:g}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2+3_ef)+(4+5_ef)i)");
@ -208,6 +302,10 @@ TEST(libfmt, dual_cgts) {
s = fmt::format("{:,*g}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2+3*ef),(4+5*ef))");
// nonsense but should still work
s = fmt::format("{:*,g}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2,3)+(4,5)*i)");
s = fmt::format("{:,,g}", cdualf(2 + 3_ef, 4 + 5_ef));
EXPECT_EQ(s, "((2,3),(4,5))");
}

View File

@ -32,21 +32,34 @@ typedef std::complex<double> complexd;
// not verify precision.
#define FD_CHECK(T, F, ...) \
TEST(func##_##T, F) { \
using std::isnan; \
for (T x : __VA_ARGS__) { \
T prec = 100 * std::sqrt(std::numeric_limits<T>::epsilon()); \
T dd = dpart(F(x + dual<T>(0,1))); \
T dd = duals::dpart(F(x + dual<T>(0,1))); \
/*T dx = std::numeric_limits<T>::epsilon() * (T)1000000; */ \
T dx = T(1)/ (1ull << (std::numeric_limits<T>::digits / 3)); \
T fd = (F(x + dx) - F(x - dx)) / (2*dx); \
EXPECT_CNEAR(dd, fd, prec * std::abs(std::max(std::max(dd,fd),T(1)))) \
if (!isnan(dd) && !isnan(fd)) { \
EXPECT_CNEAR(dd, fd, \
prec * std::abs(std::max(std::max(dd,fd),T(1)))) \
<< "dd=" << dd << " fd=" << fd << " x=" << x << " dx=" << dx; \
} \
} \
}
#define powL(x) pow(x,2)
#define powR(x) pow(2,x)
#define powLR(x) pow(x,x)
FD_CHECK(double, exp, {-1,0,1})
FD_CHECK(double, log, {1})
FD_CHECK(double, log, {1, 3})
// FD_CHECK(complexd, log, {-1,1}) TODO
FD_CHECK(double, log10, {1})
FD_CHECK(double, log10, {1, 3})
FD_CHECK(double, powL, {-3.,-1.,-0.4,0.,0.6,1.,2.5})
FD_CHECK(double, powR, {-3.,-1.,-0.4,0.,0.6,1.,2.5})
FD_CHECK(double, powLR, {-3.,-1.,-0.4,0.,0.6,1.,2.5})
// FD_CHECK(complexd, log10, {-1,0,1}) TODO
FD_CHECK(double, sqrt, {0.5,1.0})
FD_CHECK(double, cbrt, {-10.,-0.01,0.01,1.0,10.})
@ -59,12 +72,27 @@ FD_CHECK(double, acos, {-.9,0.,.9})
FD_CHECK(double, atan, {-10,-1,0,1,10})
// TODO:
//FD_CHECK(double, sinh, {0})
//FD_CHECK(double, cosh, {0})
//FD_CHECK(double, tanh, {0})
//FD_CHECK(double, asinh, {0})
//FD_CHECK(double, acosh, {0})
//FD_CHECK(double, atanh, {0})
#define atan2L(x) atan2(x,2)
#define atan2R(x) atan2(2,x)
#define atan2LR(x) atan2(x,x)
FD_CHECK(double, atan2L, {-10.,-1.,0.,1.,10.})
FD_CHECK(double, atan2R, {-10.,-1.,0.01,1.,10.})
FD_CHECK(double, atan2LR, {-10.,-1.,0.01,1.,10.})
#define hypot2LR(x) hypot(x,x)
FD_CHECK(double, hypot2LR, {-10.,-1.,0.01,1.,10.})
#define scalbnL(x) scalbn(x,2)
FD_CHECK(double, scalbnL, {-10.,-1.,0.01,1.,10.})
FD_CHECK(double, sinh, {-0.1, 0.1})
FD_CHECK(double, cosh, {-0.1, 0.1})
FD_CHECK(double, tanh, {-0.1, 0.1})
FD_CHECK(double, asinh, {-0.1, 0.1})
FD_CHECK(double, acosh, {-1.1, 1.1})
FD_CHECK(double, atanh, {-0.1, 0.1})
FD_CHECK(double, log1p, {-0.1, 0.1})
FD_CHECK(double, expm1, {-0.1, 0.1})
FD_CHECK(double, erf, {-1,0,1})
FD_CHECK(double, erfc, {-1,0,1})
@ -97,6 +125,8 @@ TEST(func, tgamma) {
//EXPECT_EQ(tgamma(x).rpart(), 362880); "interestingly", compiling without optimization (-O0) causes this to fail
EXPECT_NEAR(tgamma(x).rpart(), 362880, 362880 * 100 * std::numeric_limits<double>::epsilon());
}
// part selection functions
TEST(func, rpart) {
dualf x = 10 + 4_e;
EXPECT_EQ(rpart(x), 10);
@ -105,16 +135,258 @@ TEST(func, dpart) {
dualf x = 2 + 4_e;
EXPECT_EQ(dpart(x), 4);
}
// non-differentiable operations on the real part.
TEST(func, abs) {
dualf x = -10 + 4_e;
EXPECT_EQ(abs(x), 10);
}
TEST(func, arg) {
TEST(func, fabs) {
dualf x = -10 + 4_e;
EXPECT_EQ(fabs(x), 10);
}
TEST(func, fmax) {
dualf x = -10 + 4_e;
dualf y = 10 + 4_e;
EXPECT_EQ(fmax(x, y), 10);
}
TEST(func, fmin) {
dualf x = -10 + 4_e;
dualf y = 10 + 4_e;
EXPECT_EQ(fmin(x, y), -10);
}
TEST(func, frexp) {
dualf x = 6 + 4_e;
int exp = 0;
EXPECT_EQ(frexp(x, &exp), 0.75);
EXPECT_EQ(exp, 3);
}
TEST(func, ldexp) {
dualf x = 0.5 + 4_e;
int exp = 1;
EXPECT_EQ(ldexp(x, exp), 1);
}
TEST(func, trunc) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(trunc(x), 1);
}
TEST(func, floor) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(floor(x), 1);
}
TEST(func, ceil) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(ceil(x), 2);
}
TEST(func, round) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(round(x), 2);
}
// floating point functions
TEST(func, fpclassify) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(fpclassify(x), FP_NORMAL);
EXPECT_EQ(fpclassify(std::numeric_limits<dualf>::infinity()), FP_INFINITE);
EXPECT_EQ(fpclassify(std::numeric_limits<dualf>::quiet_NaN()), FP_NAN);
if (std::numeric_limits<dualf>::has_denorm != std::denorm_absent) {
EXPECT_EQ(fpclassify(std::numeric_limits<dualf>::denorm_min()), FP_SUBNORMAL);
}
EXPECT_EQ(fpclassify(x+std::numeric_limits<dualf>::min()), FP_NORMAL);
EXPECT_EQ(fpclassify(2*std::numeric_limits<dualf>::max()), FP_INFINITE);
EXPECT_EQ(fpclassify(x+std::numeric_limits<dualf>::epsilon()), FP_NORMAL);
}
TEST(func, isfinite) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(isfinite(x), true);
}
TEST(func, isnormal) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(isnormal(x), true);
}
TEST(func, isinf) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(isinf(x), false);
}
TEST(func, isnan) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(isnan(x), false);
}
TEST(func, signbit) {
dualf x = 1.5 + 4_e;
EXPECT_EQ(signbit(x), false);
}
TEST(func, copysign) {
dualf x = 1.5 + 4_e;
dualf y = -1.3 + 2_e;
EXPECT_EQ(copysign(x, y), -1.5);
}
// Utility functions
TEST(func, random) {
dualf x = random(0.001 + 0.001_e, 1 + 1_e);
EXPECT_GE(rpart(x), 0.001);
EXPECT_LE(rpart(x), 1);
EXPECT_GE(dpart(x), 0.001);
EXPECT_LE(dpart(x), 1);
}
TEST(func, random2) {
dualf x = duals::randos::random2(0.001 + 0.001_e, 1 + 1_e);
EXPECT_GE(rpart(x), 0.001);
EXPECT_LE(rpart(x), 1);
EXPECT_GE(dpart(x), 0.001);
EXPECT_LE(dpart(x), 1);
}
// more tests
TEST(func, logb) {
dualf x = 4 + 1_e;
EXPECT_EQ(rpart(logb(.5 + 1_e)), -1.);
EXPECT_EQ(rpart(logb(1 + 1_e)), 0.);
EXPECT_EQ(rpart(logb(2 + 1_e)), 1.);
EXPECT_EQ(rpart(logb(3 + 1_e)), 1.);
EXPECT_EQ(rpart(logb(4 + 1_e)), 2.);
EXPECT_EQ(rpart(logb(x * x)), 4.);
EXPECT_EQ(dpart(logb(4 + 8_e)), std::numeric_limits<dualf>::infinity());
EXPECT_EQ(dpart(logb(4.01 + 8_e)), 0.);
EXPECT_EQ(dpart(logb(x * x)), std::numeric_limits<dualf>::infinity());
EXPECT_EQ(dpart(logb(3 * x)), 0.);
x += 0.01;
EXPECT_EQ(dpart(logb(3 * x)), 0.);
EXPECT_EQ(dpart(logb(x * x)), 0.);
}
TEST(func, pow) {
dualf x = pow(0 + 0_e, 0.);
EXPECT_EQ(rpart(x), 1);
EXPECT_EQ(dpart(x), 0);
dualf y = pow(0 + 0_e, 0. + 0_e);
EXPECT_EQ(rpart(y), 1);
EXPECT_EQ(dpart(y), 0);
dualf z = pow(0, 0. + 0_e);
EXPECT_EQ(rpart(z), 1);
EXPECT_EQ(dpart(z), 0);
}
TEST(func, pow_complex) {
std::complex<dualf> C(3+4_ef, 5+6_ef);
std::complex<dualf> x = std::pow(C, 2+1_ef);
std::complex<float> ref = std::complex<float>(std::pow(std::complex<float>(3,5), 2));
EXPECT_NEAR(rpart(x.real()), ref.real(), 1e-5);
EXPECT_NEAR(rpart(x.imag()), ref.imag(), 1e-6);
//EXPECT_EQ(dpart(x), std::pow(std::complex<float>(3, 5), 2) * (2+1_ef));
}
//----------------------------------------------------------------------
// Test for pow_dual_complex(const dual<T>& realBase, const std::complex<dual<T>>& complexExponent)
//----------------------------------------------------------------------
TEST(func, PowDualComplexTest)
{
// 1) Prepare inputs:
// realBase = 2.0 (with zero derivative for this example)
duald realBase(2.0f);
// complexExponent = (1.5 + 0.7i),
// each part a dual with .rpart() = 1.5 or 0.7, derivative 0
std::complex<duald> complexExponent(duald(1.5f), duald(0.7f));
// 2) Call the function we want to test:
// x^y => pow_dual_complex(realBase, complexExponent)
std::complex<duald> result = std::pow(realBase, complexExponent);
// 3) Reference: use standard pow in double
double dblBase = 2.0;
std::complex<double> dblExponent(1.5, 0.7);
std::complex<double> reference = std::pow(dblBase, dblExponent);
// 4) Compare the .rpart() of the duals real/imag with reference
EXPECT_NEAR(result.real().rpart(), reference.real(), 1e-6);
EXPECT_NEAR(result.imag().rpart(), reference.imag(), 1e-6);
}
//----------------------------------------------------------------------
// Test for pow_complex_dual(const std::complex<dual<T>>& complexBase, const dual<T>& realExponent)
//----------------------------------------------------------------------
TEST(func, PowComplexDualTest)
{
// 1) Prepare inputs:
// complexBase = (3 + 5i), each part dual with zero derivative
std::complex<duald> complexBase(duald(3.0f), duald(5.0f));
// realExponent = 2.0 as a dual
duald realExponent(2.0f);
// 2) Call the function we want to test:
// x^y => pow_complex_dual(complexBase, realExponent)
std::complex<duald> result = pow(complexBase, realExponent);
// 3) Reference: again, standard pow in double
std::complex<double> dblBase(3.0, 5.0);
double dblExponent = 2.0;
std::complex<double> reference = std::pow(dblBase, dblExponent);
// 4) Compare the .rpart() of the duals real/imag with reference
EXPECT_NEAR(result.real().rpart(), reference.real(), 1e-6);
EXPECT_NEAR(result.imag().rpart(), reference.imag(), 1e-6);
}
TEST(func, norm) {
// TODO
}
TEST(func, conj) {
// TODO
}
TEST(func, polar) {
// TODO
}
TEST(func, atan) {
EXPECT_EQ(rpart(atan(0 + 1_e)), atan(0));
EXPECT_EQ(dpart(atan(1_e)), 1);
EXPECT_EQ(dpart(atan(1 + 1_e)), 0.5); // = 1 / (1 + x^2)
EXPECT_EQ(dpart(atan(-2 + 1_e)), 1. / 5.); // = 1 / (1 + x^2)
}
TEST(func, atan2) {
// TODO
//EXPECT_EQ(dpart(atan2(1_e, 1)), 1);
//EXPECT_EQ(dpart(atan2(1 + 1_e, 1)), 0.5);
//EXPECT_EQ(dpart(atan2(-2 + 1_e, 1)), (1. / 5.));
duald y = 1 + 1_e;
duald x = 1 + 0_e;
auto z = atan2(y, x);
z = atan2(y, x);
EXPECT_EQ(rpart(z), atan2(rpart(y), rpart(x)));
EXPECT_EQ(dpart(z), 0.5);
y = -2 + 1_e;
x = 1 + 0_e;
z = atan2(y, x);
EXPECT_EQ(rpart(z), atan2(rpart(y), rpart(x)));
EXPECT_EQ(dpart(z), 1. / 5.);
y = 1 + 0_e;
x = -2 + 1_e;
z = atan2(y, x);
EXPECT_EQ(rpart(z), atan2(rpart(y), rpart(x)));
EXPECT_EQ(dpart(z), -1. / 5.);
}
TEST(func, atan2a) {
// TODO
duald y = 1 + 1_e;
EXPECT_EQ(rpart(atan2(y, 1)), atan2(rpart(y), 1));
EXPECT_EQ(rpart(atan2(y, 2)), atan2(rpart(y), 2));
EXPECT_EQ(dpart(atan2(y, 1)), 0.5);
y = 2 + 1_e;
EXPECT_EQ(dpart(atan2(y, -2)), -0.25);
}
TEST(func, atan2b) {
// TODO
duald x = 10 + 1_e;
EXPECT_EQ(rpart(atan2(2, x)), atan2(2, rpart(x)));
EXPECT_EQ(dpart(atan2(2, x)), -1./52);
}
struct pike_f1 {
// function

View File

@ -16,8 +16,8 @@
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include "type_name.hpp"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
@ -60,6 +60,7 @@ template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
#if !defined(CPPDUALS_DONT_VECTORIZE) && !defined(EIGEN_DONT_VECTORIZE)
#ifdef EIGEN_VECTORIZE_SSE
TEST(Packet1cdf, pload_pstore) {
using namespace Eigen::internal;
cdualf cd1 = cdualf(1+2_ef,3+4_ef);
@ -68,6 +69,7 @@ TEST(Packet1cdf, pload_pstore) {
pstore(&cd2, p1);
EXPECT_DEQ(cd1, cd2);
}
#endif
using duals::randos::random2;
@ -89,7 +91,7 @@ using duals::randos::random2;
pstore(cd3.data(), p3); \
for (int i = 0; i < N; i++) { \
EXPECT_DNEAR(cd3[i], cd1[i] op cd2[i], tol) \
<< cd1[i] << ',' << cd2[i] << " fail at " << i; \
<< cd1[i] << #op << cd2[i] << "=" << cd3[i] << "!=" << (cd1[i] op cd2[i]) << " fail at " << i << "/" << N; \
} \
}
@ -323,13 +325,11 @@ using duals::randos::random2;
GEN_PACKET_TEST_UN(PTYPE,pconj,conj)
// TODO:
//pcplxflip
//preduxp
//pand
//por
//pxor
//andnot
//pbroadcast4
//ploadquad (for packets w/ size==8)
//pgather
//pscatter
@ -345,7 +345,7 @@ GEN_CPACKET_TESTS(Packet2cf)
GEN_CPACKET_TESTS(Packet4cf)
#endif
#ifdef EIGEN_VECTORIZE_SSE
#if defined(EIGEN_VECTORIZE_SSE) || defined(EIGEN_VECTORIZE_NEON)
GEN_PACKET_TESTS(Packet2df)
GEN_PACKET_TESTS(Packet1dd)
GEN_CPACKET_TESTS(Packet1cdf)
@ -368,20 +368,28 @@ TEST(compile, VECTORIZE) {
#endif
}
TEST(compile, SSE) {
#ifdef EIGEN_VECTORIZE_SSE
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("SSE") != std::string::npos)
<< "Not using SSE instructions:" << Eigen::SimdInstructionSetsInUse();
#ifndef EIGEN_VECTORIZE_SSE
EXPECT_TRUE(false)
<< "Not using EIGEN_VECTORIZE_SSE:" << Eigen::SimdInstructionSetsInUse();
#else
EXPECT_TRUE(true)
#endif
<< "Not using EIGEN_VECTORIZE_SSE:" << Eigen::SimdInstructionSetsInUse();
}
TEST(compile, AVX) {
#ifdef EIGEN_VECTORIZE_AVX
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("AVX") != std::string::npos)
<< "Not using AVX instructions:" << Eigen::SimdInstructionSetsInUse();
#ifndef EIGEN_VECTORIZE_AVX
EXPECT_TRUE(false)
<< "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse();
#else
EXPECT_TRUE(true)
#endif
<< "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse();
}
TEST(compile, NEON) {
#ifdef EIGEN_VECTORIZE_NEON
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("NEON") != std::string::npos)
#else
EXPECT_TRUE(true)
#endif
<< "Not using EIGEN_VECTORIZE_NEON:" << Eigen::SimdInstructionSetsInUse();
}
#define QUOTE(...) STRFY(__VA_ARGS__)

View File

@ -16,8 +16,8 @@
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include "type_name.hpp"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
@ -78,7 +78,10 @@ void solveLu() {
emtx<DT,NN> B = b + DT(0,1) * emtx<T,NN>::Random();
emtx<DT,NN> C,D,E;
C = A * B;
D = A.lu().solve(C);
// D = A.lu().solve(C);
// D = A.colPivHouseholderQr().solve(C);
// D = A.bdcSvd().solve(C);
D = A.fullPivLu().solve(C);
EXPECT_LT(rpart(B - D).norm(), tol);
EXPECT_LT(dpart(B - D).norm(), tol);
}

View File

@ -16,8 +16,8 @@
* (c)2019 Michael Tesch. tesch1@gmail.com
*/
#include "type_name.hpp"
#include <duals/dual_eigen>
#include "type_name.hpp"
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <Eigen/StdVector>
@ -52,7 +52,7 @@ template <int N=2, int K = N> using ecdf = Eigen::Matrix<cdualf, N, K> ;
#define _EXPECT_FALSE(...) {typedef __VA_ARGS__ fal; EXPECT_FALSE(fal::value); static_assert(!fal::value, "sa"); }
#define ASSERT_DEQ(A,B) ASSERT_EQ(rpart(A), rpart(B)); ASSERT_EQ(dpart(A), dpart(B))
#define ASSERT_DNEAR(A,B,tol) \
ASSERT_NEAR(abs(rpart((A) - (B))),0,abs(rpart(A))*(tol)); \
ASSERT_NEAR(abs(rpart((A) - (B))),0,abs(rpart(A))*(tol)) << "rpart " << A << " " << B << "\n"; \
ASSERT_NEAR(abs(dpart((A) - (B))),0,abs(dpart(A))*(tol))
#define EXPECT_DEQ(A,B) EXPECT_EQ(rpart(A), rpart(B)); EXPECT_EQ(dpart(A), dpart(B))
#define EXPECT_DNE(A,B) EXPECT_NE(rpart(A), rpart(B)); EXPECT_NE(dpart(A), dpart(B))
@ -117,9 +117,9 @@ void elemwise(int N) {
ASSERT_DEQ(cca[i], Cca(i)) << "ca mismatch at " << i << "\n";
ASSERT_DEQ(ccb[i], Ccb(i)) << "cb mismatch at " << i << "\n";
}
ASSERT_DNEAR(sum, A.sum(), N*tol);
ASSERT_DNEAR(sum, A.sum(), N*tol);
ASSERT_DNEAR(sum, A.sum(), N*tol) << "sum mismatch at " << sum << " " << A.sum() << "\n";
}
#if defined(PHASE_1)
TEST(Vector, full_even_dualf) { elemwise<dualf>(512); }
TEST(Vector, full_even_duald) { elemwise<duald>(512); }
@ -136,6 +136,7 @@ TEST(Vector, single_elem_cdualf) { elemwise<cdualf>(1); }
TEST(Vector, two_elem_dualf) { elemwise<dualf>(2); }
TEST(Vector, two_elem_duald) { elemwise<duald>(2); }
TEST(Vector, two_elem_cdualf) { elemwise<cdualf>(2); }
#endif
#define DBOUT(X)
#define MAKE_MULT_TEST(TYPE1, TYPE2, FIX, SIZE) \
@ -308,20 +309,30 @@ TEST(flags, VECTORIZE) {
#endif
}
TEST(flags, SSE) {
#ifdef EIGEN_VECTORIZE_SSE
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("SSE") != std::string::npos)
<< "Not using SSE instructions:" << Eigen::SimdInstructionSetsInUse();
#ifndef EIGEN_VECTORIZE_SSE
EXPECT_TRUE(false)
#else
EXPECT_TRUE(true)
#endif
<< "Not using EIGEN_VECTORIZE_SSE:" << Eigen::SimdInstructionSetsInUse();
#endif
}
TEST(flags, AVX) {
#ifdef EIGEN_VECTORIZE_AVX
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("AVX") != std::string::npos)
<< "Not using AVX instructions:" << Eigen::SimdInstructionSetsInUse();
#ifndef EIGEN_VECTORIZE_AVX
EXPECT_TRUE(false)
<< "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse();
#else
EXPECT_TRUE(true)
#endif
<< "Not using EIGEN_VECTORIZE_AVX:" << Eigen::SimdInstructionSetsInUse();
}
TEST(flags, NEON) {
#ifdef EIGEN_VECTORIZE_NEON
EXPECT_TRUE(std::string(Eigen::SimdInstructionSetsInUse()).find("NEON") != std::string::npos)
#else
EXPECT_TRUE(true)
#endif
<< "Not using EIGEN_VECTORIZE_NEON:" << Eigen::SimdInstructionSetsInUse();
}
#define QUOTE(...) STRFY(__VA_ARGS__)

View File

@ -4,12 +4,19 @@
# 3.10 adds support for "gtest_discover_tests" which enumerates the tests inside
# of the code and adds them to ctest.
#
cmake_minimum_required (VERSION 3.10)
cmake_minimum_required (VERSION 3.14)
project (cppduals_thirdparty)
include (ExternalProject)
get_directory_property (hasParent PARENT_DIRECTORY)
if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.23)
cmake_policy (SET CMP0135 NEW)
endif ()
if (CMAKE_XCODE_BUILD_SYSTEM VERSION_GREATER_EQUAL 12)
cmake_policy (SET CMP0114 NEW)
endif ()
set (DEPS_ROOT "${CMAKE_BINARY_DIR}/root")
if (hasParent)
set (DEPS_ROOT "${CMAKE_BINARY_DIR}/thirdparty/root" PARENT_SCOPE)
@ -21,98 +28,109 @@ else (NOT WIN32)
set (DOWNLOAD_DIR "C:/Downloads")
endif (NOT WIN32)
#
# Google test (https://github.com/google/googletest/blob/master/googletest/README.md)
#
include(FetchContent)
# Download and unpack googletest at configure time
configure_file (CMakeLists-gt.txt.in googletest-download/CMakeLists.txt)
execute_process (COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
if (result)
message (FATAL_ERROR "CMake step for googletest failed: ${result}")
endif ()
execute_process (COMMAND ${CMAKE_COMMAND} --build .
RESULT_VARIABLE result
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
if (result)
message (FATAL_ERROR "Build step for googletest failed: ${result}")
endif ()
#
# Google test
# https://google.github.io/googletest/quickstart-cmake.html
# Prevent overriding the parent project's compiler/linker
# settings on Windows
#
# Configure google-test
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip
URL_HASH MD5=eb1c5c237d13ed12bf492d3997ca6b0d
DOWNLOAD_NAME googletest-v1.15.2.zip
DOWNLOAD_DIR "$ENV{HOME}/Downloads"
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
# Add googletest directly to our build. This defines
# the gtest and gtest_main targets.
add_subdirectory (
${CMAKE_CURRENT_BINARY_DIR}/googletest-src
${CMAKE_CURRENT_BINARY_DIR}/googletest-build
EXCLUDE_FROM_ALL)
# The gtest/gtest_main targets carry header search path
# dependencies automatically when using CMake 2.8.11 or
# later. Otherwise we have to add them here ourselves.
if (CMAKE_VERSION VERSION_LESS 2.8.11)
include_directories ("${gtest_SOURCE_DIR}/include")
endif ()
# Can simply link against gtest or gtest_main as needed. Eg
#add_executable (example example.cpp)
#target_link_libraries (example gtest_main)
#add_test (NAME example_test COMMAND example)
# Enable testing
include(GoogleTest)
#
# Eigen
#
if (CPPDUALS_EIGEN_LATEST)
set (EIGEN_URL http://bitbucket.org/eigen/eigen/get/default.tar.bz2)
#set (EIGEN_MD5 ffc83130dcd37b694c6cf7e905099af9)
if (TRUE)
set (EIGEN_URL https://gitlab.com/libeigen/eigen/-/archive/3.3.8/eigen-3.3.8.tar.bz2)
set (EIGEN_MD5 432ef01499d514f4606343276afa0ec3)
set (EIGEN_MAX_CXX 17)
else ()
set (EIGEN_URL http://bitbucket.org/eigen/eigen/get/3.3.7.tar.bz2)
set (EIGEN_MD5 05b1f7511c93980c385ebe11bd3c93fa)
set (EIGEN_URL https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.bz2)
set (EIGEN_MD5 b9e98a200d2455f06db9c661c5610496)
set (EIGEN_MAX_CXX 17)
endif ()
#
# Eigen
#
ExternalProject_Add (eigenX
PREFIX eigenX
URL ${EIGEN_URL}
#URL_HASH MD5=${EIGEN_MD5}
URL_HASH MD5=${EIGEN_MD5}
DOWNLOAD_DIR "$ENV{HOME}/Downloads"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
ExternalProject_Get_Property (eigenX source_dir)
if (hasParent AND NOT EIGEN3_INCLUDE_DIRS)
set (EIGEN3_INCLUDE_DIRS "${source_dir}" PARENT_SCOPE)
if (true) # || hasParent
add_library (eigen INTERFACE IMPORTED GLOBAL)
add_dependencies (eigen eigenX)
set_property (TARGET eigen APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${source_dir}")
if (XCODE)
set (IOFORMAT "IOFormat\(FullPrecision, DontAlignCols, \", \", \"\\$<SEMICOLON>\\\\n\", \"\", \"\", \"[\", \"]\"\)")
else ()
set (IOFORMAT "IOFormat\(FullPrecision, DontAlignCols, \", \", \"\\$<SEMICOLON>\\n\", \"\", \"\", \"[\", \"]\"\)")
endif ()
#target_compile_definitions (eigen INTERFACE EIGEN_DEFAULT_IO_FORMAT=${IOFORMAT})
#target_compile_definitions (eigen INTERFACE EIGEN_DEFAULT_IO_FORMAT=EIGEN_IO_FORMAT_OCTAVE)
set_property (TARGET eigen APPEND PROPERTY
INTERFACE_COMPILE_DEFINITIONS EIGEN_DEFAULT_IO_FORMAT=${IOFORMAT})
endif ()
# if c++20, disable warning -Wdeprecated-enum-enum-conversion to eigen
if (CMAKE_CXX_STANDARD GREATER_EQUAL 20)
target_compile_options (eigen INTERFACE -Wno-deprecated-enum-enum-conversion)
endif ()
#
# Eigen-Expokit
# expokit
#
set (EEX_SHA 72bf6e445d5ae84218dcbd74580720491e0074db )
#set (EEX_SHA ee28baa3bf29561501e17e5c68c2e54c85daae19 ) newer? used by spindropsSDL. md5=cebd15f9b5068c0e327753244ff6d394
set (EEX_SHA c157dec0057be6e183a1ea2a5de353fac7e5e3a7 )
set (EEX_MD5 89484e51f706398284235b96bc805515 )
ExternalProject_Add (expokitX
PREFIX expokitX
URL https://gitlab.com/api/v4/projects/tesch1%2Feigen-expokit/repository/archive.tbz2?sha=${EEX_SHA}
#URL_HASH MD5=96b79de1d01547f6d658865b7caa02ee
URL https://gitlab.com/tesch1/eigen-expokit/-/archive/${EEX_SHA}/eigen-expokit.tar.bz2
URL_HASH MD5=${EEX_MD5}
DOWNLOAD_NAME eigen-expokit-${EEX_SHA}.tar.bz2
DOWNLOAD_DIR "$ENV{HOME}/Downloads"
UPDATE_COMMAND ""
PATCH_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
ExternalProject_Get_Property (expokitX source_dir)
if (hasParent)
set (EXPOKIT_INCLUDE_DIR "${source_dir}" PARENT_SCOPE)
endif()
add_library (expokit INTERFACE IMPORTED GLOBAL)
add_dependencies (expokit expokitX)
set_property (TARGET expokit APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${source_dir}")
endif (hasParent)
#
# fmt
#
ExternalProject_Add (fmtX
PREFIX fmtX
URL https://github.com/fmtlib/fmt/archive/6.1.1.tar.gz
URL_HASH MD5=acfb83d44afdca171ee26c597c931e7c
URL https://github.com/fmtlib/fmt/archive/11.1.4.tar.gz
URL_HASH MD5=10c2ae163accd3b82e6b8b4dff877645
DOWNLOAD_DIR ${DOWNLOAD_DIR}
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
@ -121,7 +139,6 @@ ExternalProject_Add (fmtX
ExternalProject_Get_Property (fmtX source_dir)
ExternalProject_Get_Property (fmtX binary_dir)
if (hasParent)
message (" FMT3_INCLUDE_DIRS: ${source_dir}")
add_subdirectory (${source_dir} ${binary_dir} EXCLUDE_FROM_ALL)
endif ()
@ -131,19 +148,20 @@ if (CPPDUALS_BENCHMARK)
#
ExternalProject_Add (benchmarkX
PREFIX benchmarkX
URL "http://github.com/google/benchmark/archive/v1.5.0.tar.gz"
URL_HASH MD5=eb1466370f3ae31e74557baa29729e9e
URL "http://github.com/google/benchmark/archive/v1.9.1.tar.gz"
URL_HASH MD5=92000ef8b4a7b1e9229972f8943070a7
DOWNLOAD_DIR ${DOWNLOAD_DIR}
CMAKE_ARGS --target install -DBENCHMARK_ENABLE_GTEST_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -DBENCHMARK_USE_LIBCXX=${CPPDUALS_USE_LIBCXX}
"-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>"
INSTALL_DIR "${DEPS_ROOT}"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Get_Property (benchmarkX source_dir)
ExternalProject_Get_Property (benchmarkX install_dir)
ExternalProject_Get_Property (benchmarkX binary_dir)
if (hasParent)
set (BENCHMARK_SRC_DIR "${source_dir}" PARENT_SCOPE)
set (BENCHMARK_INC_DIR "${install_dir}/include" PARENT_SCOPE)
message (" BENCHMARK_SRC_DIR: ${BENCHMARK_SRC_DIR}")
# https://github.com/google/benchmark#requirements
set (BENCHMARK_ENABLE_GTEST_TESTS OFF)
set (BENCHMARK_USE_LIBCXX ${CPPDUALS_USE_LIBCXX})
add_subdirectory (${source_dir} ${binary_dir} EXCLUDE_FROM_ALL)
endif()
if (Boost_FOUND AND NO)
@ -158,18 +176,6 @@ if (CPPDUALS_BENCHMARK)
set (Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} PARENT_SCOPE)
endif ()
# piranha
ExternalProject_Add (piranhaX PREFIX piranhaX
URL https://github.com/bluescarni/piranha/archive/v0.11.tar.gz
URL_HASH MD5=33482f719f6b8a6a5316f9bd148f5b10
DOWNLOAD_DIR "$ENV{HOME}/Downloads"
CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND ""
)
ExternalProject_Get_Property (piranhaX source_dir)
if (hasParent)
set (PIRANHA_INCLUDE_DIR "${source_dir}/include" PARENT_SCOPE)
endif ()
# AuDi
ExternalProject_Add (audiX PREFIX audiX
URL https://github.com/darioizzo/audi/archive/v1.6.5.tar.gz

View File

@ -99,6 +99,7 @@ double cm_netlist_get_l(void);
void cm_irreversible(unsigned int);
const char *cm_get_node_name(const char *, unsigned int);
const char *cm_get_neg_node_name(const char *, unsigned int);
bool cm_probe_node(unsigned int, unsigned int, void *);
bool cm_schedule_output(unsigned int, unsigned int, double, void *);

View File

@ -61,6 +61,7 @@ struct coreInfo_t {
double ((*dllitf_cm_netlist_get_l)(void));
void ((*dllitf_cm_irreversible)(unsigned int));
const char * ((*dllitf_cm_get_node_name)(const char *, unsigned int));
const char* ((*dllitf_cm_get_neg_node_name)(const char*, unsigned int));
bool ((*dllitf_cm_probe_node)(unsigned int, unsigned int,
void *));
bool ((*dllitf_cm_schedule_output)(unsigned int, unsigned int,

View File

@ -22,6 +22,7 @@ extern int OSDIparam(int, IFvalue *, GENinstance *, IFvalue *);
extern int OSDIsetup(SMPmatrix *, GENmodel *, CKTcircuit *, int *);
extern int OSDIunsetup(GENmodel *, CKTcircuit *);
extern int OSDIask(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *);
extern int OSDImAsk(CKTcircuit *, GENmodel *, int, IFvalue *);
extern int OSDIload(GENmodel *, CKTcircuit *);
extern int OSDItemp(GENmodel *, CKTcircuit *);
extern int OSDIacLoad(GENmodel *, CKTcircuit *);
@ -39,5 +40,4 @@ extern int OSDIbindCSCComplex(GENmodel *inModel, CKTcircuit *ckt);
/* extern int OSDIconvTest(GENmodel*,CKTcircuit*); */
/* extern int OSDImDelete(GENmodel*); */
/* extern int OSDIgetic(GENmodel*,CKTcircuit*); */
/* extern int OSDImAsk(CKTcircuit*,GENmodel*,int,IFvalue*); */
/* extern int OSDIsoaCheck(CKTcircuit *, GENmodel *); */

View File

@ -188,6 +188,7 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) {
OSDIinfo->DEVparam = OSDIparam;
OSDIinfo->DEVmodParam = OSDImParam;
OSDIinfo->DEVask = OSDIask;
OSDIinfo->DEVmodAsk = OSDImAsk;
OSDIinfo->DEVsetup = OSDIsetup;
OSDIinfo->DEVpzSetup = OSDIsetup;
OSDIinfo->DEVtemperature = OSDItemp;

View File

@ -162,3 +162,21 @@ extern int OSDIask(CKTcircuit *ckt, GENinstance *instPtr, int id,
void *src = descr->access(inst, model, (uint32_t)id, flags);
return osdi_read_param(src, value, id, descr);
}
extern int OSDImAsk(CKTcircuit *ckt, GENmodel *modelPtr, int id,
IFvalue *value) {
NG_IGNORE(ckt);
OsdiRegistryEntry *entry = osdi_reg_entry_model(modelPtr);
const OsdiDescriptor *descr = entry->descriptor;
void *model = osdi_model_data(modelPtr);
if (id >= (int)(descr->num_params)) {
return (E_BADPARM);
}
void *src = descr->access(NULL, model, (uint32_t)id, ACCESS_FLAG_READ);
return osdi_read_param(src, value, id, descr);
}

View File

@ -20,7 +20,7 @@ CKTdltNod(CKTcircuit* ckt, CKTnode* node)
int
CKTdltNNum(CKTcircuit* ckt, int num)
{
CKTnode* n, * prev, * node, * sprev;
CKTnode* n, * prev, * node;
int error;
if (!ckt->prev_CKTlastNode->number || num <= ckt->prev_CKTlastNode->number) {
@ -30,12 +30,11 @@ CKTdltNNum(CKTcircuit* ckt, int num)
prev = NULL;
node = NULL;
sprev = NULL;
for (n = ckt->CKTnodes; n; n = n->next) {
if (n->number == num) {
node = n;
sprev = prev;
break;
}
prev = n;
}
@ -45,14 +44,14 @@ CKTdltNNum(CKTcircuit* ckt, int num)
ckt->CKTmaxEqNum -= 1;
if (!sprev) {
if (!prev) {
ckt->CKTnodes = node->next;
}
else {
sprev->next = node->next;
prev->next = node->next;
}
if (node == ckt->CKTlastNode)
ckt->CKTlastNode = sprev;
ckt->CKTlastNode = prev;
error = SPfrontEnd->IFdelUid(ckt, node->name, UID_SIGNAL);
tfree(node);

View File

@ -30,6 +30,9 @@ IOP( "geo", BSIM3_GEO, IF_INTEGER, "ACM model drain/source connection"),
IOP( "delvto", BSIM3_DELVTO, IF_REAL, "Zero bias threshold voltage variation"),
IOP( "mulu0", BSIM3_MULU0, IF_REAL, "Low field mobility multiplier"),
IP( "ic", BSIM3_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"),
IOP( "icvgs", BSIM3_IC_VGS, IF_REAL , "GS initial voltage"),
IOP( "icvds", BSIM3_IC_VDS, IF_REAL , "DS initial voltage"),
IOP( "icvbs", BSIM3_IC_VBS, IF_REAL , "BS initial voltage"),
OP( "gmbs", BSIM3_GMBS, IF_REAL, "Gmb"),
OP( "gm", BSIM3_GM, IF_REAL, "Gm"),
OP( "gds", BSIM3_GDS, IF_REAL, "Gds"),

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,8 +17,12 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
#include "ngspice/devdefs.h"
#include "bsim4def.h"
@ -58,10 +55,9 @@ IOP( "rbps", BSIM4_RBPS, IF_REAL , "Body resistance"),
IOP( "rbpd", BSIM4_RBPD, IF_REAL , "Body resistance"),
IOP( "delvto", BSIM4_DELVTO, IF_REAL , "Zero bias threshold voltage variation"),
IOPR("delvt0", BSIM4_DELVTO, IF_REAL , "Zero bias threshold voltage variation"),
IOP( "mulu0", BSIM4_MULU0, IF_REAL, "Low field mobility multiplier"),
IOP( "xgw", BSIM4_XGW, IF_REAL, "Distance from gate contact center to device edge"),
IOP( "ngcon", BSIM4_NGCON, IF_REAL, "Number of gate contacts"),
IOP( "wnflag", BSIM4_WNFLAG, IF_INTEGER, "W/NF device flag for bin selection"),
IOP( "trnqsmod", BSIM4_TRNQSMOD, IF_INTEGER, "Transient NQS model selector"),
IOP( "acnqsmod", BSIM4_ACNQSMOD, IF_INTEGER, "AC NQS model selector"),
@ -69,6 +65,10 @@ IOP( "rbodymod", BSIM4_RBODYMOD, IF_INTEGER, "Distributed body R model selector"
IOP( "rgatemod", BSIM4_RGATEMOD, IF_INTEGER, "Gate resistance model selector"),
IOP( "geomod", BSIM4_GEOMOD, IF_INTEGER, "Geometry dependent parasitics model selector"),
IOP( "rgeomod", BSIM4_RGEOMOD, IF_INTEGER, "S/D resistance and contact model selector"),
IOP( "mult_i", BSIM4_MULT_I, IF_REAL, "Variability in current"),
IOP( "mult_q", BSIM4_MULT_Q, IF_REAL, "Variability in charge"),
IOP( "mult_fn", BSIM4_MULT_FN, IF_REAL, "Variability in flicker noise"),
IP( "ic", BSIM4_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"),
OP( "gmbs", BSIM4_GMBS, IF_REAL, "Gmb"),
OP( "gm", BSIM4_GM, IF_REAL, "Gm"),
@ -138,7 +138,6 @@ IOP( "rbodymod", BSIM4_MOD_RBODYMOD, IF_INTEGER, "Distributed body R model selec
IOP( "rgatemod", BSIM4_MOD_RGATEMOD, IF_INTEGER, "Gate R model selector"),
IOP( "permod", BSIM4_MOD_PERMOD, IF_INTEGER, "Pd and Ps model selector"),
IOP( "geomod", BSIM4_MOD_GEOMOD, IF_INTEGER, "Geometry dependent parasitics model selector"),
IOP( "rgeomod", BSIM4_MOD_RGEOMOD, IF_INTEGER, "S/D resistance and contact model selector"),
IOP( "fnoimod", BSIM4_MOD_FNOIMOD, IF_INTEGER, "Flicker noise model selector"),
IOP( "tnoimod", BSIM4_MOD_TNOIMOD, IF_INTEGER, "Thermal noise model selector"),
IOP( "mtrlmod", BSIM4_MOD_MTRLMOD, IF_INTEGER, "parameter for non-silicon substrate or metal gate selector"),
@ -176,6 +175,7 @@ IOP( "ags", BSIM4_MOD_AGS, IF_REAL, "Gate bias coefficient of Abulk."),
IOP( "a1", BSIM4_MOD_A1, IF_REAL, "Non-saturation effect coefficient"),
IOP( "a2", BSIM4_MOD_A2, IF_REAL, "Non-saturation effect coefficient"),
IOP( "keta", BSIM4_MOD_KETA, IF_REAL, "Body-bias coefficient of non-uniform depletion width effect."),
IOP( "ketac", BSIM4_MOD_KETAC, IF_REAL, "Body-bias coefficient of non-uniform depletion width effect in dynamic evaluation."),
IOP( "phig", BSIM4_MOD_PHIG, IF_REAL, "Work function of gate"),
IOP( "epsrgate", BSIM4_MOD_EPSRGATE, IF_REAL, "Dielectric constant of gate relative to vacuum"),
IOP( "easub",BSIM4_MOD_EASUB, IF_REAL, "Electron affinity of substrate"),
@ -442,7 +442,7 @@ IOP( "jtssws", BSIM4_MOD_JTSSWS, IF_REAL, "Source STI sidewall trap-assisted sat
IOP( "jtsswd", BSIM4_MOD_JTSSWD, IF_REAL, "Drain STI sidewall trap-assisted saturation current density"),
IOP( "jtsswgs", BSIM4_MOD_JTSSWGS, IF_REAL, "Source gate-edge sidewall trap-assisted saturation current density"),
IOP( "jtsswgd", BSIM4_MOD_JTSSWGD, IF_REAL, "Drain gate-edge sidewall trap-assisted saturation current density"),
IOP( "jtweff", BSIM4_MOD_JTWEFF, IF_REAL, "TAT current width dependence"),
IOP( "jtweff", BSIM4_MOD_JTWEFF, IF_REAL, "TAT current width dependance"),
IOP( "njts", BSIM4_MOD_NJTS, IF_REAL, "Non-ideality factor for bottom junction"),
IOP( "njtssw", BSIM4_MOD_NJTSSW, IF_REAL, "Non-ideality factor for STI sidewall junction"),
IOP( "njtsswg", BSIM4_MOD_NJTSSWG, IF_REAL, "Non-ideality factor for gate-edge sidewall junction"),
@ -519,6 +519,7 @@ IOP( "lags", BSIM4_MOD_LAGS, IF_REAL, "Length dependence of ags"),
IOP( "la1", BSIM4_MOD_LA1, IF_REAL, "Length dependence of a1"),
IOP( "la2", BSIM4_MOD_LA2, IF_REAL, "Length dependence of a2"),
IOP( "lketa", BSIM4_MOD_LKETA, IF_REAL, "Length dependence of keta"),
IOP( "lketac", BSIM4_MOD_LKETAC, IF_REAL, "Length dependence of ketac"),
IOP( "lnsub", BSIM4_MOD_LNSUB, IF_REAL, "Length dependence of nsub"),
IOP( "lndep", BSIM4_MOD_LNDEP, IF_REAL, "Length dependence of ndep"),
IOP( "lnsd", BSIM4_MOD_LNSD, IF_REAL, "Length dependence of nsd"),
@ -553,8 +554,8 @@ IOP( "ldvt1w", BSIM4_MOD_LDVT1W, IF_REAL, "Length dependence of dvt1w"),
IOP( "ldvt2w", BSIM4_MOD_LDVT2W, IF_REAL, "Length dependence of dvt2w"),
IOP( "ldrout", BSIM4_MOD_LDROUT, IF_REAL, "Length dependence of drout"),
IOP( "ldsub", BSIM4_MOD_LDSUB, IF_REAL, "Length dependence of dsub"),
IOP( "lvth0", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vth0"),
IOPR("lvtho", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vtho"),
IOP( "lvth0", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vto"),
IOPR("lvtho", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vto"),
IOP( "lua", BSIM4_MOD_LUA, IF_REAL, "Length dependence of ua"),
IOP( "lua1", BSIM4_MOD_LUA1, IF_REAL, "Length dependence of ua1"),
IOP( "lub", BSIM4_MOD_LUB, IF_REAL, "Length dependence of ub"),
@ -681,6 +682,7 @@ IOP( "wags", BSIM4_MOD_WAGS, IF_REAL, "Width dependence of ags"),
IOP( "wa1", BSIM4_MOD_WA1, IF_REAL, "Width dependence of a1"),
IOP( "wa2", BSIM4_MOD_WA2, IF_REAL, "Width dependence of a2"),
IOP( "wketa", BSIM4_MOD_WKETA, IF_REAL, "Width dependence of keta"),
IOP( "wketac", BSIM4_MOD_WKETAC, IF_REAL, "Width dependence of ketac"),
IOP( "wnsub", BSIM4_MOD_WNSUB, IF_REAL, "Width dependence of nsub"),
IOP( "wndep", BSIM4_MOD_WNDEP, IF_REAL, "Width dependence of ndep"),
IOP( "wnsd", BSIM4_MOD_WNSD, IF_REAL, "Width dependence of nsd"),
@ -715,8 +717,8 @@ IOP( "wdvt1w", BSIM4_MOD_WDVT1W, IF_REAL, "Width dependence of dvt1w"),
IOP( "wdvt2w", BSIM4_MOD_WDVT2W, IF_REAL, "Width dependence of dvt2w"),
IOP( "wdrout", BSIM4_MOD_WDROUT, IF_REAL, "Width dependence of drout"),
IOP( "wdsub", BSIM4_MOD_WDSUB, IF_REAL, "Width dependence of dsub"),
IOP( "wvth0", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vth0"),
IOPR("wvtho", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vtho"),
IOP( "wvth0", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vto"),
IOPR("wvtho", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vto"),
IOP( "wua", BSIM4_MOD_WUA, IF_REAL, "Width dependence of ua"),
IOP( "wua1", BSIM4_MOD_WUA1, IF_REAL, "Width dependence of ua1"),
IOP( "wub", BSIM4_MOD_WUB, IF_REAL, "Width dependence of ub"),
@ -842,6 +844,7 @@ IOP( "pags", BSIM4_MOD_PAGS, IF_REAL, "Cross-term dependence of ags"),
IOP( "pa1", BSIM4_MOD_PA1, IF_REAL, "Cross-term dependence of a1"),
IOP( "pa2", BSIM4_MOD_PA2, IF_REAL, "Cross-term dependence of a2"),
IOP( "pketa", BSIM4_MOD_PKETA, IF_REAL, "Cross-term dependence of keta"),
IOP( "pketac", BSIM4_MOD_PKETAC, IF_REAL, "Cross-term dependence of ketac"),
IOP( "pnsub", BSIM4_MOD_PNSUB, IF_REAL, "Cross-term dependence of nsub"),
IOP( "pndep", BSIM4_MOD_PNDEP, IF_REAL, "Cross-term dependence of ndep"),
IOP( "pnsd", BSIM4_MOD_PNSD, IF_REAL, "Cross-term dependence of nsd"),
@ -876,8 +879,8 @@ IOP( "pdvt1w", BSIM4_MOD_PDVT1W, IF_REAL, "Cross-term dependence of dvt1w"),
IOP( "pdvt2w", BSIM4_MOD_PDVT2W, IF_REAL, "Cross-term dependence of dvt2w"),
IOP( "pdrout", BSIM4_MOD_PDROUT, IF_REAL, "Cross-term dependence of drout"),
IOP( "pdsub", BSIM4_MOD_PDSUB, IF_REAL, "Cross-term dependence of dsub"),
IOP( "pvth0", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vth0"),
IOPR("pvtho", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vtho"),
IOP( "pvth0", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"),
IOPR("pvtho", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"),
IOP( "pua", BSIM4_MOD_PUA, IF_REAL, "Cross-term dependence of ua"),
IOP( "pua1", BSIM4_MOD_PUA1, IF_REAL, "Cross-term dependence of ua1"),
IOP( "pub", BSIM4_MOD_PUB, IF_REAL, "Cross-term dependence of ub"),
@ -1076,3 +1079,4 @@ int BSIM4pTSize = NUMELEMS(BSIM4pTable);
int BSIM4mPTSize = NUMELEMS(BSIM4mPTable);
int BSIM4iSize = sizeof(BSIM4instance);
int BSIM4mSize = sizeof(BSIM4model);

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,15 +17,18 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "bsim4def.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
BSIM4acLoad(
GENmodel *inModel,
@ -68,15 +64,13 @@ double FwdSumr, RevSumr, Gmr, Gmbsr;
double FwdSumi, RevSumi, Gmi, Gmbsi;
struct bsim4SizeDependParam *pParam;
double ggidld, ggidlg, ggidlb, ggislg, ggislb, ggisls;
double m;
double m, mult_i, mult_q;
omega = ckt->CKTomega;
for (; model != NULL; model = BSIM4nextModel(model))
{ for (here = BSIM4instances(model); here!= NULL;
here = BSIM4nextInstance(here))
{
pParam = here->pParam;
{ pParam = here->pParam;
capbd = here->BSIM4capbd;
capbs = here->BSIM4capbs;
cgso = here->BSIM4cgso;
@ -468,6 +462,8 @@ double m;
* Loading AC matrix
*/
m = here->BSIM4m;
mult_i = here->BSIM4mult_i;
mult_q = here->BSIM4mult_q;
if (!model->BSIM4rdsMod)
{ gdpr = here->BSIM4drainConductance;
@ -486,121 +482,121 @@ double m;
geltd = here->BSIM4grgeltd;
if (here->BSIM4rgateMod == 1)
{ *(here->BSIM4GEgePtr) += m * geltd;
*(here->BSIM4GPgePtr) -= m * geltd;
*(here->BSIM4GEgpPtr) -= m * geltd;
{ *(here->BSIM4GEgePtr) += mult_i * geltd;
*(here->BSIM4GPgePtr) -= mult_i * geltd;
*(here->BSIM4GEgpPtr) -= mult_i * geltd;
*(here->BSIM4GPgpPtr +1) += m * xcggbr;
*(here->BSIM4GPgpPtr) += m * (geltd + xcggbi + gIgtotg);
*(here->BSIM4GPdpPtr +1) += m * xcgdbr;
*(here->BSIM4GPdpPtr) += m * (xcgdbi + gIgtotd);
*(here->BSIM4GPspPtr +1) += m * xcgsbr;
*(here->BSIM4GPspPtr) += m * (xcgsbi + gIgtots);
*(here->BSIM4GPbpPtr +1) += m * xcgbbr;
*(here->BSIM4GPbpPtr) += m * (xcgbbi + gIgtotb);
*(here->BSIM4GPgpPtr +1) += mult_q * xcggbr;
*(here->BSIM4GPgpPtr) += mult_i * (geltd + gIgtotg) + mult_q * xcggbi;
*(here->BSIM4GPdpPtr +1) += mult_q * xcgdbr;
*(here->BSIM4GPdpPtr) += mult_q * xcgdbi + mult_i * gIgtotd;
*(here->BSIM4GPspPtr +1) += mult_q * xcgsbr;
*(here->BSIM4GPspPtr) += mult_q * xcgsbi + mult_i * gIgtots;
*(here->BSIM4GPbpPtr +1) += mult_q * xcgbbr;
*(here->BSIM4GPbpPtr) += mult_q * xcgbbi + mult_i * gIgtotb;
} /* WDLiu: gcrg already subtracted from all gcrgg below */
else if (here->BSIM4rgateMod == 2)
{ *(here->BSIM4GEgePtr) += m * gcrg;
*(here->BSIM4GEgpPtr) += m * gcrgg;
*(here->BSIM4GEdpPtr) += m * gcrgd;
*(here->BSIM4GEspPtr) += m * gcrgs;
*(here->BSIM4GEbpPtr) += m * gcrgb;
{ *(here->BSIM4GEgePtr) += mult_i * gcrg;
*(here->BSIM4GEgpPtr) += mult_i * gcrgg;
*(here->BSIM4GEdpPtr) += mult_i * gcrgd;
*(here->BSIM4GEspPtr) += mult_i * gcrgs;
*(here->BSIM4GEbpPtr) += mult_i * gcrgb;
*(here->BSIM4GPgePtr) -= m * gcrg;
*(here->BSIM4GPgpPtr +1) += m * xcggbr;
*(here->BSIM4GPgpPtr) -= m * (gcrgg - xcggbi - gIgtotg);
*(here->BSIM4GPdpPtr +1) += m * xcgdbr;
*(here->BSIM4GPdpPtr) -= m * (gcrgd - xcgdbi - gIgtotd);
*(here->BSIM4GPspPtr +1) += m * xcgsbr;
*(here->BSIM4GPspPtr) -= m * (gcrgs - xcgsbi - gIgtots);
*(here->BSIM4GPbpPtr +1) += m * xcgbbr;
*(here->BSIM4GPbpPtr) -= m * (gcrgb - xcgbbi - gIgtotb);
*(here->BSIM4GPgePtr) -= mult_i * gcrg;
*(here->BSIM4GPgpPtr +1) += mult_q * xcggbr;
*(here->BSIM4GPgpPtr) -= mult_i * (gcrgg - gIgtotg) - mult_q * xcggbi;
*(here->BSIM4GPdpPtr +1) += mult_q * xcgdbr;
*(here->BSIM4GPdpPtr) -= mult_i * (gcrgd - gIgtotd) - mult_q * xcgdbi;
*(here->BSIM4GPspPtr +1) += mult_q * xcgsbr;
*(here->BSIM4GPspPtr) -= mult_i * (gcrgs - gIgtots) - mult_q * xcgsbi;
*(here->BSIM4GPbpPtr +1) += mult_q * xcgbbr;
*(here->BSIM4GPbpPtr) -= mult_i * (gcrgb - gIgtotb) - mult_q * xcgbbi;
}
else if (here->BSIM4rgateMod == 3)
{ *(here->BSIM4GEgePtr) += m * geltd;
*(here->BSIM4GEgmPtr) -= m * geltd;
*(here->BSIM4GMgePtr) -= m * geltd;
*(here->BSIM4GMgmPtr) += m * (geltd + gcrg);
*(here->BSIM4GMgmPtr +1) += m * xcgmgmb;
{ *(here->BSIM4GEgePtr) += mult_i * geltd;
*(here->BSIM4GEgmPtr) -= mult_i * geltd;
*(here->BSIM4GMgePtr) -= mult_i * geltd;
*(here->BSIM4GMgmPtr) += mult_i * (geltd + gcrg);
*(here->BSIM4GMgmPtr +1) += mult_q * xcgmgmb;
*(here->BSIM4GMdpPtr) += m * gcrgd;
*(here->BSIM4GMdpPtr +1) += m * xcgmdb;
*(here->BSIM4GMgpPtr) += m * gcrgg;
*(here->BSIM4GMspPtr) += m * gcrgs;
*(here->BSIM4GMspPtr +1) += m * xcgmsb;
*(here->BSIM4GMbpPtr) += m * gcrgb;
*(here->BSIM4GMbpPtr +1) += m * xcgmbb;
*(here->BSIM4GMdpPtr) += mult_i * gcrgd;
*(here->BSIM4GMdpPtr +1) += mult_q * xcgmdb;
*(here->BSIM4GMgpPtr) += mult_i * gcrgg;
*(here->BSIM4GMspPtr) += mult_i * gcrgs;
*(here->BSIM4GMspPtr +1) += mult_q * xcgmsb;
*(here->BSIM4GMbpPtr) += mult_i * gcrgb;
*(here->BSIM4GMbpPtr +1) += mult_q * xcgmbb;
*(here->BSIM4DPgmPtr +1) += m * xcdgmb;
*(here->BSIM4GPgmPtr) -= m * gcrg;
*(here->BSIM4SPgmPtr +1) += m * xcsgmb;
*(here->BSIM4BPgmPtr +1) += m * xcbgmb;
*(here->BSIM4DPgmPtr +1) += mult_q * xcdgmb;
*(here->BSIM4GPgmPtr) -= mult_i * gcrg;
*(here->BSIM4SPgmPtr +1) += mult_q * xcsgmb;
*(here->BSIM4BPgmPtr +1) += mult_q * xcbgmb;
*(here->BSIM4GPgpPtr) -= m * (gcrgg - xcggbi - gIgtotg);
*(here->BSIM4GPgpPtr +1) += m * xcggbr;
*(here->BSIM4GPdpPtr) -= m * (gcrgd - xcgdbi - gIgtotd);
*(here->BSIM4GPdpPtr +1) += m * xcgdbr;
*(here->BSIM4GPspPtr) -= m * (gcrgs - xcgsbi - gIgtots);
*(here->BSIM4GPspPtr +1) += m * xcgsbr;
*(here->BSIM4GPbpPtr) -= m * (gcrgb - xcgbbi - gIgtotb);
*(here->BSIM4GPbpPtr +1) += m * xcgbbr;
*(here->BSIM4GPgpPtr) -= mult_i * (gcrgg - gIgtotg) - mult_q * xcggbi;
*(here->BSIM4GPgpPtr +1) += mult_q * xcggbr;
*(here->BSIM4GPdpPtr) -= mult_i * (gcrgd - gIgtotd) - mult_q * xcgdbi;
*(here->BSIM4GPdpPtr +1) += mult_q * xcgdbr;
*(here->BSIM4GPspPtr) -= mult_i * (gcrgs - gIgtots) - mult_q * xcgsbi;
*(here->BSIM4GPspPtr +1) += mult_q * xcgsbr;
*(here->BSIM4GPbpPtr) -= mult_i * (gcrgb - gIgtotb) - mult_q * xcgbbi;
*(here->BSIM4GPbpPtr +1) += mult_q * xcgbbr;
}
else
{ *(here->BSIM4GPgpPtr +1) += m * xcggbr;
*(here->BSIM4GPgpPtr) += m * (xcggbi + gIgtotg);
*(here->BSIM4GPdpPtr +1) += m * xcgdbr;
*(here->BSIM4GPdpPtr) += m * (xcgdbi + gIgtotd);
*(here->BSIM4GPspPtr +1) += m * xcgsbr;
*(here->BSIM4GPspPtr) += m * (xcgsbi + gIgtots);
*(here->BSIM4GPbpPtr +1) += m * xcgbbr;
*(here->BSIM4GPbpPtr) += m * (xcgbbi + gIgtotb);
{ *(here->BSIM4GPgpPtr +1) += mult_q * xcggbr;
*(here->BSIM4GPgpPtr) += mult_q * xcggbi + mult_i * gIgtotg;
*(here->BSIM4GPdpPtr +1) += mult_q * xcgdbr;
*(here->BSIM4GPdpPtr) += mult_q * xcgdbi + mult_i * gIgtotd;
*(here->BSIM4GPspPtr +1) += mult_q * xcgsbr;
*(here->BSIM4GPspPtr) += mult_q * xcgsbi + mult_i * gIgtots;
*(here->BSIM4GPbpPtr +1) += mult_q * xcgbbr;
*(here->BSIM4GPbpPtr) += mult_q * xcgbbi + mult_i * gIgtotb;
}
if (model->BSIM4rdsMod)
{ (*(here->BSIM4DgpPtr) += m * gdtotg);
(*(here->BSIM4DspPtr) += m * gdtots);
(*(here->BSIM4DbpPtr) += m * gdtotb);
(*(here->BSIM4SdpPtr) += m * gstotd);
(*(here->BSIM4SgpPtr) += m * gstotg);
(*(here->BSIM4SbpPtr) += m * gstotb);
{ (*(here->BSIM4DgpPtr) += mult_i * gdtotg);
(*(here->BSIM4DspPtr) += mult_i * gdtots);
(*(here->BSIM4DbpPtr) += mult_i * gdtotb);
(*(here->BSIM4SdpPtr) += mult_i * gstotd);
(*(here->BSIM4SgpPtr) += mult_i * gstotg);
(*(here->BSIM4SbpPtr) += mult_i * gstotb);
}
*(here->BSIM4DPdpPtr +1) += m * (xcddbr + gdsi + RevSumi);
*(here->BSIM4DPdpPtr) += m * (gdpr + xcddbi + gdsr + here->BSIM4gbd
- gdtotd + RevSumr + gbdpdp - gIdtotd);
*(here->BSIM4DPdPtr) -= m * (gdpr + gdtot);
*(here->BSIM4DPgpPtr +1) += m * (xcdgbr + Gmi);
*(here->BSIM4DPgpPtr) += m * (Gmr + xcdgbi - gdtotg + gbdpg - gIdtotg);
*(here->BSIM4DPspPtr +1) += m * (xcdsbr - gdsi - FwdSumi);
*(here->BSIM4DPspPtr) -= m * (gdsr - xcdsbi + FwdSumr + gdtots - gbdpsp + gIdtots);
*(here->BSIM4DPbpPtr +1) += m * (xcdbbr + Gmbsi);
*(here->BSIM4DPbpPtr) -= m * (gjbd + gdtotb - xcdbbi - Gmbsr - gbdpb + gIdtotb);
*(here->BSIM4DPdpPtr +1) += mult_q * xcddbr + mult_i * (gdsi + RevSumi);
*(here->BSIM4DPdpPtr) += + mult_i * (gdpr + gdsr + here->BSIM4gbd
- gdtotd + RevSumr + gbdpdp - gIdtotd) + mult_q * xcddbi;
*(here->BSIM4DPdPtr) -= mult_i * (gdpr + gdtot);
*(here->BSIM4DPgpPtr +1) += mult_q * xcdgbr + mult_i * Gmi;
*(here->BSIM4DPgpPtr) += mult_i * (Gmr - gdtotg + gbdpg - gIdtotg) + mult_q * xcdgbi;
*(here->BSIM4DPspPtr +1) += mult_q * xcdsbr - mult_i * (gdsi + FwdSumi);
*(here->BSIM4DPspPtr) -= mult_i * (gdsr + FwdSumr + gdtots - gbdpsp + gIdtots) - mult_q * xcdsbi;
*(here->BSIM4DPbpPtr +1) += mult_q * xcdbbr + mult_i * Gmbsi;
*(here->BSIM4DPbpPtr) -= mult_i * (gjbd + gdtotb - Gmbsr - gbdpb + gIdtotb) - mult_q * xcdbbi;
*(here->BSIM4DdpPtr) -= m * (gdpr - gdtotd);
*(here->BSIM4DdPtr) += m * (gdpr + gdtot);
*(here->BSIM4DdpPtr) -= mult_i * (gdpr - gdtotd);
*(here->BSIM4DdPtr) += mult_i * (gdpr + gdtot);
*(here->BSIM4SPdpPtr +1) += m * (xcsdbr - gdsi - RevSumi);
*(here->BSIM4SPdpPtr) -= m * (gdsr - xcsdbi + gstotd + RevSumr - gbspdp + gIstotd);
*(here->BSIM4SPgpPtr +1) += m * (xcsgbr - Gmi);
*(here->BSIM4SPgpPtr) -= m * (Gmr - xcsgbi + gstotg - gbspg + gIstotg);
*(here->BSIM4SPspPtr +1) += m * (xcssbr + gdsi + FwdSumi);
*(here->BSIM4SPspPtr) += m * (gspr + xcssbi + gdsr + here->BSIM4gbs
- gstots + FwdSumr + gbspsp - gIstots);
*(here->BSIM4SPsPtr) -= m * (gspr + gstot);
*(here->BSIM4SPbpPtr +1) += m * (xcsbbr - Gmbsi);
*(here->BSIM4SPbpPtr) -= m * (gjbs + gstotb - xcsbbi + Gmbsr - gbspb + gIstotb);
*(here->BSIM4SPdpPtr +1) += mult_q * xcsdbr - mult_i * (gdsi + RevSumi);
*(here->BSIM4SPdpPtr) -= mult_i * (gdsr + gstotd + RevSumr - gbspdp + gIstotd) - mult_q * xcsdbi;
*(here->BSIM4SPgpPtr +1) += mult_q * xcsgbr - mult_i * Gmi;
*(here->BSIM4SPgpPtr) -= mult_i * (Gmr + gstotg - gbspg + gIstotg) - mult_q * xcsgbi;
*(here->BSIM4SPspPtr +1) += mult_q * xcssbr + mult_i * (gdsi + FwdSumi);
*(here->BSIM4SPspPtr) += mult_i * (gspr + gdsr + here->BSIM4gbs
- gstots + FwdSumr + gbspsp - gIstots) + mult_q * xcssbi;
*(here->BSIM4SPsPtr) -= mult_i * (gspr + gstot);
*(here->BSIM4SPbpPtr +1) += mult_q * xcsbbr - mult_i * Gmbsi;
*(here->BSIM4SPbpPtr) -= mult_i * (gjbs + gstotb + Gmbsr - gbspb + gIstotb) - mult_q * xcsbbi;
*(here->BSIM4SspPtr) -= m * (gspr - gstots);
*(here->BSIM4SsPtr) += m * (gspr + gstot);
*(here->BSIM4SspPtr) -= mult_i * (gspr - gstots);
*(here->BSIM4SsPtr) += mult_i * (gspr + gstot);
*(here->BSIM4BPdpPtr +1) += m * xcbdb;
*(here->BSIM4BPdpPtr) -= m * (gjbd - gbbdp + gIbtotd);
*(here->BSIM4BPgpPtr +1) += m * xcbgb;
*(here->BSIM4BPgpPtr) -= m * (here->BSIM4gbgs + gIbtotg);
*(here->BSIM4BPspPtr +1) += m * xcbsb;
*(here->BSIM4BPspPtr) -= m * (gjbs - gbbsp + gIbtots);
*(here->BSIM4BPbpPtr +1) += m * xcbbb;
*(here->BSIM4BPbpPtr) += m * (gjbd + gjbs - here->BSIM4gbbs
*(here->BSIM4BPdpPtr +1) += mult_q * xcbdb;
*(here->BSIM4BPdpPtr) -= mult_i * (gjbd - gbbdp + gIbtotd);
*(here->BSIM4BPgpPtr +1) += mult_q * xcbgb;
*(here->BSIM4BPgpPtr) -= mult_i * (here->BSIM4gbgs + gIbtotg);
*(here->BSIM4BPspPtr +1) += mult_q * xcbsb;
*(here->BSIM4BPspPtr) -= mult_i * (gjbs - gbbsp + gIbtots);
*(here->BSIM4BPbpPtr +1) += mult_q * xcbbb;
*(here->BSIM4BPbpPtr) += mult_i * (gjbd + gjbs - here->BSIM4gbbs
- gIbtotb);
ggidld = here->BSIM4ggidld;
ggidlg = here->BSIM4ggidlg;
@ -610,57 +606,57 @@ double m;
ggislb = here->BSIM4ggislb;
/* stamp gidl */
(*(here->BSIM4DPdpPtr) += m * ggidld);
(*(here->BSIM4DPgpPtr) += m * ggidlg);
(*(here->BSIM4DPspPtr) -= m * ((ggidlg + ggidld) + ggidlb));
(*(here->BSIM4DPbpPtr) += m * ggidlb);
(*(here->BSIM4BPdpPtr) -= m * ggidld);
(*(here->BSIM4BPgpPtr) -= m * ggidlg);
(*(here->BSIM4BPspPtr) += m * ((ggidlg + ggidld) + ggidlb));
(*(here->BSIM4BPbpPtr) -= m * ggidlb);
(*(here->BSIM4DPdpPtr) += mult_i * ggidld);
(*(here->BSIM4DPgpPtr) += mult_i * ggidlg);
(*(here->BSIM4DPspPtr) -= mult_i * ((ggidlg + ggidld) + ggidlb));
(*(here->BSIM4DPbpPtr) += mult_i * ggidlb);
(*(here->BSIM4BPdpPtr) -= mult_i * ggidld);
(*(here->BSIM4BPgpPtr) -= mult_i * ggidlg);
(*(here->BSIM4BPspPtr) += mult_i * ((ggidlg + ggidld) + ggidlb));
(*(here->BSIM4BPbpPtr) -= mult_i * ggidlb);
/* stamp gisl */
(*(here->BSIM4SPdpPtr) -= m * ((ggisls + ggislg) + ggislb));
(*(here->BSIM4SPgpPtr) += m * ggislg);
(*(here->BSIM4SPspPtr) += m * ggisls);
(*(here->BSIM4SPbpPtr) += m * ggislb);
(*(here->BSIM4BPdpPtr) += m * ((ggislg + ggisls) + ggislb));
(*(here->BSIM4BPgpPtr) -= m * ggislg);
(*(here->BSIM4BPspPtr) -= m * ggisls);
(*(here->BSIM4BPbpPtr) -= m * ggislb);
(*(here->BSIM4SPdpPtr) -= mult_i * ((ggisls + ggislg) + ggislb));
(*(here->BSIM4SPgpPtr) += mult_i * ggislg);
(*(here->BSIM4SPspPtr) += mult_i * ggisls);
(*(here->BSIM4SPbpPtr) += mult_i * ggislb);
(*(here->BSIM4BPdpPtr) += mult_i * ((ggislg + ggisls) + ggislb));
(*(here->BSIM4BPgpPtr) -= mult_i * ggislg);
(*(here->BSIM4BPspPtr) -= mult_i * ggisls);
(*(here->BSIM4BPbpPtr) -= mult_i * ggislb);
if (here->BSIM4rbodyMod)
{ (*(here->BSIM4DPdbPtr +1) += m * xcdbdb);
(*(here->BSIM4DPdbPtr) -= m * here->BSIM4gbd);
(*(here->BSIM4SPsbPtr +1) += m * xcsbsb);
(*(here->BSIM4SPsbPtr) -= m * here->BSIM4gbs);
{ (*(here->BSIM4DPdbPtr +1) += mult_q * xcdbdb);
(*(here->BSIM4DPdbPtr) -= mult_i * here->BSIM4gbd);
(*(here->BSIM4SPsbPtr +1) += mult_q * xcsbsb);
(*(here->BSIM4SPsbPtr) -= mult_i * here->BSIM4gbs);
(*(here->BSIM4DBdpPtr +1) += m * xcdbdb);
(*(here->BSIM4DBdpPtr) -= m * here->BSIM4gbd);
(*(here->BSIM4DBdbPtr +1) -= m * xcdbdb);
(*(here->BSIM4DBdbPtr) += m * (here->BSIM4gbd + here->BSIM4grbpd
(*(here->BSIM4DBdpPtr +1) += mult_q * xcdbdb);
(*(here->BSIM4DBdpPtr) -= mult_i * here->BSIM4gbd);
(*(here->BSIM4DBdbPtr +1) -= mult_q * xcdbdb);
(*(here->BSIM4DBdbPtr) += mult_i * (here->BSIM4gbd + here->BSIM4grbpd
+ here->BSIM4grbdb));
(*(here->BSIM4DBbpPtr) -= m * here->BSIM4grbpd);
(*(here->BSIM4DBbPtr) -= m * here->BSIM4grbdb);
(*(here->BSIM4DBbpPtr) -= mult_i * here->BSIM4grbpd);
(*(here->BSIM4DBbPtr) -= mult_i * here->BSIM4grbdb);
(*(here->BSIM4BPdbPtr) -= m * here->BSIM4grbpd);
(*(here->BSIM4BPbPtr) -= m * here->BSIM4grbpb);
(*(here->BSIM4BPsbPtr) -= m * here->BSIM4grbps);
(*(here->BSIM4BPbpPtr) += m * (here->BSIM4grbpd + here->BSIM4grbps
(*(here->BSIM4BPdbPtr) -= mult_i * here->BSIM4grbpd);
(*(here->BSIM4BPbPtr) -= mult_i * here->BSIM4grbpb);
(*(here->BSIM4BPsbPtr) -= mult_i * here->BSIM4grbps);
(*(here->BSIM4BPbpPtr) += mult_i * (here->BSIM4grbpd + here->BSIM4grbps
+ here->BSIM4grbpb));
/* WDLiu: (-here->BSIM4gbbs) already added to BPbpPtr */
(*(here->BSIM4SBspPtr +1) += m * xcsbsb);
(*(here->BSIM4SBspPtr) -= m * here->BSIM4gbs);
(*(here->BSIM4SBbpPtr) -= m * here->BSIM4grbps);
(*(here->BSIM4SBbPtr) -= m * here->BSIM4grbsb);
(*(here->BSIM4SBsbPtr +1) -= m * xcsbsb);
(*(here->BSIM4SBsbPtr) += m * (here->BSIM4gbs
(*(here->BSIM4SBspPtr +1) += mult_q * xcsbsb);
(*(here->BSIM4SBspPtr) -= mult_i * here->BSIM4gbs);
(*(here->BSIM4SBbpPtr) -= mult_i * here->BSIM4grbps);
(*(here->BSIM4SBbPtr) -= mult_i * here->BSIM4grbsb);
(*(here->BSIM4SBsbPtr +1) -= mult_q * xcsbsb);
(*(here->BSIM4SBsbPtr) += mult_i * (here->BSIM4gbs
+ here->BSIM4grbps + here->BSIM4grbsb));
(*(here->BSIM4BdbPtr) -= m * here->BSIM4grbdb);
(*(here->BSIM4BbpPtr) -= m * here->BSIM4grbpb);
(*(here->BSIM4BsbPtr) -= m * here->BSIM4grbsb);
(*(here->BSIM4BbPtr) += m * (here->BSIM4grbsb + here->BSIM4grbdb
(*(here->BSIM4BdbPtr) -= mult_i * here->BSIM4grbdb);
(*(here->BSIM4BbpPtr) -= mult_i * here->BSIM4grbpb);
(*(here->BSIM4BsbPtr) -= mult_i * here->BSIM4grbsb);
(*(here->BSIM4BbPtr) += mult_i * (here->BSIM4grbsb + here->BSIM4grbdb
+ here->BSIM4grbpb));
}

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,8 +17,12 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
#include "ngspice/ifsim.h"
#include "ngspice/cktdefs.h"
@ -56,6 +53,15 @@ BSIM4instance *here = (BSIM4instance*)inst;
case BSIM4_M:
value->rValue = here->BSIM4m;
return(OK);
case BSIM4_MULT_I:
value->rValue = here->BSIM4mult_i;
return(OK);
case BSIM4_MULT_Q:
value->rValue = here->BSIM4mult_q;
return(OK);
case BSIM4_MULT_FN:
value->rValue = here->BSIM4mult_fn;
return(OK);
case BSIM4_NF:
value->rValue = here->BSIM4nf;
return(OK);
@ -123,12 +129,6 @@ BSIM4instance *here = (BSIM4instance*)inst;
case BSIM4_DELVTO:
value->rValue = here->BSIM4delvto;
return(OK);
case BSIM4_MULU0:
value->rValue = here->BSIM4mulu0;
return(OK);
case BSIM4_WNFLAG:
value->iValue = here->BSIM4wnflag;
return(OK);
case BSIM4_XGW:
value->rValue = here->BSIM4xgw;
return(OK);
@ -197,11 +197,11 @@ BSIM4instance *here = (BSIM4instance*)inst;
return(OK);
case BSIM4_SOURCECONDUCT:
value->rValue = here->BSIM4sourceConductance;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_DRAINCONDUCT:
value->rValue = here->BSIM4drainConductance;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_VBD:
value->rValue = *(ckt->CKTstate0 + here->BSIM4vbd);
@ -217,71 +217,67 @@ BSIM4instance *here = (BSIM4instance*)inst;
return(OK);
case BSIM4_CD:
value->rValue = here->BSIM4cd;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_CBS:
value->rValue = here->BSIM4cbs;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_CBD:
value->rValue = here->BSIM4cbd;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_CSUB:
value->rValue = here->BSIM4csub;
value->rValue *= here->BSIM4m;
return(OK);
case BSIM4_QINV:
value->rValue = here-> BSIM4qinv;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_IGIDL:
value->rValue = here->BSIM4Igidl;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_IGISL:
value->rValue = here->BSIM4Igisl;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_IGS:
value->rValue = here->BSIM4Igs;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_IGD:
value->rValue = here->BSIM4Igd;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_IGB:
value->rValue = here->BSIM4Igb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_IGCS:
value->rValue = here->BSIM4Igcs;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_IGCD:
value->rValue = here->BSIM4Igcd;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_GM:
value->rValue = here->BSIM4gm;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_GDS:
value->rValue = here->BSIM4gds;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_GMBS:
value->rValue = here->BSIM4gmbs;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_GBD:
value->rValue = here->BSIM4gbd;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_GBS:
value->rValue = here->BSIM4gbs;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
/* case BSIM4_QB:
value->rValue = *(ckt->CKTstate0 + here->BSIM4qb);
@ -306,102 +302,104 @@ BSIM4instance *here = (BSIM4instance*)inst;
return(OK); */
case BSIM4_QB:
value->rValue = here->BSIM4qbulk;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_QG:
value->rValue = here->BSIM4qgate;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_QS:
value->rValue = here->BSIM4qsrc;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_QD:
value->rValue = here->BSIM4qdrn;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_QINV:
value->rValue = here->BSIM4qinv;
return(OK);
case BSIM4_QDEF:
value->rValue = *(ckt->CKTstate0 + here->BSIM4qdef);
return(OK);
case BSIM4_GCRG:
value->rValue = here->BSIM4gcrg;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_i;
return(OK);
case BSIM4_GTAU:
value->rValue = here->BSIM4gtau;
value->rValue *= here->BSIM4m;
return(OK);
case BSIM4_CGGB:
value->rValue = here->BSIM4cggb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CGDB:
value->rValue = here->BSIM4cgdb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CGSB:
value->rValue = here->BSIM4cgsb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CDGB:
value->rValue = here->BSIM4cdgb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CDDB:
value->rValue = here->BSIM4cddb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CDSB:
value->rValue = here->BSIM4cdsb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CBGB:
value->rValue = here->BSIM4cbgb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CBDB:
value->rValue = here->BSIM4cbdb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CBSB:
value->rValue = here->BSIM4cbsb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CSGB:
value->rValue = here->BSIM4csgb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CSDB:
value->rValue = here->BSIM4csdb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CSSB:
value->rValue = here->BSIM4cssb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CGBB:
value->rValue = here->BSIM4cgbb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CDBB:
value->rValue = here->BSIM4cdbb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CSBB:
value->rValue = here->BSIM4csbb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CBBB:
value->rValue = here->BSIM4cbbb;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CAPBD:
value->rValue = here->BSIM4capbd;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_CAPBS:
value->rValue = here->BSIM4capbs;
value->rValue *= here->BSIM4m;
value->rValue *= here->BSIM4mult_q;
return(OK);
case BSIM4_VON:
value->rValue = here->BSIM4von;

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
@ -37,11 +33,6 @@ under the License.
#include "ngspice/wordlist.h"
#include "ngspice/cpextern.h"
/* Check for correctness of the BSIM4.8 parameters:
If parameter excursions are found, put the warning or error message into a wordlist.
Only then open a file bsim4.out and print the data into the file. */
int
BSIM4checkModel(
BSIM4model *model,
@ -75,38 +66,42 @@ CKTcircuit *ckt)
wl->wl_word = tprintf("\nChecking parameters for BSIM 4.8 model %s\n", model->BSIM4modName);
if ((strcmp(model->BSIM4version, "4.8.0")) && (strncmp(model->BSIM4version, "4.80", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) &&
(strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)))
(strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) &&
(strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4)))
{
printf("Warning: This model supports BSIM4 version 4.8\n");
printf("You specified a wrong version number. Working now with BSIM4.8.2\n");
printf("You specified a wrong version number. Working now with BSIM4.8.3\n");
wl_append_word(&wl, &wl, tprintf("Warning: This model supports BSIM4 version 4.8\n"));
wl_append_word(&wl, &wl, tprintf("You specified a wrong version number. Working now with BSIM4.8.2.\n"));
wl_append_word(&wl, &wl, tprintf("You specified a wrong version number. Working now with BSIM4.8.3.\n"));
}
if ((here->BSIM4rgateMod == 2) || (here->BSIM4rgateMod == 3))
{ if ((here->BSIM4trnqsMod == 1) || (here->BSIM4acnqsMod == 1)) {
{ if ((here->BSIM4trnqsMod == 1) || (here->BSIM4acnqsMod == 1))
{
wl_append_word(&wl, &wl, tprintf("Warning: You've selected both Rg and charge deficit NQS; select one only.\n"));
}
}
if (model->BSIM4toxe <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: Toxe = %g is not positive.\n",
model->BSIM4toxe));
wl_append_word(&wl, &wl, tprintf("Fatal: Toxe = %g is not positive.\n", model->BSIM4toxe));
Fatal_Flag = 1;
}
if (model->BSIM4toxp <= 0.0)
if (here->BSIM4toxp <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: Toxp = %g is not positive.\n", model->BSIM4toxp));
wl_append_word(&wl, &wl, tprintf("Fatal: Toxp = %g is not positive.\n", here->BSIM4toxp));
Fatal_Flag = 1;
}
if (model->BSIM4eot <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: EOT = %g is not positive.\n", model->BSIM4eot));
Fatal_Flag = 1;
}
if(model->BSIM4tempeot <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: TEMPEOT = %g is not positive.\n", model->BSIM4tempeot));
Fatal_Flag = 1;
}
if (model->BSIM4epsrgate < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: Epsrgate = %g is not positive.\n", model->BSIM4epsrgate));
@ -133,6 +128,7 @@ CKTcircuit *ckt)
wl_append_word(&wl, &wl, tprintf("Fatal: Toxm = %g is not positive.\n", model->BSIM4toxm));
Fatal_Flag = 1;
}
if (model->BSIM4toxref <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: Toxref = %g is not positive.\n", model->BSIM4toxref));
@ -171,6 +167,7 @@ CKTcircuit *ckt)
pParam->BSIM4phin, pParam->BSIM4ndep));
Fatal_Flag = 1;
}
if (pParam->BSIM4nsub <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: Nsub = %g is not positive.\n",
@ -260,6 +257,7 @@ CKTcircuit *ckt)
wl_append_word(&wl, &wl, tprintf("Fatal: multiplier = %g is not positive.\n", here->BSIM4m));
Fatal_Flag = 1;
}
if (here->BSIM4nf < 1.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: Number of finger = %g is smaller than one.\n", here->BSIM4nf));
@ -268,8 +266,7 @@ CKTcircuit *ckt)
if((here->BSIM4sa > 0.0) && (here->BSIM4sb > 0.0) &&
((here->BSIM4nf == 1.0) || ((here->BSIM4nf > 1.0) && (here->BSIM4sd > 0.0))) )
{
if (model->BSIM4saref <= 0.0)
{ if (model->BSIM4saref <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Fatal: SAref = %g is not positive.\n",model->BSIM4saref));
Fatal_Flag = 1;
@ -292,8 +289,7 @@ CKTcircuit *ckt)
Fatal_Flag = 1;
}
if ((here->BSIM4ngcon != 1.0) && (here->BSIM4ngcon != 2.0))
{
here->BSIM4ngcon = 1.0;
{ here->BSIM4ngcon = 1.0;
wl_append_word(&wl, &wl, tprintf("Warning: Ngcon must be equal to one or two; reset to 1.0.\n"));
}
@ -439,9 +435,9 @@ CKTcircuit *ckt)
{
wl_append_word(&wl, &wl, tprintf("Warning: Toxe = %g is less than 1A. Recommended Toxe >= 5A\n", model->BSIM4toxe));
}
if (model->BSIM4toxp < 1.0e-10)
if (here->BSIM4toxp < 1.0e-10)
{
wl_append_word(&wl, &wl, tprintf("Warning: Toxp = %g is less than 1A. Recommended Toxp >= 5A\n", model->BSIM4toxp));
wl_append_word(&wl, &wl, tprintf("Warning: Toxp = %g is less than 1A. Recommended Toxp >= 5A\n", here->BSIM4toxp));
}
if (model->BSIM4toxm < 1.0e-10)
{
@ -603,8 +599,6 @@ CKTcircuit *ckt)
{
wl_append_word(&wl, &wl, tprintf("Warning: Pdibl1 = %g is negative.\n", pParam->BSIM4pdibl1));
}
}
if (pParam->BSIM4pdibl2 < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: Pdibl2 = %g is negative.\n", pParam->BSIM4pdibl2));
@ -613,8 +607,7 @@ CKTcircuit *ckt)
/* Check stress effect parameters */
if((here->BSIM4sa > 0.0) && (here->BSIM4sb > 0.0) &&
((here->BSIM4nf == 1.0) || ((here->BSIM4nf > 1.0) && (here->BSIM4sd > 0.0))) )
{
if (model->BSIM4lodk2 <= 0.0)
{ if (model->BSIM4lodk2 <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: LODK2 = %g is not positive.\n",model->BSIM4lodk2));
}
@ -643,36 +636,45 @@ CKTcircuit *ckt)
}
/* Check body resistance parameters */
if (model->BSIM4rbps0 <= 0.0)
{ wl_append_word(&wl, &wl, tprintf("Fatal: RBPS0 = %g is not positive.\n", model->BSIM4rbps0));
{
wl_append_word(&wl, &wl, tprintf("Fatal: RBPS0 = %g is not positive.\n", model->BSIM4rbps0));
Fatal_Flag = 1;
}
if (model->BSIM4rbpd0 <= 0.0)
{ wl_append_word(&wl, &wl, tprintf("Fatal: RBPD0 = %g is not positive.\n", model->BSIM4rbpd0));
{
wl_append_word(&wl, &wl, tprintf("Fatal: RBPD0 = %g is not positive.\n", model->BSIM4rbpd0));
Fatal_Flag = 1;
}
if (model->BSIM4rbpbx0 <= 0.0)
{ wl_append_word(&wl, &wl, tprintf("Fatal: RBPBX0 = %g is not positive.\n", model->BSIM4rbpbx0));
{
wl_append_word(&wl, &wl, tprintf("Fatal: RBPBX0 = %g is not positive.\n", model->BSIM4rbpbx0));
Fatal_Flag = 1;
}
if (model->BSIM4rbpby0 <= 0.0)
{ wl_append_word(&wl, &wl, tprintf("Fatal: RBPBY0 = %g is not positive.\n", model->BSIM4rbpby0));
{
wl_append_word(&wl, &wl, tprintf("Fatal: RBPBY0 = %g is not positive.\n", model->BSIM4rbpby0));
Fatal_Flag = 1;
}
if (model->BSIM4rbdbx0 <= 0.0)
{ wl_append_word(&wl, &wl, tprintf("Fatal: RBDBX0 = %g is not positive.\n", model->BSIM4rbdbx0));
{
wl_append_word(&wl, &wl, tprintf("Fatal: RBDBX0 = %g is not positive.\n", model->BSIM4rbdbx0));
Fatal_Flag = 1;
}
if (model->BSIM4rbdby0 <= 0.0)
{ wl_append_word(&wl, &wl, tprintf("Fatal: RBDBY0 = %g is not positive.\n", model->BSIM4rbdby0));
{
wl_append_word(&wl, &wl, tprintf("Fatal: RBDBY0 = %g is not positive.\n", model->BSIM4rbdby0));
Fatal_Flag = 1;
}
if (model->BSIM4rbsbx0 <= 0.0)
{ wl_append_word(&wl, &wl, tprintf("Fatal: RBSBX0 = %g is not positive.\n", model->BSIM4rbsbx0));
{
wl_append_word(&wl, &wl, tprintf("Fatal: RBSBX0 = %g is not positive.\n", model->BSIM4rbsbx0));
Fatal_Flag = 1;
}
if (model->BSIM4rbsby0 <= 0.0)
{ wl_append_word(&wl, &wl, tprintf("Fatal: RBSBY0 = %g is not positive.\n", model->BSIM4rbsby0));
{
wl_append_word(&wl, &wl, tprintf("Fatal: RBSBY0 = %g is not positive.\n", model->BSIM4rbsby0));
Fatal_Flag = 1;
}
@ -686,7 +688,6 @@ CKTcircuit *ckt)
{
wl_append_word(&wl, &wl, tprintf("Warning: Voffcv = %g is too small.\n", pParam->BSIM4voffcv));
}
if (pParam->BSIM4moin < 5.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: Moin = %g is too small.\n", pParam->BSIM4moin));
@ -723,56 +724,18 @@ CKTcircuit *ckt)
model->BSIM4cgbo = 0.0;
}
if (model->BSIM4tnoiMod == 1){
wl_append_word(&wl, &wl, tprintf("Warning: TNOIMOD=1 is not supported and may be removed from future version.\n"));
wl_append_word(&wl, &wl, tprintf("Warning: TNOIMOD=%d is not supported and may be removed from future version.\n", model->BSIM4tnoiMod));
}
if (model->BSIM4idovvdsc <= 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: idovvdsc = %g is zero or negative.\n", model->BSIM4idovvdsc));
}
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) &&
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)))
{ /* checking for version <= 4.8 */
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) &&
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) &&
(strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4)))
{
/* v4.7 */
if (model->BSIM4tnoiMod == 1 || model->BSIM4tnoiMod == 2) {
if (model->BSIM4tnoia < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: tnoia = %g is negative. Set to zero.\n", model->BSIM4tnoia));
model->BSIM4tnoia = 0.0;
}
if (model->BSIM4tnoib < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: tnoib = %g is negative. Set to zero.\n", model->BSIM4tnoib));
model->BSIM4tnoib = 0.0;
}
if (model->BSIM4rnoia < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: rnoia = %g is negative. Set to zero.\n", model->BSIM4rnoia));
model->BSIM4rnoia = 0.0;
}
if (model->BSIM4rnoib < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: rnoib = %g is negative. Set to zero.\n", model->BSIM4rnoib));
model->BSIM4rnoib = 0.0;
}
}
/* v4.7 */
if (model->BSIM4tnoiMod == 2) {
if (model->BSIM4tnoic < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: tnoic = %g is negative. Set to zero.\n", model->BSIM4tnoic));
model->BSIM4tnoic = 0.0;
}
if (model->BSIM4rnoic < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: rnoic = %g is negative. Set to zero.\n", model->BSIM4rnoic));
model->BSIM4rnoic = 0.0;
}
}
}
else
{
if (model->BSIM4tnoiMod == 1){
if (model->BSIM4tnoia < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: tnoia = %g is negative. Set to zero.\n", model->BSIM4tnoia));
model->BSIM4tnoia = 0.0;
@ -790,8 +753,46 @@ CKTcircuit *ckt)
model->BSIM4rnoib = 0.0;
}
}
}
/* v4.7 */
if (model->BSIM4tnoiMod == 2) {
if (model->BSIM4tnoic < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: tnoic = %g is negative. Set to zero.\n", model->BSIM4tnoic));
model->BSIM4tnoic = 0.0;
}
if (model->BSIM4rnoic < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: rnoic = %g is negative. Set to zero.\n", model->BSIM4rnoic));
model->BSIM4rnoic = 0.0;
}
}
}
else
{
if (model->BSIM4tnoiMod == 1){
if (model->BSIM4tnoia < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: tnoia = %g is negative. Set to zero.\n", model->BSIM4tnoia));
model->BSIM4tnoia = 0.0;
}
if (model->BSIM4tnoib < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: tnoib = %g is negative. Set to zero.\n", model->BSIM4tnoib));
model->BSIM4tnoib = 0.0;
}
if (model->BSIM4rnoia < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: rnoia = %g is negative. Set to zero.\n", model->BSIM4rnoia));
model->BSIM4rnoia = 0.0;
}
if (model->BSIM4rnoib < 0.0) {
wl_append_word(&wl, &wl, tprintf("Warning: rnoib = %g is negative. Set to zero.\n", model->BSIM4rnoib));
model->BSIM4rnoib = 0.0;
}
}
}
/* Limits of Njs and Njd modified in BSIM4.7 */
if (model->BSIM4SjctEmissionCoeff < 0.1) {
wl_append_word(&wl, &wl, tprintf("Warning: Njs = %g is less than 0.1. Setting Njs to 0.1.\n", model->BSIM4SjctEmissionCoeff));
@ -800,8 +801,7 @@ CKTcircuit *ckt)
else if (model->BSIM4SjctEmissionCoeff < 0.7) {
wl_append_word(&wl, &wl, tprintf("Warning: Njs = %g is less than 0.7.\n", model->BSIM4SjctEmissionCoeff));
}
if (model->BSIM4DjctEmissionCoeff < 0.1)
{
if (model->BSIM4DjctEmissionCoeff < 0.1) {
wl_append_word(&wl, &wl, tprintf("Warning: Njd = %g is less than 0.1. Setting Njd to 0.1.\n", model->BSIM4DjctEmissionCoeff));
model->BSIM4DjctEmissionCoeff = 0.1;
}
@ -809,15 +809,18 @@ CKTcircuit *ckt)
wl_append_word(&wl, &wl, tprintf("Warning: Njd = %g is less than 0.7.\n", model->BSIM4DjctEmissionCoeff));
}
if (model->BSIM4njtsstemp < 0.0) {
if (model->BSIM4njtsstemp < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: Njts = %g is negative at temperature = %g.\n",
model->BSIM4njtsstemp, ckt->CKTtemp));
}
if (model->BSIM4njtsswstemp < 0.0) {
if (model->BSIM4njtsswstemp < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: Njtssw = %g is negative at temperature = %g.\n",
model->BSIM4njtsswstemp, ckt->CKTtemp));
}
if (model->BSIM4njtsswgstemp < 0.0) {
if (model->BSIM4njtsswgstemp < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: Njtsswg = %g is negative at temperature = %g.\n",
model->BSIM4njtsswgstemp, ckt->CKTtemp));
}
@ -883,26 +886,30 @@ CKTcircuit *ckt)
wl_append_word(&wl, &wl, tprintf("Warning: SCREF = %g is not positive. Set to 1e-6.\n", model->BSIM4scref));
model->BSIM4scref = 1e-6;
}
/*Move these checks to temp.c for sceff calculation*/
/*
if (here->BSIM4sca < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: SCA = %g is negative. Set to 0.0.\n", here->BSIM4sca));
wl_append_word(&wl, &wl, tprintf("Warning: SCA = %g is negative. Set to 0.0.\n", here->BSIM4sca);
here->BSIM4sca = 0.0;
}
if (here->BSIM4scb < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: SCB = %g is negative. Set to 0.0.\n", here->BSIM4scb));
wl_append_word(&wl, &wl, tprintf("Warning: SCB = %g is negative. Set to 0.0.\n", here->BSIM4scb);
here->BSIM4scb = 0.0;
}
if (here->BSIM4scc < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: SCC = %g is negative. Set to 0.0.\n", here->BSIM4scc));
wl_append_word(&wl, &wl, tprintf("Warning: SCC = %g is negative. Set to 0.0.\n", here->BSIM4scc);
here->BSIM4scc = 0.0;
}
if (here->BSIM4sc < 0.0)
{
wl_append_word(&wl, &wl, tprintf("Warning: SC = %g is negative. Set to 0.0.\n", here->BSIM4sc));
wl_append_word(&wl, &wl, tprintf("Warning: SC = %g is negative. Set to 0.0.\n", here->BSIM4sc);
here->BSIM4sc = 0.0;
}
*/
}
}
if (wlstart->wl_next) {
@ -923,7 +930,6 @@ CKTcircuit *ckt)
}
wl_free(wlstart);
return(Fatal_Flag);
}

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,8 +17,12 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "bsim4def.h"
@ -35,7 +32,6 @@ under the License.
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
BSIM4convTest(
GENmodel *inModel,
@ -57,8 +53,7 @@ double tol0, tol1, tol2, tol3, tol4, tol5, tol6;
for (; model != NULL; model = BSIM4nextModel(model))
{ for (here = BSIM4instances(model); here != NULL ;
here=BSIM4nextInstance(here))
{
vds = model->BSIM4type
{ vds = model->BSIM4type
* (*(ckt->CKTrhsOld + here->BSIM4dNodePrime)
- *(ckt->CKTrhsOld + here->BSIM4sNodePrime));
vgs = model->BSIM4type

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,12 +17,14 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
#include "bsim4def.h"
static int
BSIM4NumFingerDiff(
double nf,
@ -59,11 +54,9 @@ int NF;
return 0;
}
int
BSIM4PAeffGeo(
double nf,
int geo, int minSD,
double nf, int geo, int minSD,
double Weffcj, double DMCG, double DMCI, double DMDG,
double *Ps, double *Pd, double *As, double *Ad)
{
@ -163,10 +156,8 @@ return 0;
int
BSIM4RdseffGeo(
double nf,
int geo, int rgeo, int minSD,
double Weffcj, double Rsh, double DMCG, double DMCI, double DMDG,
int Type,
double nf, int geo, int rgeo, int minSD,
double Weffcj, double Rsh, double DMCG, double DMCI, double DMDG, int Type,
double *Rtot)
{
double Rint = 0.0, Rend = 0.0;
@ -284,12 +275,9 @@ return 0;
int
BSIM4RdsEndIso(
double Weffcj, double Rsh, double DMCG, double DMCI, double DMDG,
double nuEnd,
int rgeo, int Type,
double *Rend)
double nuEnd, int rgeo, int Type, double *Rend)
{
NG_IGNORE(DMDG);
if (Type == 1)
{ switch(rgeo)
{ case 1:
@ -345,9 +333,7 @@ return 0;
int
BSIM4RdsEndSha(
double Weffcj, double Rsh, double DMCG, double DMCI, double DMDG,
double nuEnd,
int rgeo, int Type,
double *Rend)
double nuEnd, int rgeo, int Type, double *Rend)
{
NG_IGNORE(DMCI);
NG_IGNORE(DMDG);

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
@ -32,7 +28,6 @@ under the License.
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
BSIM4getic(
GENmodel *inModel,

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,9 +17,10 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
*/
/**** OpenMP support ngspice 06/28/2010 ****/
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
@ -97,13 +91,13 @@ CKTcircuit *ckt)
return error;
}
int BSIM4LoadOMP(BSIM4instance *here, CKTcircuit *ckt) {
BSIM4model *model = BSIM4modPtr(here);
#else
BSIM4model *model = (BSIM4model*)inModel;
BSIM4instance *here;
#endif
double ceqgstot, dgstot_dvd, dgstot_dvg, dgstot_dvs, dgstot_dvb;
double ceqgdtot, dgdtot_dvd, dgdtot_dvg, dgdtot_dvs, dgdtot_dvb;
double gstot, gstotd, gstotg, gstots, gstotb, gspr, Rs, Rd;
@ -113,9 +107,6 @@ double dRs_dvg, dRd_dvg, dRs_dvb, dRd_dvb;
double dT0_dvg, dT1_dvb, dT3_dvg, dT3_dvb;
double vses, vdes, vdedo, delvses, delvded, delvdes;
double Isestot, cseshat, Idedtot, cdedhat;
#ifndef NEWCONV
double tol0, tol1, tol2, tol3, tol4, tol5, tol6;
#endif
double geltd, gcrg, gcrgg, gcrgd, gcrgs, gcrgb, ceqgcrg;
double vges, vgms, vgedo, vgmdo, vged, vgmd, delvged, delvgmd;
@ -123,10 +114,7 @@ double delvges, delvgms, vgmb;
double gcgmgmb=0.0, gcgmdb=0.0, gcgmsb=0.0, gcdgmb, gcsgmb;
double gcgmbb=0.0, gcbgmb, qgmb, qgmid=0.0, ceqqgmid;
double vbd, vbs, vds, vgb, vgd, vgs, vgdo;
#ifndef PREDICTOR
double xfact;
#endif
double vbd, vbs, vds, vgb, vgd, vgs, vgdo, xfact;
double vdbs, vdbd, vsbs, vsbdo, vsbd;
double delvdbs, delvdbd, delvsbs;
double delvbd_jct, delvbs_jct, vbs_jct, vbd_jct;
@ -191,7 +179,7 @@ double T8, dT8_dVg, dT8_dVd, dT8_dVb;
double T9, dT9_dVg, dT9_dVd, dT9_dVb;
double T10, dT10_dVg, dT10_dVb, dT10_dVd;
double T11, T12, T13, T14;
double tmp, Abulk, dAbulk_dVb, Abulk0, dAbulk0_dVb;
double tmp, Abulk, dAbulk_dVb, Abulk0, Abulk0_Q, dAbulk0_dVb, dAbulk0_Q_dVb;
double Cclm, dCclm_dVg, dCclm_dVd, dCclm_dVb;
double FP, dFP_dVg, PvagTerm, dPvagTerm_dVg, dPvagTerm_dVd, dPvagTerm_dVb;
double VADITS, dVADITS_dVg, dVADITS_dVd;
@ -233,7 +221,7 @@ double gbdpdp, gbdpg, gbdpb, gbdpsp;
double qgdo, qgso, cgdo, cgso;
double Cgg, Cgd, Cgb, Cdg, Cdd, Cds;
double Csg, Csd, Css, Csb, Cbg, Cbd, Cbb;
double Cgg1, Cgd1, Cgb1, Cbg1, Cbb1, Cbd1, Qac0, Qsub0;
double Cgg1, Cgb1, Cgd1, Cbg1, Cbb1, Cbd1, Qac0, Qsub0;
double dQac0_dVg, dQac0_dVb, dQsub0_dVg, dQsub0_dVd, dQsub0_dVb;
double ggidld, ggidlg, ggidlb, ggislg, ggislb, ggisls;
double Igisl, Ggislg, Ggislb, Ggisls;
@ -244,10 +232,10 @@ double vs, Fsevl, dvs_dVg, dvs_dVd, dvs_dVb, dFsevl_dVg, dFsevl_dVd, dFsevl_dVb;
double vgdx, vgsx, epssub, toxe, epsrox;
struct bsim4SizeDependParam *pParam;
int ByPass, ChargeComputationNeeded, error, Check, Check1, Check2;
double m;
double m, mult_i, mult_q;
ScalingFactor = 1.0e-9;
/* no integration, if dc sweep, but keep evaluating capacitances */
ChargeComputationNeeded =
((ckt->CKTmode & (MODEDCTRANCURVE | MODEAC | MODETRAN | MODEINITSMSIG)) ||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)))
@ -1425,12 +1413,34 @@ for (; model != NULL; model = BSIM4nextModel(model))
T0 = (17.0 + 20.0 * T2) * T1;
dT0_dVb = -pParam->BSIM4keta * T1 * T1;
}
dAbulk_dVg *= T0;
dAbulk_dVb = dAbulk_dVb * T0 + Abulk * dT0_dVb;
dAbulk0_Q_dVb = dAbulk0_dVb; // copy before scaling
dAbulk0_dVb = dAbulk0_dVb * T0 + Abulk0 * dT0_dVb;
Abulk *= T0;
Abulk0_Q = Abulk0; // copy before scaling
Abulk0 *= T0;
/* Calculate Abulk0_Q */
if (pParam->BSIM4ketac != pParam->BSIM4keta) {
T2 = pParam->BSIM4ketac * Vbseff;
if (T2 >= -0.9)
{ T0 = 1.0 / (1.0 + T2);
dT0_dVb = -pParam->BSIM4ketac * T0 * T0;
}
else
{ T1 = 1.0 / (0.8 + T2);
T0 = (17.0 + 20.0 * T2) * T1;
dT0_dVb = -pParam->BSIM4ketac * T1 * T1;
}
dAbulk0_Q_dVb = dAbulk0_Q_dVb * T0 + Abulk0_Q * dT0_dVb;
Abulk0_Q *= T0;
} else {
dAbulk0_Q_dVb = dAbulk0_dVb;
Abulk0_Q = Abulk0;
}
/* Mobility calculation */
if (model->BSIM4mtrlMod && model->BSIM4mtrlCompatMod == 0)
T14 = 2.0 * model->BSIM4type *(model->BSIM4phig - model->BSIM4easub - 0.5*model->BSIM4Eg0 + 0.45);
@ -2352,9 +2362,9 @@ for (; model != NULL; model = BSIM4nextModel(model))
T1 = (-vds - vgd_eff - pParam->BSIM4egisl + pParam->BSIM4vfbsd ) / T0;
if ((pParam->BSIM4agisl <= 0.0) || (pParam->BSIM4bgisl <= 0.0)
|| (T1 <= 0.0) || (pParam->BSIM4cgisl <= 0.0) || (vbs > 0.0))
|| (T1 <= 0.0) || (pParam->BSIM4cgisl <= 0.0) || (vbs > 0.0)) {
Igisl = Ggisls = Ggislg = Ggislb = 0.0;
else {
} else {
dT1_dVd = 1.0 / T0;
dT1_dVg = -dvgd_eff_dvg * dT1_dVd;
T2 = pParam->BSIM4bgisl / T1;
@ -2596,10 +2606,10 @@ for (; model != NULL; model = BSIM4nextModel(model))
dVaux_dVg *= dVgs_eff_dVg;
}
T2 = Vgs_eff * Vaux;
dT2_dVg = dVgs_eff_dVg * Vaux + Vgs_eff * dVaux_dVg;
dT2_dVd = Vgs_eff * dVaux_dVd;
dT2_dVb = Vgs_eff * dVaux_dVb;
T2 = Vgs * Vaux;
dT2_dVg = Vaux + Vgs * dVaux_dVg;
dT2_dVd = Vgs * dVaux_dVd;
dT2_dVb = Vgs * dVaux_dVb;
T11 = pParam->BSIM4Aechvb;
T12 = pParam->BSIM4Bechvb;
@ -2804,9 +2814,9 @@ for (; model != NULL; model = BSIM4nextModel(model))
dVaux_dVg = -dVaux_dVb * dVgs_eff_dVg;
}
T2 = (Vgs_eff - Vbseff) * Vaux;
dT2_dVg = dVgs_eff_dVg * Vaux + (Vgs_eff - Vbseff) * dVaux_dVg;
dT2_dVb = -Vaux + (Vgs_eff - Vbseff) * dVaux_dVb;
T2 = (Vgs - Vbs) * Vaux;
dT2_dVg = Vaux + (Vgs - Vbs) * dVaux_dVg;
dT2_dVb = -Vaux + (Vgs - Vbs) * dVaux_dVb;
T11 = 4.97232e-7 * pParam->BSIM4weff
* pParam->BSIM4leff * pParam->BSIM4ToxRatio;
@ -2859,10 +2869,10 @@ for (; model != NULL; model = BSIM4nextModel(model))
dVaux_dVg *= dVoxdepinv_dVg;
}
T2 = (Vgs_eff - Vbseff) * Vaux;
dT2_dVg = dVgs_eff_dVg * Vaux + (Vgs_eff - Vbseff) * dVaux_dVg;
dT2_dVd = (Vgs_eff - Vbseff) * dVaux_dVd;
dT2_dVb = -Vaux + (Vgs_eff - Vbseff) * dVaux_dVb;
T2 = (Vgs - Vbs) * Vaux;
dT2_dVg = Vaux + (Vgs - Vbs) * dVaux_dVg;
dT2_dVd = (Vgs - Vbs) * dVaux_dVd;
dT2_dVb = -Vaux + (Vgs - Vbs) * dVaux_dVb;
T11 *= 0.75610;
T12 *= 1.31724;
@ -2963,7 +2973,7 @@ for (; model != NULL; model = BSIM4nextModel(model))
/* Calculations for noise analysis */
if (model->BSIM4tnoiMod == 0)
{ Abulk = Abulk0 * pParam->BSIM4abulkCVfactor;
{ Abulk = Abulk0_Q * pParam->BSIM4abulkCVfactor;
Vdsat = Vgsteff / Abulk;
T0 = Vdsat - Vds - DELTA_4;
T1 = sqrt(T0 * T0 + 4.0 * DELTA_4 * Vdsat);
@ -3070,8 +3080,8 @@ for (; model != NULL; model = BSIM4nextModel(model))
{ One_Third_CoxWL = CoxWL / 3.0;
Two_Third_CoxWL = 2.0 * One_Third_CoxWL;
AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor;
dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb*dVbseff_dVb;
AbulkCV = Abulk0_Q * pParam->BSIM4abulkCVfactor;
dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_Q_dVb*dVbseff_dVb;
dVdsat_dVg = 1.0 / AbulkCV; /*4.6.2*/
Vdsat = Vgst * dVdsat_dVg;
@ -3479,8 +3489,8 @@ for (; model != NULL; model = BSIM4nextModel(model))
dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb
+ dVgsteff_dVb);
AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor;
dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb;
AbulkCV = Abulk0_Q * pParam->BSIM4abulkCVfactor;
dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_Q_dVb;
VdsatCV = Vgsteff / AbulkCV;
T0 = VdsatCV - Vds - DELTA_4;
@ -3738,8 +3748,8 @@ for (; model != NULL; model = BSIM4nextModel(model))
dCoxeff_dVg *= dTcen_dVg;
CoxWLcen = CoxWL * Coxeff / model->BSIM4coxe;
AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor;
dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb;
AbulkCV = Abulk0_Q * pParam->BSIM4abulkCVfactor;
dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_Q_dVb;
VdsatCV = VgDP / AbulkCV;
T0 = VdsatCV - Vds - DELTA_4;
@ -4164,9 +4174,8 @@ finished:
here->BSIM4cgso = cgso;
here->BSIM4qgso = qgso;
#ifndef NOBYPASS
line755:
#endif
ag0 = ckt->CKTag[0];
if (here->BSIM4mode > 0)
{ if (here->BSIM4trnqsMod == 0)
@ -4588,10 +4597,6 @@ line755:
if (!ChargeComputationNeeded)
goto line850;
/* no integration, if dc sweep, but keep evaluating capacitances */
if (ckt->CKTmode & MODEDCTRANCURVE)
goto line850;
if (ckt->CKTmode & MODEINITTRAN)
{ *(ckt->CKTstate1 + here->BSIM4qb) =
*(ckt->CKTstate0 + here->BSIM4qb);
@ -4801,9 +4806,9 @@ line900:
gIgtotb = gIstotb + gIdtotb + gIbtotb;
Igtoteq = Istoteq + Idtoteq + Ibtoteq;
}
else
else {
gIgtotg = gIgtotd = gIgtots = gIgtotb = Igtoteq = 0.0;
}
if (here->BSIM4rgateMod == 2)
T0 = vges - vgs;
@ -4970,66 +4975,67 @@ line900:
*/
m = here->BSIM4m;
mult_i = here->BSIM4mult_i;
mult_q = here->BSIM4mult_q;
#ifdef USE_OMP
here->BSIM4rhsdPrime = m * (ceqjd - ceqbd + ceqgdtot
- ceqdrn - ceqqd + Idtoteq);
here->BSIM4rhsgPrime = m * (ceqqg - ceqgcrg + Igtoteq);
here->BSIM4rhsdPrime = (mult_i * (ceqjd - ceqbd + ceqgdtot
- ceqdrn + Idtoteq) - mult_q * ceqqd);
here->BSIM4rhsgPrime = mult_q * ceqqg - mult_i * (ceqgcrg - Igtoteq);
if (here->BSIM4rgateMod == 2)
here->BSIM4rhsgExt = m * ceqgcrg;
here->BSIM4rhsgExt = mult_i * ceqgcrg;
else if (here->BSIM4rgateMod == 3)
here->BSIM4grhsMid = m * (ceqqgmid + ceqgcrg);
here->BSIM4grhsMid = mult_q * ceqqgmid + mult_i * ceqgcrg;
if (!here->BSIM4rbodyMod)
{ here->BSIM4rhsbPrime = m * (ceqbd + ceqbs - ceqjd
- ceqjs - ceqqb + Ibtoteq);
here->BSIM4rhssPrime = m * (ceqdrn - ceqbs + ceqjs
+ ceqqg + ceqqb + ceqqd + ceqqgmid - ceqgstot + Istoteq);
{ here->BSIM4rhsbPrime = (mult_i * (ceqbd + ceqbs - ceqjd
- ceqjs + Ibtoteq) - mult_q * ceqqb);
here->BSIM4rhssPrime = (mult_i * (ceqdrn - ceqbs + ceqjs
- ceqgstot + Istoteq) + mult_q * (ceqqg + ceqqb + ceqqd + ceqqgmid));
}
else
{ here->BSIM4rhsdb = m * (ceqjd + ceqqjd);
here->BSIM4rhsbPrime = m * (ceqbd + ceqbs - ceqqb + Ibtoteq);
here->BSIM4rhssb = m * (ceqjs + ceqqjs);
here->BSIM4rhssPrime = m * (ceqdrn - ceqbs + ceqjs + ceqqd
+ ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid - ceqgstot + Istoteq);
{ here->BSIM4rhsdb = mult_i * (ceqjd + ceqqjd);
here->BSIM4rhsbPrime = (mult_i * (ceqbd + ceqbs + Ibtoteq) - mult_q * ceqqb);
here->BSIM4rhssb = mult_i * (ceqjs + ceqqjs);
here->BSIM4rhssPrime = (mult_i * (ceqdrn - ceqbs + ceqjs - ceqgstot + Istoteq) + mult_q * (ceqqd
+ ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid));
}
if (model->BSIM4rdsMod)
{ here->BSIM4rhsd = m * ceqgdtot;
here->BSIM4rhss = m * ceqgstot;
{ here->BSIM4rhsd = mult_i * ceqgdtot;
here->BSIM4rhss = mult_i * ceqgstot;
}
if (here->BSIM4trnqsMod)
here->BSIM4rhsq = m * (cqcheq - cqdef);
#else
(*(ckt->CKTrhs + here->BSIM4dNodePrime) += m * (ceqjd - ceqbd + ceqgdtot
- ceqdrn - ceqqd + Idtoteq));
(*(ckt->CKTrhs + here->BSIM4gNodePrime) -= m * (ceqqg - ceqgcrg + Igtoteq));
(*(ckt->CKTrhs + here->BSIM4dNodePrime) += (mult_i * (ceqjd - ceqbd + ceqgdtot
- ceqdrn + Idtoteq) - mult_q * ceqqd));
(*(ckt->CKTrhs + here->BSIM4gNodePrime) -= mult_q * ceqqg - mult_i * (ceqgcrg - Igtoteq));
if (here->BSIM4rgateMod == 2)
(*(ckt->CKTrhs + here->BSIM4gNodeExt) -= m * ceqgcrg);
(*(ckt->CKTrhs + here->BSIM4gNodeExt) -= mult_i * ceqgcrg);
else if (here->BSIM4rgateMod == 3)
(*(ckt->CKTrhs + here->BSIM4gNodeMid) -= m * (ceqqgmid + ceqgcrg));
(*(ckt->CKTrhs + here->BSIM4gNodeMid) -= mult_q * ceqqgmid + mult_i * ceqgcrg);
if (!here->BSIM4rbodyMod)
{ (*(ckt->CKTrhs + here->BSIM4bNodePrime) += m * (ceqbd + ceqbs - ceqjd
- ceqjs - ceqqb + Ibtoteq));
(*(ckt->CKTrhs + here->BSIM4sNodePrime) += m * (ceqdrn - ceqbs + ceqjs
+ ceqqg + ceqqb + ceqqd + ceqqgmid - ceqgstot + Istoteq));
{ (*(ckt->CKTrhs + here->BSIM4bNodePrime) += (mult_i * (ceqbd + ceqbs - ceqjd
- ceqjs + Ibtoteq) - mult_q * ceqqb));
(*(ckt->CKTrhs + here->BSIM4sNodePrime) += (mult_i * (ceqdrn - ceqbs + ceqjs
- ceqgstot + Istoteq) + mult_q * (ceqqg + ceqqb + ceqqd + ceqqgmid)));
}
else
{ (*(ckt->CKTrhs + here->BSIM4dbNode) -= m * (ceqjd + ceqqjd));
(*(ckt->CKTrhs + here->BSIM4bNodePrime) += m * (ceqbd + ceqbs - ceqqb + Ibtoteq));
(*(ckt->CKTrhs + here->BSIM4sbNode) -= m * (ceqjs + ceqqjs));
(*(ckt->CKTrhs + here->BSIM4sNodePrime) += m * (ceqdrn - ceqbs + ceqjs + ceqqd
+ ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid - ceqgstot + Istoteq));
{ (*(ckt->CKTrhs + here->BSIM4dbNode) -= mult_i * (ceqjd + ceqqjd));
(*(ckt->CKTrhs + here->BSIM4bNodePrime) += (mult_i * (ceqbd + ceqbs + Ibtoteq) - mult_q * ceqqb));
(*(ckt->CKTrhs + here->BSIM4sbNode) -= mult_i * (ceqjs + ceqqjs));
(*(ckt->CKTrhs + here->BSIM4sNodePrime) += (mult_i * (ceqdrn - ceqbs + ceqjs - ceqgstot + Istoteq) + mult_q * (ceqqd
+ ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid)));
}
if (model->BSIM4rdsMod)
{ (*(ckt->CKTrhs + here->BSIM4dNode) -= m * ceqgdtot);
(*(ckt->CKTrhs + here->BSIM4sNode) += m * ceqgstot);
{ (*(ckt->CKTrhs + here->BSIM4dNode) -= mult_i * ceqgdtot);
(*(ckt->CKTrhs + here->BSIM4sNode) += mult_i * ceqgstot);
}
if (here->BSIM4trnqsMod)
@ -5057,96 +5063,96 @@ line900:
geltd = here->BSIM4grgeltd;
T1 = qdef * here->BSIM4gtau;
#ifdef USE_OMP
if (here->BSIM4rgateMod == 1)
{ here->BSIM4_1 = m * geltd;
here->BSIM4_2 = m * geltd;
here->BSIM4_3 = m * geltd;
here->BSIM4_4 = m * (gcggb + geltd - ggtg + gIgtotg);
here->BSIM4_5 = m * (gcgdb - ggtd + gIgtotd);
here->BSIM4_6 = m * (gcgsb - ggts + gIgtots);
here->BSIM4_7 = m * (gcgbb - ggtb + gIgtotb);
{ here->BSIM4_1 = mult_i * geltd;
here->BSIM4_2 = mult_i * geltd;
here->BSIM4_3 = mult_i * geltd;
here->BSIM4_4 = mult_q * (gcggb - ggtg) + mult_i * (geltd + gIgtotg);
here->BSIM4_5 = mult_q * (gcgdb - ggtd) + mult_i * gIgtotd;
here->BSIM4_6 = mult_q * (gcgsb - ggts) + mult_i * gIgtots;
here->BSIM4_7 = mult_q * (gcgbb - ggtb) + mult_i * gIgtotb;
} /* WDLiu: gcrg already subtracted from all gcrgg below */
else if (here->BSIM4rgateMod == 2)
{ here->BSIM4_8 = m * gcrg;
here->BSIM4_9 = m * gcrgg;
here->BSIM4_10 = m * gcrgd;
here->BSIM4_11 = m * gcrgs;
here->BSIM4_12 = m * gcrgb;
{ here->BSIM4_8 = mult_i * gcrg;
here->BSIM4_9 = mult_i * gcrgg;
here->BSIM4_10 = mult_i * gcrgd;
here->BSIM4_11 = mult_i * gcrgs;
here->BSIM4_12 = mult_i * gcrgb;
here->BSIM4_13 = m * gcrg;
here->BSIM4_14 = m * (gcggb - gcrgg - ggtg + gIgtotg);
here->BSIM4_15 = m * (gcgdb - gcrgd - ggtd + gIgtotd);
here->BSIM4_16 = m * (gcgsb - gcrgs - ggts + gIgtots);
here->BSIM4_17 = m * (gcgbb - gcrgb - ggtb + gIgtotb);
here->BSIM4_13 = mult_i * gcrg;
here->BSIM4_14 = mult_q * (gcggb - ggtg) + mult_i * (gIgtotg - gcrgg);
here->BSIM4_15 = mult_q * (gcgdb - ggtd) + mult_i * (gIgtotd - gcrgd);
here->BSIM4_16 = mult_q * (gcgsb - ggts) + mult_i * (gIgtots - gcrgs);
here->BSIM4_17 = mult_q * (gcgbb - ggtb) + mult_i * (gIgtotb - gcrgb);
}
else if (here->BSIM4rgateMod == 3)
{ here->BSIM4_18 = m * geltd;
here->BSIM4_19 = m * geltd;
here->BSIM4_20 = m * geltd;
here->BSIM4_21 = m * (geltd + gcrg + gcgmgmb);
{ here->BSIM4_18 = mult_i * geltd;
here->BSIM4_19 = mult_i * geltd;
here->BSIM4_20 = mult_i * geltd;
here->BSIM4_21 = mult_i * (geltd + gcrg) + mult_q * gcgmgmb;
here->BSIM4_22 = m * (gcrgd + gcgmdb);
here->BSIM4_23 = m * gcrgg;
here->BSIM4_24 = m * (gcrgs + gcgmsb);
here->BSIM4_25 = m * (gcrgb + gcgmbb);
here->BSIM4_22 = mult_i * gcrgd + mult_q * gcgmdb;
here->BSIM4_23 = mult_i * gcrgg;
here->BSIM4_24 = mult_i * gcrgs + mult_q * gcgmsb;
here->BSIM4_25 = mult_i * gcrgb + mult_q * gcgmbb;
here->BSIM4_26 = m * gcdgmb;
here->BSIM4_27 = m * gcrg;
here->BSIM4_28 = m * gcsgmb;
here->BSIM4_29 = m * gcbgmb;
here->BSIM4_26 = mult_q * gcdgmb;
here->BSIM4_27 = mult_i * gcrg;
here->BSIM4_28 = mult_q * gcsgmb;
here->BSIM4_29 = mult_q * gcbgmb;
here->BSIM4_30 = m * (gcggb - gcrgg - ggtg + gIgtotg);
here->BSIM4_31 = m * (gcgdb - gcrgd - ggtd + gIgtotd);
here->BSIM4_32 = m * (gcgsb - gcrgs - ggts + gIgtots);
here->BSIM4_33 = m * (gcgbb - gcrgb - ggtb + gIgtotb);
here->BSIM4_30 = mult_q * (gcggb - ggtg) + mult_i * (gIgtotg - gcrgg);
here->BSIM4_31 = mult_q * (gcgdb - ggtd) + mult_i * (gIgtotd - gcrgd);
here->BSIM4_32 = mult_q * (gcgsb - ggts) + mult_i * (gIgtots - gcrgs);
here->BSIM4_33 = mult_q * (gcgbb - ggtb) + mult_i * (gIgtotb - gcrgb);
}
else
{ here->BSIM4_34 = m * (gcggb - ggtg + gIgtotg);
here->BSIM4_35 = m * (gcgdb - ggtd + gIgtotd);
here->BSIM4_36 = m * (gcgsb - ggts + gIgtots);
here->BSIM4_37 = m * (gcgbb - ggtb + gIgtotb);
{ here->BSIM4_34 = mult_q * (gcggb - ggtg) + mult_i * gIgtotg;
here->BSIM4_35 = mult_q * (gcgdb - ggtd) + mult_i * gIgtotd;
here->BSIM4_36 = mult_q * (gcgsb - ggts) + mult_i * gIgtots;
here->BSIM4_37 = mult_q * (gcgbb - ggtb) + mult_i * gIgtotb;
}
if (model->BSIM4rdsMod)
{ here->BSIM4_38 = m * gdtotg;
here->BSIM4_39 = m * gdtots;
here->BSIM4_40 = m * gdtotb;
here->BSIM4_41 = m * gstotd;
here->BSIM4_42 = m * gstotg;
here->BSIM4_43 = m * gstotb;
{ here->BSIM4_38 = mult_i * gdtotg;
here->BSIM4_39 = mult_i * gdtots;
here->BSIM4_40 = mult_i * gdtotb;
here->BSIM4_41 = mult_i * gstotd;
here->BSIM4_42 = mult_i * gstotg;
here->BSIM4_43 = mult_i * gstotb;
}
here->BSIM4_44 = m * (gdpr + here->BSIM4gds + here->BSIM4gbd + T1 * ddxpart_dVd
- gdtotd + RevSum + gcddb + gbdpdp + dxpart * ggtd - gIdtotd);
here->BSIM4_45 = m * (gdpr + gdtot);
here->BSIM4_46 = m * (Gm + gcdgb - gdtotg + gbdpg - gIdtotg
+ dxpart * ggtg + T1 * ddxpart_dVg);
here->BSIM4_47 = m * (here->BSIM4gds + gdtots - dxpart * ggts + gIdtots
- T1 * ddxpart_dVs + FwdSum - gcdsb - gbdpsp);
here->BSIM4_48 = m * (gjbd + gdtotb - Gmbs - gcdbb - gbdpb + gIdtotb
- T1 * ddxpart_dVb - dxpart * ggtb);
here->BSIM4_44 = mult_i * (gdpr + here->BSIM4gds + here->BSIM4gbd
- gdtotd + RevSum + gbdpdp - gIdtotd) + mult_q * (T1 * ddxpart_dVd + gcddb + dxpart * ggtd);
here->BSIM4_45 = mult_i * (gdpr + gdtot);
here->BSIM4_46 = mult_i * (Gm - gdtotg + gbdpg - gIdtotg)
+ mult_q * (dxpart * ggtg + T1 * ddxpart_dVg + gcdgb);
here->BSIM4_47 = mult_i * (here->BSIM4gds + gdtots + gIdtots
+ FwdSum - gbdpsp) - mult_q * (dxpart * ggts + T1 * ddxpart_dVs + gcdsb);
here->BSIM4_48 = mult_i * (gjbd + gdtotb - Gmbs - gbdpb + gIdtotb)
- mult_q * (dxpart * ggtb + gcdbb + T1 * ddxpart_dVb);
here->BSIM4_49 = m * (gdpr - gdtotd);
here->BSIM4_50 = m * (gdpr + gdtot);
here->BSIM4_49 = mult_i * (gdpr - gdtotd);
here->BSIM4_50 = mult_i * (gdpr + gdtot);
here->BSIM4_51 = m * (here->BSIM4gds + gstotd + RevSum - gcsdb - gbspdp
- T1 * dsxpart_dVd - sxpart * ggtd + gIstotd);
here->BSIM4_52 = m * (gcsgb - Gm - gstotg + gbspg + sxpart * ggtg
+ T1 * dsxpart_dVg - gIstotg);
here->BSIM4_53 = m * (gspr + here->BSIM4gds + here->BSIM4gbs + T1 * dsxpart_dVs
- gstots + FwdSum + gcssb + gbspsp + sxpart * ggts - gIstots);
here->BSIM4_54 = m * (gspr + gstot);
here->BSIM4_55 = m * (gjbs + gstotb + Gmbs - gcsbb - gbspb - sxpart * ggtb
- T1 * dsxpart_dVb + gIstotb);
here->BSIM4_51 = mult_i * (here->BSIM4gds + gstotd + RevSum - gbspdp + gIstotd)
- mult_q * (T1 * dsxpart_dVd + sxpart * ggtd + gcsdb);
here->BSIM4_52 = mult_q * (gcsgb + sxpart * ggtg + T1 * dsxpart_dVg) + mult_i * (gbspg - Gm - gstotg - gIstotg);
here->BSIM4_53 = mult_i * (gspr + here->BSIM4gds + here->BSIM4gbs - gIstots - gstots + FwdSum + gbspsp)
+ mult_q * (sxpart * ggts + T1 * dsxpart_dVs + gcssb);
here->BSIM4_54 = mult_i * (gspr + gstot);
here->BSIM4_55 = mult_i * (gjbs + gstotb + Gmbs - gbspb + gIstotb) - mult_q * (gcsbb + sxpart * ggtb + T1 * dsxpart_dVb);
here->BSIM4_56 = m * (gspr - gstots);
here->BSIM4_57 = m * (gspr + gstot);
here->BSIM4_56 = mult_i * (gspr - gstots);
here->BSIM4_57 = mult_i * (gspr + gstot);
here->BSIM4_58 = m * (gcbdb - gjbd + gbbdp - gIbtotd);
here->BSIM4_59 = m * (gcbgb - here->BSIM4gbgs - gIbtotg);
here->BSIM4_60 = m * (gcbsb - gjbs + gbbsp - gIbtots);
here->BSIM4_61 = m * (gjbd + gjbs + gcbbb - here->BSIM4gbbs - gIbtotb);
here->BSIM4_58 = mult_q * gcbdb - mult_i * (gjbd - gbbdp + gIbtotd);
here->BSIM4_59 = mult_q * gcbgb - mult_i * (here->BSIM4gbgs + gIbtotg);
here->BSIM4_60 = mult_q * gcbsb - mult_i * (gjbs - gbbsp + gIbtots);
here->BSIM4_61 = mult_i * (gjbd + gjbs - here->BSIM4gbbs
- gIbtotb) + mult_q * gcbbb;
ggidld = here->BSIM4ggidld;
ggidlg = here->BSIM4ggidlg;
@ -5156,51 +5162,50 @@ line900:
ggislb = here->BSIM4ggislb;
/* stamp gidl */
here->BSIM4_62 = m * ggidld;
here->BSIM4_63 = m * ggidlg;
here->BSIM4_64 = m * (ggidlg + ggidld + ggidlb);
here->BSIM4_65 = m * ggidlb;
here->BSIM4_66 = m * ggidld;
here->BSIM4_67 = m * ggidlg;
here->BSIM4_68 = m * (ggidlg + ggidld + ggidlb);
here->BSIM4_69 = m * ggidlb;
here->BSIM4_62 = mult_i * ggidld;
here->BSIM4_63 = mult_i * ggidlg;
here->BSIM4_64 = mult_i * (ggidlg + ggidld + ggidlb);
here->BSIM4_65 = mult_i * ggidlb;
here->BSIM4_66 = mult_i * ggidld;
here->BSIM4_67 = mult_i * ggidlg;
here->BSIM4_68 = mult_i * (ggidlg + ggidld + ggidlb);
here->BSIM4_69 = mult_i * ggidlb;
/* stamp gisl */
here->BSIM4_70 = m * (ggisls + ggislg + ggislb);
here->BSIM4_71 = m * ggislg;
here->BSIM4_72 = m * ggisls;
here->BSIM4_73 = m * ggislb;
here->BSIM4_74 = m * (ggislg + ggisls + ggislb);
here->BSIM4_75 = m * ggislg;
here->BSIM4_76 = m * ggisls;
here->BSIM4_77 = m * ggislb;
here->BSIM4_70 = mult_i * (ggisls + ggislg + ggislb);
here->BSIM4_71 = mult_i * ggislg;
here->BSIM4_72 = mult_i * ggisls;
here->BSIM4_73 = mult_i * ggislb;
here->BSIM4_74 = mult_i * (ggislg + ggisls + ggislb);
here->BSIM4_75 = mult_i * ggislg;
here->BSIM4_76 = mult_i * ggisls;
here->BSIM4_77 = mult_i * ggislb;
if (here->BSIM4rbodyMod)
{ here->BSIM4_78 = m * (gcdbdb - here->BSIM4gbd);
here->BSIM4_79 = m * (here->BSIM4gbs - gcsbsb);
{ here->BSIM4_78 = mult_q * gcdbdb - mult_i * here->BSIM4gbd;
here->BSIM4_79 = mult_i * here->BSIM4gbs - mult_q * gcsbsb;
here->BSIM4_80 = m * (gcdbdb - here->BSIM4gbd);
here->BSIM4_81 = m * (here->BSIM4gbd - gcdbdb
+ here->BSIM4grbpd + here->BSIM4grbdb);
here->BSIM4_82 = m * here->BSIM4grbpd;
here->BSIM4_83 = m * here->BSIM4grbdb;
here->BSIM4_80 = mult_q * gcdbdb - mult_i * here->BSIM4gbd;
here->BSIM4_81 = mult_i * (here->BSIM4gbd + here->BSIM4grbpd + here->BSIM4grbdb) - mult_q * gcdbdb;
here->BSIM4_82 = mult_i * here->BSIM4grbpd;
here->BSIM4_83 = mult_i * here->BSIM4grbdb;
here->BSIM4_84 = m * here->BSIM4grbpd;
here->BSIM4_85 = m * here->BSIM4grbpb;
here->BSIM4_86 = m * here->BSIM4grbps;
here->BSIM4_87 = m * (here->BSIM4grbpd + here->BSIM4grbps
here->BSIM4_84 = mult_i * here->BSIM4grbpd;
here->BSIM4_85 = mult_i * here->BSIM4grbpb;
here->BSIM4_86 = mult_i * here->BSIM4grbps;
here->BSIM4_87 = mult_i * (here->BSIM4grbpd + here->BSIM4grbps
+ here->BSIM4grbpb);
/* WDLiu: (gcbbb - here->BSIM4gbbs) already added to BPbpPtr */
here->BSIM4_88 = m * (gcsbsb - here->BSIM4gbs);
here->BSIM4_89 = m * here->BSIM4grbps;
here->BSIM4_90 = m * here->BSIM4grbsb;
here->BSIM4_91 = m * (here->BSIM4gbs - gcsbsb
here->BSIM4_88 = mult_q * gcsbsb - mult_i * here->BSIM4gbs;
here->BSIM4_89 = mult_i * here->BSIM4grbps;
here->BSIM4_90 = mult_i * here->BSIM4grbsb;
here->BSIM4_91 = mult_i * (here->BSIM4gbs - gcsbsb
+ here->BSIM4grbps + here->BSIM4grbsb);
here->BSIM4_92 = m * here->BSIM4grbdb;
here->BSIM4_93 = m * here->BSIM4grbpb;
here->BSIM4_94 = m * here->BSIM4grbsb;
here->BSIM4_95 = m * (here->BSIM4grbsb + here->BSIM4grbdb
here->BSIM4_92 = mult_i * here->BSIM4grbdb;
here->BSIM4_93 = mult_i * here->BSIM4grbpb;
here->BSIM4_94 = mult_i * here->BSIM4grbsb;
here->BSIM4_95 = mult_i * (here->BSIM4grbsb + here->BSIM4grbdb
+ here->BSIM4grbpb);
}
@ -5217,95 +5222,92 @@ line900:
}
#else
if (here->BSIM4rgateMod == 1)
{ (*(here->BSIM4GEgePtr) += m * geltd);
(*(here->BSIM4GPgePtr) -= m * geltd);
(*(here->BSIM4GEgpPtr) -= m * geltd);
(*(here->BSIM4GPgpPtr) += m * (gcggb + geltd - ggtg + gIgtotg));
(*(here->BSIM4GPdpPtr) += m * (gcgdb - ggtd + gIgtotd));
(*(here->BSIM4GPspPtr) += m * (gcgsb - ggts + gIgtots));
(*(here->BSIM4GPbpPtr) += m * (gcgbb - ggtb + gIgtotb));
{ (*(here->BSIM4GEgePtr) += mult_i * geltd);
(*(here->BSIM4GPgePtr) -= mult_i * geltd);
(*(here->BSIM4GEgpPtr) -= mult_i * geltd);
(*(here->BSIM4GPgpPtr) += mult_q * (gcggb - ggtg) + mult_i * (geltd + gIgtotg));
(*(here->BSIM4GPdpPtr) += mult_q * (gcgdb - ggtd) + mult_i * gIgtotd);
(*(here->BSIM4GPspPtr) += mult_q * (gcgsb - ggts) + mult_i * gIgtots);
(*(here->BSIM4GPbpPtr) += mult_q * (gcgbb - ggtb) + mult_i * gIgtotb);
} /* WDLiu: gcrg already subtracted from all gcrgg below */
else if (here->BSIM4rgateMod == 2)
{ (*(here->BSIM4GEgePtr) += m * gcrg);
(*(here->BSIM4GEgpPtr) += m * gcrgg);
(*(here->BSIM4GEdpPtr) += m * gcrgd);
(*(here->BSIM4GEspPtr) += m * gcrgs);
(*(here->BSIM4GEbpPtr) += m * gcrgb);
{ (*(here->BSIM4GEgePtr) += mult_i * gcrg);
(*(here->BSIM4GEgpPtr) += mult_i * gcrgg);
(*(here->BSIM4GEdpPtr) += mult_i * gcrgd);
(*(here->BSIM4GEspPtr) += mult_i * gcrgs);
(*(here->BSIM4GEbpPtr) += mult_i * gcrgb);
(*(here->BSIM4GPgePtr) -= m * gcrg);
(*(here->BSIM4GPgpPtr) += m * (gcggb - gcrgg - ggtg + gIgtotg));
(*(here->BSIM4GPdpPtr) += m * (gcgdb - gcrgd - ggtd + gIgtotd));
(*(here->BSIM4GPspPtr) += m * (gcgsb - gcrgs - ggts + gIgtots));
(*(here->BSIM4GPbpPtr) += m * (gcgbb - gcrgb - ggtb + gIgtotb));
(*(here->BSIM4GPgePtr) -= mult_i * gcrg);
(*(here->BSIM4GPgpPtr) += mult_q * (gcggb - ggtg) + mult_i * (gIgtotg - gcrgg));
(*(here->BSIM4GPdpPtr) += mult_q * (gcgdb - ggtd) + mult_i * (gIgtotd - gcrgd));
(*(here->BSIM4GPspPtr) += mult_q * (gcgsb - ggts) + mult_i * (gIgtots - gcrgs));
(*(here->BSIM4GPbpPtr) += mult_q * (gcgbb - ggtb) + mult_i * (gIgtotb - gcrgb));
}
else if (here->BSIM4rgateMod == 3)
{ (*(here->BSIM4GEgePtr) += m * geltd);
(*(here->BSIM4GEgmPtr) -= m * geltd);
(*(here->BSIM4GMgePtr) -= m * geltd);
(*(here->BSIM4GMgmPtr) += m * (geltd + gcrg + gcgmgmb));
{ (*(here->BSIM4GEgePtr) += mult_i * geltd);
(*(here->BSIM4GEgmPtr) -= mult_i * geltd);
(*(here->BSIM4GMgePtr) -= mult_i * geltd);
(*(here->BSIM4GMgmPtr) += mult_i * (geltd + gcrg) + mult_q * gcgmgmb);
(*(here->BSIM4GMdpPtr) += m * (gcrgd + gcgmdb));
(*(here->BSIM4GMgpPtr) += m * gcrgg);
(*(here->BSIM4GMspPtr) += m * (gcrgs + gcgmsb));
(*(here->BSIM4GMbpPtr) += m * (gcrgb + gcgmbb));
(*(here->BSIM4GMdpPtr) += mult_i * gcrgd + mult_q * gcgmdb);
(*(here->BSIM4GMgpPtr) += mult_i * gcrgg);
(*(here->BSIM4GMspPtr) += mult_i * gcrgs + mult_q * gcgmsb);
(*(here->BSIM4GMbpPtr) += mult_i * gcrgb + mult_q * gcgmbb);
(*(here->BSIM4DPgmPtr) += m * gcdgmb);
(*(here->BSIM4GPgmPtr) -= m * gcrg);
(*(here->BSIM4SPgmPtr) += m * gcsgmb);
(*(here->BSIM4BPgmPtr) += m * gcbgmb);
(*(here->BSIM4DPgmPtr) += mult_q * gcdgmb);
(*(here->BSIM4GPgmPtr) -= mult_i * gcrg);
(*(here->BSIM4SPgmPtr) += mult_q * gcsgmb);
(*(here->BSIM4BPgmPtr) += mult_q * gcbgmb);
(*(here->BSIM4GPgpPtr) += m * (gcggb - gcrgg - ggtg + gIgtotg));
(*(here->BSIM4GPdpPtr) += m * (gcgdb - gcrgd - ggtd + gIgtotd));
(*(here->BSIM4GPspPtr) += m * (gcgsb - gcrgs - ggts + gIgtots));
(*(here->BSIM4GPbpPtr) += m * (gcgbb - gcrgb - ggtb + gIgtotb));
(*(here->BSIM4GPgpPtr) += mult_q * (gcggb - ggtg) + mult_i * (gIgtotg - gcrgg));
(*(here->BSIM4GPdpPtr) += mult_q * (gcgdb - ggtd) + mult_i * (gIgtotd - gcrgd));
(*(here->BSIM4GPspPtr) += mult_q * (gcgsb - ggts) + mult_i * (gIgtots - gcrgs));
(*(here->BSIM4GPbpPtr) += mult_q * (gcgbb - ggtb) + mult_i * (gIgtotb - gcrgb));
}
else
{ (*(here->BSIM4GPgpPtr) += m * (gcggb - ggtg + gIgtotg));
(*(here->BSIM4GPdpPtr) += m * (gcgdb - ggtd + gIgtotd));
(*(here->BSIM4GPspPtr) += m * (gcgsb - ggts + gIgtots));
(*(here->BSIM4GPbpPtr) += m * (gcgbb - ggtb + gIgtotb));
{ (*(here->BSIM4GPgpPtr) += mult_q * (gcggb - ggtg) + mult_i * gIgtotg);
(*(here->BSIM4GPdpPtr) += mult_q * (gcgdb - ggtd) + mult_i * gIgtotd);
(*(here->BSIM4GPspPtr) += mult_q * (gcgsb - ggts) + mult_i * gIgtots);
(*(here->BSIM4GPbpPtr) += mult_q * (gcgbb - ggtb) + mult_i * gIgtotb);
}
if (model->BSIM4rdsMod)
{ (*(here->BSIM4DgpPtr) += m * gdtotg);
(*(here->BSIM4DspPtr) += m * gdtots);
(*(here->BSIM4DbpPtr) += m * gdtotb);
(*(here->BSIM4SdpPtr) += m * gstotd);
(*(here->BSIM4SgpPtr) += m * gstotg);
(*(here->BSIM4SbpPtr) += m * gstotb);
{ (*(here->BSIM4DgpPtr) += mult_i * gdtotg);
(*(here->BSIM4DspPtr) += mult_i * gdtots);
(*(here->BSIM4DbpPtr) += mult_i * gdtotb);
(*(here->BSIM4SdpPtr) += mult_i * gstotd);
(*(here->BSIM4SgpPtr) += mult_i * gstotg);
(*(here->BSIM4SbpPtr) += mult_i * gstotb);
}
(*(here->BSIM4DPdpPtr) += m * (gdpr + here->BSIM4gds + here->BSIM4gbd + T1 * ddxpart_dVd
- gdtotd + RevSum + gcddb + gbdpdp + dxpart * ggtd - gIdtotd));
(*(here->BSIM4DPdPtr) -= m * (gdpr + gdtot));
(*(here->BSIM4DPgpPtr) += m * (Gm + gcdgb - gdtotg + gbdpg - gIdtotg
+ dxpart * ggtg + T1 * ddxpart_dVg));
(*(here->BSIM4DPspPtr) -= m * (here->BSIM4gds + gdtots - dxpart * ggts + gIdtots
- T1 * ddxpart_dVs + FwdSum - gcdsb - gbdpsp));
(*(here->BSIM4DPbpPtr) -= m * (gjbd + gdtotb - Gmbs - gcdbb - gbdpb + gIdtotb
- T1 * ddxpart_dVb - dxpart * ggtb));
(*(here->BSIM4DPdpPtr) += mult_i * (gdpr + here->BSIM4gds + here->BSIM4gbd
- gdtotd + RevSum + gbdpdp - gIdtotd) + mult_q * (T1 * ddxpart_dVd + gcddb + dxpart * ggtd));
(*(here->BSIM4DPdPtr) -= mult_i * (gdpr + gdtot));
(*(here->BSIM4DPgpPtr) += mult_i * (Gm - gdtotg + gbdpg - gIdtotg)
+ mult_q * (dxpart * ggtg + T1 * ddxpart_dVg + gcdgb));
(*(here->BSIM4DPspPtr) -= mult_i * (here->BSIM4gds + gdtots + gIdtots
+ FwdSum - gbdpsp) - mult_q * (dxpart * ggts + T1 * ddxpart_dVs + gcdsb));
(*(here->BSIM4DPbpPtr) -= mult_i * (gjbd + gdtotb - Gmbs - gbdpb + gIdtotb)
- mult_q * (dxpart * ggtb + gcdbb + T1 * ddxpart_dVb));
(*(here->BSIM4DdpPtr) -= m * (gdpr - gdtotd));
(*(here->BSIM4DdPtr) += m * (gdpr + gdtot));
(*(here->BSIM4DdpPtr) -= mult_i * (gdpr - gdtotd));
(*(here->BSIM4DdPtr) += mult_i * (gdpr + gdtot));
(*(here->BSIM4SPdpPtr) -= m * (here->BSIM4gds + gstotd + RevSum - gcsdb - gbspdp
- T1 * dsxpart_dVd - sxpart * ggtd + gIstotd));
(*(here->BSIM4SPgpPtr) += m * (gcsgb - Gm - gstotg + gbspg + sxpart * ggtg
+ T1 * dsxpart_dVg - gIstotg));
(*(here->BSIM4SPspPtr) += m * (gspr + here->BSIM4gds + here->BSIM4gbs + T1 * dsxpart_dVs
- gstots + FwdSum + gcssb + gbspsp + sxpart * ggts - gIstots));
(*(here->BSIM4SPsPtr) -= m * (gspr + gstot));
(*(here->BSIM4SPbpPtr) -= m * (gjbs + gstotb + Gmbs - gcsbb - gbspb - sxpart * ggtb
- T1 * dsxpart_dVb + gIstotb));
(*(here->BSIM4SPdpPtr) -= mult_i * (here->BSIM4gds + gstotd + RevSum - gbspdp + gIstotd)
- mult_q * (T1 * dsxpart_dVd + sxpart * ggtd + gcsdb));
(*(here->BSIM4SPgpPtr) += mult_q * (gcsgb + sxpart * ggtg + T1 * dsxpart_dVg) + mult_i * (gbspg - Gm - gstotg - gIstotg));
(*(here->BSIM4SPspPtr) += mult_i * (gspr + here->BSIM4gds + here->BSIM4gbs - gIstots - gstots + FwdSum + gbspsp) + mult_q * (sxpart * ggts + T1 * dsxpart_dVs + gcssb));
(*(here->BSIM4SPsPtr) -= mult_i * (gspr + gstot));
(*(here->BSIM4SPbpPtr) -= mult_i * (gjbs + gstotb + Gmbs - gbspb + gIstotb) - mult_q * (gcsbb + sxpart * ggtb + T1 * dsxpart_dVb));
(*(here->BSIM4SspPtr) -= m * (gspr - gstots));
(*(here->BSIM4SsPtr) += m * (gspr + gstot));
(*(here->BSIM4SspPtr) -= mult_i * (gspr - gstots));
(*(here->BSIM4SsPtr) += mult_i * (gspr + gstot));
(*(here->BSIM4BPdpPtr) += m * (gcbdb - gjbd + gbbdp - gIbtotd));
(*(here->BSIM4BPgpPtr) += m * (gcbgb - here->BSIM4gbgs - gIbtotg));
(*(here->BSIM4BPspPtr) += m * (gcbsb - gjbs + gbbsp - gIbtots));
(*(here->BSIM4BPbpPtr) += m * (gjbd + gjbs + gcbbb - here->BSIM4gbbs
- gIbtotb));
(*(here->BSIM4BPdpPtr) += mult_q * gcbdb - mult_i * (gjbd - gbbdp + gIbtotd));
(*(here->BSIM4BPgpPtr) += mult_q * gcbgb - mult_i * (here->BSIM4gbgs + gIbtotg));
(*(here->BSIM4BPspPtr) += mult_q * gcbsb - mult_i * (gjbs - gbbsp + gIbtots));
(*(here->BSIM4BPbpPtr) += mult_i * (gjbd + gjbs - here->BSIM4gbbs
- gIbtotb) + mult_q * gcbbb);
ggidld = here->BSIM4ggidld;
ggidlg = here->BSIM4ggidlg;
@ -5315,52 +5317,50 @@ line900:
ggislb = here->BSIM4ggislb;
/* stamp gidl */
(*(here->BSIM4DPdpPtr) += m * ggidld);
(*(here->BSIM4DPgpPtr) += m * ggidlg);
(*(here->BSIM4DPspPtr) -= m * (ggidlg + ggidld + ggidlb));
(*(here->BSIM4DPbpPtr) += m * ggidlb);
(*(here->BSIM4BPdpPtr) -= m * ggidld);
(*(here->BSIM4BPgpPtr) -= m * ggidlg);
(*(here->BSIM4BPspPtr) += m * (ggidlg + ggidld + ggidlb));
(*(here->BSIM4BPbpPtr) -= m * ggidlb);
(*(here->BSIM4DPdpPtr) += mult_i * ggidld);
(*(here->BSIM4DPgpPtr) += mult_i * ggidlg);
(*(here->BSIM4DPspPtr) -= mult_i * (ggidlg + ggidld + ggidlb));
(*(here->BSIM4DPbpPtr) += mult_i * ggidlb);
(*(here->BSIM4BPdpPtr) -= mult_i * ggidld);
(*(here->BSIM4BPgpPtr) -= mult_i * ggidlg);
(*(here->BSIM4BPspPtr) += mult_i * (ggidlg + ggidld + ggidlb));
(*(here->BSIM4BPbpPtr) -= mult_i * ggidlb);
/* stamp gisl */
(*(here->BSIM4SPdpPtr) -= m * (ggisls + ggislg + ggislb));
(*(here->BSIM4SPgpPtr) += m * ggislg);
(*(here->BSIM4SPspPtr) += m * ggisls);
(*(here->BSIM4SPbpPtr) += m * ggislb);
(*(here->BSIM4BPdpPtr) += m * (ggislg + ggisls + ggislb));
(*(here->BSIM4BPgpPtr) -= m * ggislg);
(*(here->BSIM4BPspPtr) -= m * ggisls);
(*(here->BSIM4BPbpPtr) -= m * ggislb);
(*(here->BSIM4SPdpPtr) -= mult_i * (ggisls + ggislg + ggislb));
(*(here->BSIM4SPgpPtr) += mult_i * ggislg);
(*(here->BSIM4SPspPtr) += mult_i * ggisls);
(*(here->BSIM4SPbpPtr) += mult_i * ggislb);
(*(here->BSIM4BPdpPtr) += mult_i * (ggislg + ggisls + ggislb));
(*(here->BSIM4BPgpPtr) -= mult_i * ggislg);
(*(here->BSIM4BPspPtr) -= mult_i * ggisls);
(*(here->BSIM4BPbpPtr) -= mult_i * ggislb);
if (here->BSIM4rbodyMod)
{ (*(here->BSIM4DPdbPtr) += m * (gcdbdb - here->BSIM4gbd));
(*(here->BSIM4SPsbPtr) -= m * (here->BSIM4gbs - gcsbsb));
{ (*(here->BSIM4DPdbPtr) += mult_q * gcdbdb - mult_i * here->BSIM4gbd);
(*(here->BSIM4SPsbPtr) -= mult_i * here->BSIM4gbs - mult_q * gcsbsb);
(*(here->BSIM4DBdpPtr) += m * (gcdbdb - here->BSIM4gbd));
(*(here->BSIM4DBdbPtr) += m * (here->BSIM4gbd - gcdbdb
+ here->BSIM4grbpd + here->BSIM4grbdb));
(*(here->BSIM4DBbpPtr) -= m * here->BSIM4grbpd);
(*(here->BSIM4DBbPtr) -= m * here->BSIM4grbdb);
(*(here->BSIM4DBdpPtr) += mult_q * gcdbdb - mult_i * here->BSIM4gbd);
(*(here->BSIM4DBdbPtr) += mult_i * (here->BSIM4gbd + here->BSIM4grbpd + here->BSIM4grbdb) - mult_q * gcdbdb);
(*(here->BSIM4DBbpPtr) -= mult_i * here->BSIM4grbpd);
(*(here->BSIM4DBbPtr) -= mult_i * here->BSIM4grbdb);
(*(here->BSIM4BPdbPtr) -= m * here->BSIM4grbpd);
(*(here->BSIM4BPbPtr) -= m * here->BSIM4grbpb);
(*(here->BSIM4BPsbPtr) -= m * here->BSIM4grbps);
(*(here->BSIM4BPbpPtr) += m * (here->BSIM4grbpd + here->BSIM4grbps
(*(here->BSIM4BPdbPtr) -= mult_i * here->BSIM4grbpd);
(*(here->BSIM4BPbPtr) -= mult_i * here->BSIM4grbpb);
(*(here->BSIM4BPsbPtr) -= mult_i * here->BSIM4grbps);
(*(here->BSIM4BPbpPtr) += mult_i * (here->BSIM4grbpd + here->BSIM4grbps
+ here->BSIM4grbpb));
/* WDLiu: (gcbbb - here->BSIM4gbbs) already added to BPbpPtr */
(*(here->BSIM4SBspPtr) += m * (gcsbsb - here->BSIM4gbs));
(*(here->BSIM4SBbpPtr) -= m * here->BSIM4grbps);
(*(here->BSIM4SBbPtr) -= m * here->BSIM4grbsb);
(*(here->BSIM4SBsbPtr) += m * (here->BSIM4gbs - gcsbsb
+ here->BSIM4grbps + here->BSIM4grbsb));
(*(here->BSIM4SBspPtr) += mult_q * gcsbsb - mult_i * here->BSIM4gbs);
(*(here->BSIM4SBbpPtr) -= mult_i * here->BSIM4grbps);
(*(here->BSIM4SBbPtr) -= mult_i * here->BSIM4grbsb);
(*(here->BSIM4SBsbPtr) += mult_i * (here->BSIM4gbs + here->BSIM4grbps + here->BSIM4grbsb) - mult_q * gcsbsb);
(*(here->BSIM4BdbPtr) -= m * here->BSIM4grbdb);
(*(here->BSIM4BbpPtr) -= m * here->BSIM4grbpb);
(*(here->BSIM4BsbPtr) -= m * here->BSIM4grbsb);
(*(here->BSIM4BbPtr) += m * (here->BSIM4grbsb + here->BSIM4grbdb
(*(here->BSIM4BdbPtr) -= mult_i * here->BSIM4grbdb);
(*(here->BSIM4BbpPtr) -= mult_i * here->BSIM4grbpb);
(*(here->BSIM4BsbPtr) -= mult_i * here->BSIM4grbsb);
(*(here->BSIM4BbPtr) += mult_i * (here->BSIM4grbsb + here->BSIM4grbdb
+ here->BSIM4grbpb));
}
@ -5371,9 +5371,9 @@ line900:
(*(here->BSIM4QspPtr) += m * (ggts - gcqsb));
(*(here->BSIM4QbpPtr) += m * (ggtb - gcqbb));
(*(here->BSIM4DPqPtr) += m * dxpart * here->BSIM4gtau);
(*(here->BSIM4SPqPtr) += m * sxpart * here->BSIM4gtau);
(*(here->BSIM4GPqPtr) -= m * here->BSIM4gtau);
(*(here->BSIM4DPqPtr) += m * (dxpart * here->BSIM4gtau));
(*(here->BSIM4SPqPtr) += m * (sxpart * here->BSIM4gtau));
(*(here->BSIM4GPqPtr) -= m * (here->BSIM4gtau));
}
#endif

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
@ -91,9 +87,6 @@ IFvalue *value)
case BSIM4_MOD_GEOMOD :
value->iValue = model->BSIM4geoMod;
return(OK);
case BSIM4_MOD_RGEOMOD :
value->iValue = model->BSIM4rgeoMod;
return(OK);
case BSIM4_MOD_MTRLMOD :
value->iValue = model->BSIM4mtrlMod;
return(OK);
@ -210,6 +203,9 @@ IFvalue *value)
case BSIM4_MOD_KETA:
value->rValue = model->BSIM4keta;
return(OK);
case BSIM4_MOD_KETAC:
value->rValue = model->BSIM4ketac;
return(OK);
case BSIM4_MOD_NSUB:
value->rValue = model->BSIM4nsub;
return(OK);
@ -957,12 +953,12 @@ IFvalue *value)
case BSIM4_MOD_XGL:
value->rValue = model->BSIM4xgl;
return(OK);
case BSIM4_MOD_RSHG:
value->rValue = model->BSIM4rshg;
return(OK);
case BSIM4_MOD_NGCON:
value->rValue = model->BSIM4ngcon;
return(OK);
case BSIM4_MOD_RSHG:
value->rValue = model->BSIM4rshg;
return(OK);
case BSIM4_MOD_TCJ:
value->rValue = model->BSIM4tcj;
return(OK);
@ -1022,6 +1018,9 @@ IFvalue *value)
case BSIM4_MOD_LKETA:
value->rValue = model->BSIM4lketa;
return(OK);
case BSIM4_MOD_LKETAC:
value->rValue = model->BSIM4lketac;
return(OK);
case BSIM4_MOD_LNSUB:
value->rValue = model->BSIM4lnsub;
return(OK);
@ -1178,6 +1177,9 @@ IFvalue *value)
case BSIM4_MOD_LTVOFFCV: /* v4.7 temp dep of leakage current */
value->rValue = model->BSIM4ltvoffcv;
return(OK);
case BSIM4_MOD_LINTNOI:
value->rValue = model->BSIM4lintnoi;
return(OK);
case BSIM4_MOD_LMINV:
value->rValue = model->BSIM4lminv;
return(OK);
@ -1391,6 +1393,15 @@ IFvalue *value)
case BSIM4_MOD_LXRCRG2:
value->rValue = model->BSIM4lxrcrg2;
return(OK);
case BSIM4_MOD_LLAMBDA:
value->rValue = model->BSIM4llambda;
return(OK);
case BSIM4_MOD_LVTL:
value->rValue = model->BSIM4lvtl;
return(OK);
case BSIM4_MOD_LXN:
value->rValue = model->BSIM4lxn;
return(OK);
case BSIM4_MOD_LEU:
value->rValue = model->BSIM4leu;
return(OK);
@ -1444,16 +1455,6 @@ IFvalue *value)
value->rValue = model->BSIM4ltvfbsdoff;
return(OK);
case BSIM4_MOD_LLAMBDA:
value->rValue = model->BSIM4llambda;
return(OK);
case BSIM4_MOD_LVTL:
value->rValue = model->BSIM4lvtl;
return(OK);
case BSIM4_MOD_LXN:
value->rValue = model->BSIM4lxn;
return(OK);
/* Width dependence */
case BSIM4_MOD_WCDSC :
value->rValue = model->BSIM4wcdsc;
@ -1494,6 +1495,9 @@ IFvalue *value)
case BSIM4_MOD_WKETA:
value->rValue = model->BSIM4wketa;
return(OK);
case BSIM4_MOD_WKETAC:
value->rValue = model->BSIM4wketac;
return(OK);
case BSIM4_MOD_WNSUB:
value->rValue = model->BSIM4wnsub;
return(OK);
@ -1863,6 +1867,15 @@ IFvalue *value)
case BSIM4_MOD_WXRCRG2:
value->rValue = model->BSIM4wxrcrg2;
return(OK);
case BSIM4_MOD_WLAMBDA:
value->rValue = model->BSIM4wlambda;
return(OK);
case BSIM4_MOD_WVTL:
value->rValue = model->BSIM4wvtl;
return(OK);
case BSIM4_MOD_WXN:
value->rValue = model->BSIM4wxn;
return(OK);
case BSIM4_MOD_WEU:
value->rValue = model->BSIM4weu;
return(OK);
@ -1916,16 +1929,6 @@ IFvalue *value)
value->rValue = model->BSIM4wtvfbsdoff;
return(OK);
case BSIM4_MOD_WLAMBDA:
value->rValue = model->BSIM4wlambda;
return(OK);
case BSIM4_MOD_WVTL:
value->rValue = model->BSIM4wvtl;
return(OK);
case BSIM4_MOD_WXN:
value->rValue = model->BSIM4wxn;
return(OK);
/* Cross-term dependence */
case BSIM4_MOD_PCDSC :
value->rValue = model->BSIM4pcdsc;
@ -1966,6 +1969,9 @@ IFvalue *value)
case BSIM4_MOD_PKETA:
value->rValue = model->BSIM4pketa;
return(OK);
case BSIM4_MOD_PKETAC:
value->rValue = model->BSIM4pketac;
return(OK);
case BSIM4_MOD_PNSUB:
value->rValue = model->BSIM4pnsub;
return(OK);
@ -2335,6 +2341,15 @@ IFvalue *value)
case BSIM4_MOD_PXRCRG2:
value->rValue = model->BSIM4pxrcrg2;
return(OK);
case BSIM4_MOD_PLAMBDA:
value->rValue = model->BSIM4plambda;
return(OK);
case BSIM4_MOD_PVTL:
value->rValue = model->BSIM4pvtl;
return(OK);
case BSIM4_MOD_PXN:
value->rValue = model->BSIM4pxn;
return(OK);
case BSIM4_MOD_PEU:
value->rValue = model->BSIM4peu;
return(OK);
@ -2388,16 +2403,6 @@ IFvalue *value)
value->rValue = model->BSIM4ptvfbsdoff;
return(OK);
case BSIM4_MOD_PLAMBDA:
value->rValue = model->BSIM4plambda;
return(OK);
case BSIM4_MOD_PVTL:
value->rValue = model->BSIM4pvtl;
return(OK);
case BSIM4_MOD_PXN:
value->rValue = model->BSIM4pxn;
return(OK);
case BSIM4_MOD_TNOM :
value->rValue = model->BSIM4tnom;
return(OK);
@ -2500,9 +2505,6 @@ IFvalue *value)
case BSIM4_MOD_XTID:
value->rValue = model->BSIM4DjctTempExponent;
return(OK);
case BSIM4_MOD_LINTNOI:
value->rValue = model->BSIM4lintnoi;
return(OK);
case BSIM4_MOD_LINT:
value->rValue = model->BSIM4Lint;
return(OK);

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
@ -93,10 +89,6 @@ GENmodel *inMod)
mod->BSIM4geoMod = value->iValue;
mod->BSIM4geoModGiven = TRUE;
break;
case BSIM4_MOD_RGEOMOD :
mod->BSIM4rgeoMod = value->iValue;
mod->BSIM4rgeoModGiven = TRUE;
break;
case BSIM4_MOD_FNOIMOD :
mod->BSIM4fnoiMod = value->iValue;
mod->BSIM4fnoiModGiven = TRUE;
@ -134,6 +126,14 @@ GENmodel *inMod)
mod->BSIM4version = value->sValue;
mod->BSIM4versionGiven = TRUE;
break;
case BSIM4_MOD_GIDLCLAMP : /* gidlclamp introduced in b4mpar.c */
mod->BSIM4gidlclamp = value->rValue;
mod->BSIM4gidlclampGiven = TRUE;
break;
case BSIM4_MOD_IDOVVDSC : /* idovvdsc introduced in b4mpar.c */
mod->BSIM4idovvdsc = value->rValue;
mod->BSIM4idovvdscGiven = TRUE;
break;
case BSIM4_MOD_TOXREF :
mod->BSIM4toxref = value->rValue;
mod->BSIM4toxrefGiven = TRUE;
@ -186,7 +186,6 @@ GENmodel *inMod)
mod->BSIM4epsrox = value->rValue;
mod->BSIM4epsroxGiven = TRUE;
break;
case BSIM4_MOD_CDSC :
mod->BSIM4cdsc = value->rValue;
mod->BSIM4cdscGiven = TRUE;
@ -195,12 +194,10 @@ GENmodel *inMod)
mod->BSIM4cdscb = value->rValue;
mod->BSIM4cdscbGiven = TRUE;
break;
case BSIM4_MOD_CDSCD :
mod->BSIM4cdscd = value->rValue;
mod->BSIM4cdscdGiven = TRUE;
break;
case BSIM4_MOD_CIT :
mod->BSIM4cit = value->rValue;
mod->BSIM4citGiven = TRUE;
@ -243,6 +240,10 @@ GENmodel *inMod)
mod->BSIM4keta = value->rValue;
mod->BSIM4ketaGiven = TRUE;
break;
case BSIM4_MOD_KETAC:
mod->BSIM4ketac = value->rValue;
mod->BSIM4ketacGiven = TRUE;
break;
case BSIM4_MOD_NSUB:
mod->BSIM4nsub = value->rValue;
mod->BSIM4nsubGiven = TRUE;
@ -288,13 +289,13 @@ GENmodel *inMod)
case BSIM4_MOD_NSD:
mod->BSIM4nsd = value->rValue;
mod->BSIM4nsdGiven = TRUE;
if (mod->BSIM4nsd > 1.000001e24)
if (mod->BSIM4nsd > 1.0e23)
mod->BSIM4nsd *= 1.0e-6;
break;
case BSIM4_MOD_NGATE:
mod->BSIM4ngate = value->rValue;
mod->BSIM4ngateGiven = TRUE;
if (mod->BSIM4ngate > 1.000001e24)
if (mod->BSIM4ngate > 1.0e23)
mod->BSIM4ngate *= 1.0e-6;
break;
case BSIM4_MOD_GAMMA1:
@ -525,8 +526,6 @@ GENmodel *inMod)
mod->BSIM4plp = value->rValue;
mod->BSIM4plpGiven = TRUE;
break;
case BSIM4_MOD_VOFF:
mod->BSIM4voff = value->rValue;
mod->BSIM4voffGiven = TRUE;
@ -1121,6 +1120,7 @@ GENmodel *inMod)
mod->BSIM4jtsswgd = value->rValue;
mod->BSIM4jtsswgdGiven = TRUE;
break;
case BSIM4_MOD_JTWEFF :
mod->BSIM4jtweff = value->rValue;
mod->BSIM4jtweffGiven = TRUE;
@ -1499,8 +1499,6 @@ GENmodel *inMod)
mod->BSIM4lcdsc = value->rValue;
mod->BSIM4lcdscGiven = TRUE;
break;
case BSIM4_MOD_LCDSCB :
mod->BSIM4lcdscb = value->rValue;
mod->BSIM4lcdscbGiven = TRUE;
@ -1551,6 +1549,10 @@ GENmodel *inMod)
mod->BSIM4lketa = value->rValue;
mod->BSIM4lketaGiven = TRUE;
break;
case BSIM4_MOD_LKETAC:
mod->BSIM4lketac = value->rValue;
mod->BSIM4lketacGiven = TRUE;
break;
case BSIM4_MOD_LNSUB:
mod->BSIM4lnsub = value->rValue;
mod->BSIM4lnsubGiven = TRUE;
@ -2171,6 +2173,10 @@ GENmodel *inMod)
mod->BSIM4wketa = value->rValue;
mod->BSIM4wketaGiven = TRUE;
break;
case BSIM4_MOD_WKETAC:
mod->BSIM4wketac = value->rValue;
mod->BSIM4wketacGiven = TRUE;
break;
case BSIM4_MOD_WNSUB:
mod->BSIM4wnsub = value->rValue;
mod->BSIM4wnsubGiven = TRUE;
@ -2791,6 +2797,10 @@ GENmodel *inMod)
mod->BSIM4pketa = value->rValue;
mod->BSIM4pketaGiven = TRUE;
break;
case BSIM4_MOD_PKETAC:
mod->BSIM4pketac = value->rValue;
mod->BSIM4pketacGiven = TRUE;
break;
case BSIM4_MOD_PNSUB:
mod->BSIM4pnsub = value->rValue;
mod->BSIM4pnsubGiven = TRUE;
@ -3608,15 +3618,6 @@ GENmodel *inMod)
mod->BSIM4kfGiven = TRUE;
break;
case BSIM4_MOD_GIDLCLAMP:
mod->BSIM4gidlclamp = value->rValue;
mod->BSIM4gidlclampGiven = TRUE;
break;
case BSIM4_MOD_IDOVVDSC:
mod->BSIM4idovvdsc = value->rValue;
mod->BSIM4idovvdscGiven = TRUE;
break;
case BSIM4_MOD_VGS_MAX:
mod->BSIM4vgsMax = value->rValue;
mod->BSIM4vgsMaxGiven = TRUE;
@ -3681,3 +3682,4 @@ GENmodel *inMod)
}

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
@ -50,7 +46,7 @@ double freq, double temp)
{
struct bsim4SizeDependParam *pParam;
double cd, esat, DelClm, EffFreq, N0, Nl, Leff, Leffsq;
double T0=0.0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi;
double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi;
pParam = here->pParam;
cd = fabs(here->BSIM4cd);
@ -85,7 +81,6 @@ double T0=0.0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi;
return Ssi;
}
int
BSIM4noise (
int mode, int operation,
@ -94,8 +89,6 @@ CKTcircuit *ckt,
Ndata *data,
double *OnDens)
{
NOISEAN *job = (NOISEAN *) ckt->CKTcurJob;
BSIM4model *model = (BSIM4model *)inModel;
BSIM4instance *here;
struct bsim4SizeDependParam *pParam;
@ -113,8 +106,7 @@ double eta, Leff, Lvsat, gamma, delta, epsilon, GammaGd0=0.0;
double npart_c, sigrat=0.0, C0, omega, ctnoi=0.0;
int i;
double m;
double mult_i, mult_fn;
/* define the names of the noise sources */
static char *BSIM4nNames[BSIM4NSRCS] =
@ -138,10 +130,6 @@ double m;
for (; model != NULL; model = BSIM4nextModel(model))
{
if(model->BSIM4tnoiMod != 2) {
noizDens[BSIM4CORLNOIZ] = 0.0;
lnNdens[BSIM4CORLNOIZ] = N_MINLOG;
}
for (here = BSIM4instances(model); here != NULL;
here = BSIM4nextInstance(here))
{ pParam = here->pParam;
@ -150,7 +138,7 @@ double m;
/* see if we have to to produce a summary report */
/* if so, name all the noise generators */
if (job->NStpsSm != 0)
if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0)
{ switch (mode)
{ case N_DENS:
for (i = 0; i < BSIM4NSRCS; i++)
@ -167,7 +155,8 @@ double m;
}
break;
case N_CALC:
m = here->BSIM4m;
mult_i = here->BSIM4mult_i;
mult_fn = here->BSIM4mult_fn;
switch (mode)
{ case N_DENS:
if (model->BSIM4tnoiMod == 0)
@ -230,19 +219,19 @@ double m;
NevalSrc(&noizDens[BSIM4RDNOIZ],
&lnNdens[BSIM4RDNOIZ], ckt, THERMNOISE,
here->BSIM4dNodePrime, here->BSIM4dNode,
gdpr * m);
gdpr * mult_i);
NevalSrc(&noizDens[BSIM4RSNOIZ],
&lnNdens[BSIM4RSNOIZ], ckt, THERMNOISE,
here->BSIM4sNodePrime, here->BSIM4sNode,
gspr * m);
gspr * mult_i);
if (here->BSIM4rgateMod == 1)
{ NevalSrc(&noizDens[BSIM4RGNOIZ],
&lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE,
here->BSIM4gNodePrime, here->BSIM4gNodeExt,
here->BSIM4grgeltd * m);
here->BSIM4grgeltd * mult_i);
}
else if (here->BSIM4rgateMod == 2)
{
@ -251,13 +240,13 @@ double m;
NevalSrc(&noizDens[BSIM4RGNOIZ],
&lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE,
here->BSIM4gNodePrime, here->BSIM4gNodeExt,
here->BSIM4grgeltd * m / T1);
here->BSIM4grgeltd * mult_i/T1);
}
else if (here->BSIM4rgateMod == 3)
{ NevalSrc(&noizDens[BSIM4RGNOIZ],
&lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE,
here->BSIM4gNodeMid, here->BSIM4gNodeExt,
here->BSIM4grgeltd * m);
here->BSIM4grgeltd * mult_i);
}
else
{ noizDens[BSIM4RGNOIZ] = 0.0;
@ -283,38 +272,38 @@ double m;
NevalSrc(&noizDens[BSIM4RBPSNOIZ],
&lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE,
here->BSIM4bNodePrime, here->BSIM4sbNode,
here->BSIM4grbps * m);
here->BSIM4grbps * mult_i);
NevalSrc(&noizDens[BSIM4RBPDNOIZ],
&lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE,
here->BSIM4bNodePrime, here->BSIM4dbNode,
here->BSIM4grbpd * m);
here->BSIM4grbpd * mult_i);
NevalSrc(&noizDens[BSIM4RBPBNOIZ],
&lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE,
here->BSIM4bNodePrime, here->BSIM4bNode,
here->BSIM4grbpb * m);
here->BSIM4grbpb * mult_i);
NevalSrc(&noizDens[BSIM4RBSBNOIZ],
&lnNdens[BSIM4RBSBNOIZ], ckt, THERMNOISE,
here->BSIM4bNode, here->BSIM4sbNode,
here->BSIM4grbsb * m);
here->BSIM4grbsb * mult_i);
NevalSrc(&noizDens[BSIM4RBDBNOIZ],
&lnNdens[BSIM4RBDBNOIZ], ckt, THERMNOISE,
here->BSIM4bNode, here->BSIM4dbNode,
here->BSIM4grbdb * m);
here->BSIM4grbdb * mult_i);
}
if(bodymode == 3)
{
NevalSrc(&noizDens[BSIM4RBPSNOIZ],
&lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE,
here->BSIM4bNodePrime, here->BSIM4sbNode,
here->BSIM4grbps * m);
here->BSIM4grbps * mult_i);
NevalSrc(&noizDens[BSIM4RBPDNOIZ],
&lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE,
here->BSIM4bNodePrime, here->BSIM4dbNode,
here->BSIM4grbpd * m);
here->BSIM4grbpd * mult_i);
NevalSrc(&noizDens[BSIM4RBPBNOIZ],
&lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE,
here->BSIM4bNodePrime, here->BSIM4bNode,
here->BSIM4grbpb * m);
here->BSIM4grbpb * mult_i);
noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0;
lnNdens[BSIM4RBSBNOIZ] =
log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG));
@ -326,7 +315,7 @@ double m;
NevalSrc(&noizDens[BSIM4RBPBNOIZ],
&lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE,
here->BSIM4bNodePrime, here->BSIM4bNode,
here->BSIM4grbpb * m);
here->BSIM4grbpb * mult_i);
noizDens[BSIM4RBPSNOIZ] = noizDens[BSIM4RBPDNOIZ] = 0.0;
noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0;
lnNdens[BSIM4RBPSNOIZ] =
@ -375,10 +364,12 @@ double m;
delta = (T1 / T3 - (5.0 * T1 + T2) * T4 / (15.0 * T5) + T4 * T4 / (9.0 * T5 * T2)) / (6.0 * T6 * T6 * T6);
T7 = T0 / T2;
epsilon = (T7 - T7 * T7 * T7 / 3.0) / (6.0 * T6);
T8 = here->BSIM4Vgsteff / here->BSIM4EsatL;
T8 *= T8;
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4))) {
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) &&
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) &&
(strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4)))
{
npart_c = model->BSIM4rnoic * (1.0 + T8
* model->BSIM4tnoic * Leff);
ctnoi = epsilon / sqrt(gamma * delta)
@ -397,8 +388,7 @@ double m;
sigrat = T0 * sqrt(delta / gamma);
}
else
{
npart_c = model->BSIM4rnoic * (1.0 + T8
{npart_c = model->BSIM4rnoic * (1.0 + T8
* model->BSIM4tnoic * Leff);
/* Limits added for rnoia, rnoib, rnoic, tnoia, tnoib and tnoic in BSIM4.8.1 */
T9 = gamma * delta ;
@ -428,10 +418,12 @@ double m;
sigrat = 0.0;
}
}
switch(model->BSIM4tnoiMod)
{ case 0:
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4))) {
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) &&
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) &&
(strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4)))
{
T0 = here->BSIM4ueff * fabs(here->BSIM4qinv);
T1 = T0 * tmp + pParam->BSIM4leff
* pParam->BSIM4leff;
@ -439,7 +431,7 @@ double m;
&lnNdens[BSIM4IDNOIZ], ckt,
THERMNOISE, here->BSIM4dNodePrime,
here->BSIM4sNodePrime,
(T0 / T1) * model->BSIM4ntnoi * m);
(T0 / T1) * model->BSIM4ntnoi * mult_i);
}
else
{
@ -450,14 +442,17 @@ double m;
&lnNdens[BSIM4IDNOIZ], ckt,
THERMNOISE, here->BSIM4dNodePrime,
here->BSIM4sNodePrime,
(T0 / T1) * model->BSIM4ntnoi * m);
(T0 / T1) * model->BSIM4ntnoi * mult_i);
noizDens[BSIM4CORLNOIZ] = 0.0;
lnNdens[BSIM4CORLNOIZ] = log(MAX(noizDens[BSIM4CORLNOIZ], N_MINLOG));
}
break;
case 1:
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4))) {
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) && (strncmp(model->BSIM4version, "4.8", 3)) &&
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) &&
(strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4)))
{
T0 = here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds;
T0 *= T0;
igsquare = npart_theta * npart_theta * T0 / here->BSIM4IdovVds;
@ -467,7 +462,7 @@ double m;
NevalSrc(&noizDens[BSIM4IDNOIZ],
&lnNdens[BSIM4IDNOIZ], ckt,
THERMNOISE, here->BSIM4dNodePrime,
here->BSIM4sNodePrime, (T2 - igsquare) * m);
here->BSIM4sNodePrime, (T2 - igsquare) * mult_i);
}
else
{
@ -480,7 +475,7 @@ double m;
NevalSrc(&noizDens[BSIM4IDNOIZ],
&lnNdens[BSIM4IDNOIZ], ckt,
THERMNOISE, here->BSIM4dNodePrime,
here->BSIM4sNodePrime, (T2 - igsquare) * m);
here->BSIM4sNodePrime, (T2 - igsquare) * mult_i);
noizDens[BSIM4CORLNOIZ] = 0.0;
lnNdens[BSIM4CORLNOIZ] = log(MAX(noizDens[BSIM4CORLNOIZ], N_MINLOG));
@ -493,7 +488,7 @@ double m;
NevalSrc(&noizDens[BSIM4IDNOIZ],
&lnNdens[BSIM4IDNOIZ], ckt,
THERMNOISE, here->BSIM4dNodePrime,
here->BSIM4sNodePrime, T2 * T4 * m);
here->BSIM4sNodePrime, T2 * T4 * mult_i);
/* Evaluate output noise due to two correlated noise sources */
omega = 2.0 * M_PI * data->freq;
@ -505,20 +500,20 @@ double m;
NevalSrc2(&noizDens[BSIM4CORLNOIZ],
&lnNdens[BSIM4CORLNOIZ], ckt,
THERMNOISE, here->BSIM4dNodePrime,
here->BSIM4sNodePrime, T2 * T3 * m,
here->BSIM4sNodePrime, T2 * T3 * mult_i,
here->BSIM4gNodePrime,
here->BSIM4sNodePrime,
T2 * T7 * m, 0.5 * M_PI);
T2 * T7 * mult_i, 0.5 * M_PI);
}
else
{
NevalSrc2(&noizDens[BSIM4CORLNOIZ],
&lnNdens[BSIM4CORLNOIZ], ckt,
THERMNOISE, here->BSIM4sNodePrime,
here->BSIM4dNodePrime, T2 * T3 * m,
here->BSIM4dNodePrime, T2 * T3 * mult_i,
here->BSIM4gNodePrime,
here->BSIM4dNodePrime,
T2 * T7 * m, 0.5 * M_PI);
T2 * T7 * mult_i, 0.5 * M_PI);
}
break;
}
@ -529,7 +524,7 @@ double m;
switch(model->BSIM4fnoiMod)
{ case 0:
noizDens[BSIM4FLNOIZ] *= m * model->BSIM4kf
noizDens[BSIM4FLNOIZ] *= mult_fn * model->BSIM4kf
* exp(model->BSIM4af
* log(MAX(fabs(here->BSIM4cd),
N_MINLOG)))
@ -554,7 +549,7 @@ double m;
* here->BSIM4cd;
T1 = Swi + Ssi;
if (T1 > 0.0)
noizDens[BSIM4FLNOIZ] *= m * (Ssi * Swi) / T1;
noizDens[BSIM4FLNOIZ] *= mult_fn * (Ssi * Swi) / T1;
else
noizDens[BSIM4FLNOIZ] *= 0.0;
break;
@ -568,25 +563,25 @@ double m;
NevalSrc(&noizDens[BSIM4IGSNOIZ],
&lnNdens[BSIM4IGSNOIZ], ckt, SHOTNOISE,
here->BSIM4gNodePrime, here->BSIM4sNodePrime,
m * (here->BSIM4Igs + here->BSIM4Igcs));
mult_i * (here->BSIM4Igs + here->BSIM4Igcs));
NevalSrc(&noizDens[BSIM4IGDNOIZ],
&lnNdens[BSIM4IGDNOIZ], ckt, SHOTNOISE,
here->BSIM4gNodePrime, here->BSIM4dNodePrime,
m * (here->BSIM4Igd + here->BSIM4Igcd));
mult_i * (here->BSIM4Igd + here->BSIM4Igcd));
} else {
NevalSrc(&noizDens[BSIM4IGSNOIZ],
&lnNdens[BSIM4IGSNOIZ], ckt, SHOTNOISE,
here->BSIM4gNodePrime, here->BSIM4sNodePrime,
m * (here->BSIM4Igs + here->BSIM4Igcd));
mult_i * (here->BSIM4Igs + here->BSIM4Igcd));
NevalSrc(&noizDens[BSIM4IGDNOIZ],
&lnNdens[BSIM4IGDNOIZ], ckt, SHOTNOISE,
here->BSIM4gNodePrime, here->BSIM4dNodePrime,
m * (here->BSIM4Igd + here->BSIM4Igcs));
mult_i * (here->BSIM4Igd + here->BSIM4Igcs));
}
NevalSrc(&noizDens[BSIM4IGBNOIZ],
&lnNdens[BSIM4IGBNOIZ], ckt, SHOTNOISE,
here->BSIM4gNodePrime, here->BSIM4bNodePrime,
m * here->BSIM4Igb);
mult_i * here->BSIM4Igb);
noizDens[BSIM4TOTNOIZ] = noizDens[BSIM4RDNOIZ]
@ -617,7 +612,7 @@ double m;
if it's the first pass
*/
if (data->freq ==
job->NstartFreq)
((NOISEAN*) ckt->CKTcurJob)->NstartFreq)
{ for (i = 0; i < BSIM4NSRCS; i++)
{ here->BSIM4nVar[OUTNOIZ][i] = 0.0;
here->BSIM4nVar[INNOIZ][i] = 0.0;
@ -643,7 +638,8 @@ double m;
lnNdens[i];
data->outNoiz += tempOnoise;
data->inNoise += tempInoise;
if (job->NStpsSm != 0)
if (((NOISEAN*)
ckt->CKTcurJob)->NStpsSm != 0)
{ here->BSIM4nVar[OUTNOIZ][i]
+= tempOnoise;
here->BSIM4nVar[OUTNOIZ][BSIM4TOTNOIZ]
@ -666,7 +662,7 @@ double m;
break;
case INT_NOIZ:
/* already calculated, just output */
if (job->NStpsSm != 0)
if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0)
{ for (i = 0; i < BSIM4NSRCS; i++)
{ data->outpVector[data->outNumber++]
= here->BSIM4nVar[OUTNOIZ][i];

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
@ -49,8 +45,8 @@ IFvalue *select)
if (!cp_getvar("scale", CP_REAL, &scale, 0))
scale = 1;
switch (param) {
case BSIM4_W:
switch(param)
{ case BSIM4_W:
here->BSIM4w = value->rValue * scale;
here->BSIM4wGiven = TRUE;
break;
@ -62,6 +58,18 @@ IFvalue *select)
here->BSIM4m = value->rValue;
here->BSIM4mGiven = TRUE;
break;
case BSIM4_MULT_I:
here->BSIM4mult_i = value->rValue;
here->BSIM4mult_iGiven = TRUE;
break;
case BSIM4_MULT_Q:
here->BSIM4mult_q = value->rValue;
here->BSIM4mult_qGiven = TRUE;
break;
case BSIM4_MULT_FN:
here->BSIM4mult_fn = value->rValue;
here->BSIM4mult_fnGiven = TRUE;
break;
case BSIM4_NF:
here->BSIM4nf = value->rValue;
here->BSIM4nfGiven = TRUE;
@ -149,14 +157,6 @@ IFvalue *select)
here->BSIM4delvto = value->rValue;
here->BSIM4delvtoGiven = TRUE;
break;
case BSIM4_MULU0:
here->BSIM4mulu0 = value->rValue;
here->BSIM4mulu0Given = TRUE;
break;
case BSIM4_WNFLAG:
here->BSIM4wnflag = value->iValue;
here->BSIM4wnflagGiven = TRUE;
break;
case BSIM4_XGW:
here->BSIM4xgw = value->rValue;
here->BSIM4xgwGiven = TRUE;
@ -204,8 +204,8 @@ IFvalue *select)
case BSIM4_IC:
/* FALLTHROUGH added to suppress GCC warning due to
* -Wimplicit-fallthrough flag */
switch (value->v.numValue) {
case 3:
switch(value->v.numValue)
{ case 3:
here->BSIM4icVBS = *(value->v.vec.rVec+2);
here->BSIM4icVBSGiven = TRUE;
/* FALLTHROUGH */

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,8 +17,10 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
*/
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/complex.h"
@ -64,14 +59,12 @@ double T0=0.0, T1, CoxWL, qcheq, Cdg, Cdd, Cds, Csg, Csd, Css;
double ScalingFactor = 1.0e-9;
struct bsim4SizeDependParam *pParam;
double ggidld, ggidlg, ggidlb, ggislg, ggislb, ggisls;
double m;
double m, mult_i, mult_q;
for (; model != NULL; model = BSIM4nextModel(model))
{ for (here = BSIM4instances(model); here!= NULL;
here = BSIM4nextInstance(here))
{
pParam = here->pParam;
{ pParam = here->pParam;
capbd = here->BSIM4capbd;
capbs = here->BSIM4capbs;
cgso = here->BSIM4cgso;
@ -501,6 +494,8 @@ double m;
* Loading PZ matrix
*/
m = here->BSIM4m;
mult_i = here->BSIM4mult_i;
mult_q = here->BSIM4mult_q;
if (!model->BSIM4rdsMod)
{ gdpr = here->BSIM4drainConductance;
@ -519,164 +514,164 @@ double m;
geltd = here->BSIM4grgeltd;
if (here->BSIM4rgateMod == 1)
{ *(here->BSIM4GEgePtr) += m * geltd;
*(here->BSIM4GPgePtr) -= m * geltd;
*(here->BSIM4GEgpPtr) -= m * geltd;
{ *(here->BSIM4GEgePtr) += mult_i * geltd;
*(here->BSIM4GPgePtr) -= mult_i * geltd;
*(here->BSIM4GEgpPtr) -= mult_i * geltd;
*(here->BSIM4GPgpPtr ) += m * xcggb * s->real;
*(here->BSIM4GPgpPtr +1) += m * xcggb * s->imag;
*(here->BSIM4GPgpPtr) += m * (geltd - xgtg + gIgtotg);
*(here->BSIM4GPdpPtr ) += m * xcgdb * s->real;
*(here->BSIM4GPdpPtr +1) += m * xcgdb * s->imag;
*(here->BSIM4GPdpPtr) -= m * (xgtd - gIgtotd);
*(here->BSIM4GPspPtr ) += m * xcgsb * s->real;
*(here->BSIM4GPspPtr +1) += m * xcgsb * s->imag;
*(here->BSIM4GPspPtr) -= m * (xgts - gIgtots);
*(here->BSIM4GPbpPtr ) += m * xcgbb * s->real;
*(here->BSIM4GPbpPtr +1) += m * xcgbb * s->imag;
*(here->BSIM4GPbpPtr) -= m * (xgtb - gIgtotb);
*(here->BSIM4GPgpPtr ) += mult_q * xcggb * s->real;
*(here->BSIM4GPgpPtr +1) += mult_q * xcggb * s->imag;
*(here->BSIM4GPgpPtr) += mult_i * (geltd + gIgtotg) - mult_q * xgtg;
*(here->BSIM4GPdpPtr ) += mult_q * xcgdb * s->real;
*(here->BSIM4GPdpPtr +1) += mult_q * xcgdb * s->imag;
*(here->BSIM4GPdpPtr) -= mult_q * xgtd - mult_i * gIgtotd;
*(here->BSIM4GPspPtr ) += mult_q * xcgsb * s->real;
*(here->BSIM4GPspPtr +1) += mult_q * xcgsb * s->imag;
*(here->BSIM4GPspPtr) -= mult_q * xgts - mult_i * gIgtots;
*(here->BSIM4GPbpPtr ) += mult_q * xcgbb * s->real;
*(here->BSIM4GPbpPtr +1) += mult_q * xcgbb * s->imag;
*(here->BSIM4GPbpPtr) -= mult_q * xgtb - mult_i * gIgtotb;
}
else if (here->BSIM4rgateMod == 2)
{ *(here->BSIM4GEgePtr) += m * gcrg;
*(here->BSIM4GEgpPtr) += m * gcrgg;
*(here->BSIM4GEdpPtr) += m * gcrgd;
*(here->BSIM4GEspPtr) += m * gcrgs;
*(here->BSIM4GEbpPtr) += m * gcrgb;
{ *(here->BSIM4GEgePtr) += mult_i * gcrg;
*(here->BSIM4GEgpPtr) += mult_i * gcrgg;
*(here->BSIM4GEdpPtr) += mult_i * gcrgd;
*(here->BSIM4GEspPtr) += mult_i * gcrgs;
*(here->BSIM4GEbpPtr) += mult_i * gcrgb;
*(here->BSIM4GPgePtr) -= m * gcrg;
*(here->BSIM4GPgpPtr ) += m * xcggb * s->real;
*(here->BSIM4GPgpPtr +1) += m * xcggb * s->imag;
*(here->BSIM4GPgpPtr) -= m * (gcrgg + xgtg - gIgtotg);
*(here->BSIM4GPdpPtr ) += m * xcgdb * s->real;
*(here->BSIM4GPdpPtr +1) += m * xcgdb * s->imag;
*(here->BSIM4GPdpPtr) -= m * (gcrgd + xgtd - gIgtotd);
*(here->BSIM4GPspPtr ) += m * xcgsb * s->real;
*(here->BSIM4GPspPtr +1) += m * xcgsb * s->imag;
*(here->BSIM4GPspPtr) -= m * (gcrgs + xgts - gIgtots);
*(here->BSIM4GPbpPtr ) += m * xcgbb * s->real;
*(here->BSIM4GPbpPtr +1) += m * xcgbb * s->imag;
*(here->BSIM4GPbpPtr) -= m * (gcrgb + xgtb - gIgtotb);
*(here->BSIM4GPgePtr) -= mult_i * gcrg;
*(here->BSIM4GPgpPtr ) += mult_q * xcggb * s->real;
*(here->BSIM4GPgpPtr +1) += mult_q * xcggb * s->imag;
*(here->BSIM4GPgpPtr) -= mult_i * (gcrgg - gIgtotg) + mult_q * xgtg;
*(here->BSIM4GPdpPtr ) += mult_q * xcgdb * s->real;
*(here->BSIM4GPdpPtr +1) += mult_q * xcgdb * s->imag;
*(here->BSIM4GPdpPtr) -= mult_i * (gcrgd - gIgtotd) + mult_q * xgtd;
*(here->BSIM4GPspPtr ) += mult_q * xcgsb * s->real;
*(here->BSIM4GPspPtr +1) += mult_q * xcgsb * s->imag;
*(here->BSIM4GPspPtr) -= mult_i * (gcrgs - gIgtots) + mult_q * xgts;
*(here->BSIM4GPbpPtr ) += mult_q * xcgbb * s->real;
*(here->BSIM4GPbpPtr +1) += mult_q * xcgbb * s->imag;
*(here->BSIM4GPbpPtr) -= mult_i * (gcrgb - gIgtotb) + mult_q * xgtb;
}
else if (here->BSIM4rgateMod == 3)
{ *(here->BSIM4GEgePtr) += m * geltd;
*(here->BSIM4GEgmPtr) -= m * geltd;
*(here->BSIM4GMgePtr) -= m * geltd;
*(here->BSIM4GMgmPtr) += m * (geltd + gcrg);
*(here->BSIM4GMgmPtr ) += m * xcgmgmb * s->real;
*(here->BSIM4GMgmPtr +1) += m * xcgmgmb * s->imag;
{ *(here->BSIM4GEgePtr) += mult_i * geltd;
*(here->BSIM4GEgmPtr) -= mult_i * geltd;
*(here->BSIM4GMgePtr) -= mult_i * geltd;
*(here->BSIM4GMgmPtr) += mult_i * (geltd + gcrg);
*(here->BSIM4GMgmPtr ) += mult_q * xcgmgmb * s->real;
*(here->BSIM4GMgmPtr +1) += mult_q * xcgmgmb * s->imag;
*(here->BSIM4GMdpPtr) += m * gcrgd;
*(here->BSIM4GMdpPtr ) += m * xcgmdb * s->real;
*(here->BSIM4GMdpPtr +1) += m * xcgmdb * s->imag;
*(here->BSIM4GMgpPtr) += m * gcrgg;
*(here->BSIM4GMspPtr) += m * gcrgs;
*(here->BSIM4GMspPtr ) += m * xcgmsb * s->real;
*(here->BSIM4GMspPtr +1) += m * xcgmsb * s->imag;
*(here->BSIM4GMbpPtr) += m * gcrgb;
*(here->BSIM4GMbpPtr ) += m * xcgmbb * s->real;
*(here->BSIM4GMbpPtr +1) += m * xcgmbb * s->imag;
*(here->BSIM4GMdpPtr) += mult_i * gcrgd;
*(here->BSIM4GMdpPtr ) += mult_q * xcgmdb * s->real;
*(here->BSIM4GMdpPtr +1) += mult_q * xcgmdb * s->imag;
*(here->BSIM4GMgpPtr) += mult_i * gcrgg;
*(here->BSIM4GMspPtr) += mult_i * gcrgs;
*(here->BSIM4GMspPtr ) += mult_q * xcgmsb * s->real;
*(here->BSIM4GMspPtr +1) += mult_q * xcgmsb * s->imag;
*(here->BSIM4GMbpPtr) += mult_i * gcrgb;
*(here->BSIM4GMbpPtr ) += mult_q * xcgmbb * s->real;
*(here->BSIM4GMbpPtr +1) += mult_q * xcgmbb * s->imag;
*(here->BSIM4DPgmPtr ) += m * xcdgmb * s->real;
*(here->BSIM4DPgmPtr +1) += m * xcdgmb * s->imag;
*(here->BSIM4GPgmPtr) -= m * gcrg;
*(here->BSIM4SPgmPtr ) += m * xcsgmb * s->real;
*(here->BSIM4SPgmPtr +1) += m * xcsgmb * s->imag;
*(here->BSIM4BPgmPtr ) += m * xcbgmb * s->real;
*(here->BSIM4BPgmPtr +1) += m * xcbgmb * s->imag;
*(here->BSIM4DPgmPtr ) += mult_q * xcdgmb * s->real;
*(here->BSIM4DPgmPtr +1) += mult_q * xcdgmb * s->imag;
*(here->BSIM4GPgmPtr) -= mult_i * gcrg;
*(here->BSIM4SPgmPtr ) += mult_q * xcsgmb * s->real;
*(here->BSIM4SPgmPtr +1) += mult_q * xcsgmb * s->imag;
*(here->BSIM4BPgmPtr ) += mult_q * xcbgmb * s->real;
*(here->BSIM4BPgmPtr +1) += mult_q * xcbgmb * s->imag;
*(here->BSIM4GPgpPtr) -= m * (gcrgg + xgtg - gIgtotg);
*(here->BSIM4GPgpPtr ) += m * xcggb * s->real;
*(here->BSIM4GPgpPtr +1) += m * xcggb * s->imag;
*(here->BSIM4GPdpPtr) -= m * (gcrgd + xgtd - gIgtotd);
*(here->BSIM4GPdpPtr ) += m * xcgdb * s->real;
*(here->BSIM4GPdpPtr +1) += m * xcgdb * s->imag;
*(here->BSIM4GPspPtr) -= m * (gcrgs + xgts - gIgtots);
*(here->BSIM4GPspPtr ) += m * xcgsb * s->real;
*(here->BSIM4GPspPtr +1) += m * xcgsb * s->imag;
*(here->BSIM4GPbpPtr) -= m * (gcrgb + xgtb - gIgtotb);
*(here->BSIM4GPbpPtr ) += m * xcgbb * s->real;
*(here->BSIM4GPbpPtr +1) += m * xcgbb * s->imag;
*(here->BSIM4GPgpPtr) -= mult_i * (gcrgg - gIgtotg) + mult_q * xgtg;
*(here->BSIM4GPgpPtr ) += mult_q * xcggb * s->real;
*(here->BSIM4GPgpPtr +1) += mult_q * xcggb * s->imag;
*(here->BSIM4GPdpPtr) -= mult_i * (gcrgd - gIgtotd) + mult_q * xgtd;
*(here->BSIM4GPdpPtr ) += mult_q * xcgdb * s->real;
*(here->BSIM4GPdpPtr +1) += mult_q * xcgdb * s->imag;
*(here->BSIM4GPspPtr) -= mult_i * (gcrgs - gIgtots) + mult_q * xgts;
*(here->BSIM4GPspPtr ) += mult_q * xcgsb * s->real;
*(here->BSIM4GPspPtr +1) += mult_q * xcgsb * s->imag;
*(here->BSIM4GPbpPtr) -= mult_i * (gcrgb - gIgtotb) + mult_q * xgtb;
*(here->BSIM4GPbpPtr ) += mult_q * xcgbb * s->real;
*(here->BSIM4GPbpPtr +1) += mult_q * xcgbb * s->imag;
}
else
{ *(here->BSIM4GPdpPtr ) += m * xcgdb * s->real;
*(here->BSIM4GPdpPtr +1) += m * xcgdb * s->imag;
*(here->BSIM4GPdpPtr) -= m * (xgtd - gIgtotd);
*(here->BSIM4GPgpPtr ) += m * xcggb * s->real;
*(here->BSIM4GPgpPtr +1) += m * xcggb * s->imag;
*(here->BSIM4GPgpPtr) -= m * (xgtg - gIgtotg);
*(here->BSIM4GPspPtr ) += m * xcgsb * s->real;
*(here->BSIM4GPspPtr +1) += m * xcgsb * s->imag;
*(here->BSIM4GPspPtr) -= m * (xgts - gIgtots);
*(here->BSIM4GPbpPtr ) += m * xcgbb * s->real;
*(here->BSIM4GPbpPtr +1) += m * xcgbb * s->imag;
*(here->BSIM4GPbpPtr) -= m * (xgtb - gIgtotb);
{ *(here->BSIM4GPdpPtr ) += mult_q * xcgdb * s->real;
*(here->BSIM4GPdpPtr +1) += mult_q * xcgdb * s->imag;
*(here->BSIM4GPdpPtr) -= mult_q * xgtd - mult_i * gIgtotd;
*(here->BSIM4GPgpPtr ) += mult_q * xcggb * s->real;
*(here->BSIM4GPgpPtr +1) += mult_q * xcggb * s->imag;
*(here->BSIM4GPgpPtr) -= mult_q * xgtg - mult_i * gIgtotg;
*(here->BSIM4GPspPtr ) += mult_q * xcgsb * s->real;
*(here->BSIM4GPspPtr +1) += mult_q * xcgsb * s->imag;
*(here->BSIM4GPspPtr) -= mult_q * xgts - mult_i * gIgtots;
*(here->BSIM4GPbpPtr ) += mult_q * xcgbb * s->real;
*(here->BSIM4GPbpPtr +1) += mult_q * xcgbb * s->imag;
*(here->BSIM4GPbpPtr) -= mult_q * xgtb - mult_i * gIgtotb;
}
if (model->BSIM4rdsMod)
{ (*(here->BSIM4DgpPtr) += m * gdtotg);
(*(here->BSIM4DspPtr) += m * gdtots);
(*(here->BSIM4DbpPtr) += m * gdtotb);
(*(here->BSIM4SdpPtr) += m * gstotd);
(*(here->BSIM4SgpPtr) += m * gstotg);
(*(here->BSIM4SbpPtr) += m * gstotb);
{ (*(here->BSIM4DgpPtr) += mult_i * gdtotg);
(*(here->BSIM4DspPtr) += mult_i * gdtots);
(*(here->BSIM4DbpPtr) += mult_i * gdtotb);
(*(here->BSIM4SdpPtr) += mult_i * gstotd);
(*(here->BSIM4SgpPtr) += mult_i * gstotg);
(*(here->BSIM4SbpPtr) += mult_i * gstotb);
}
*(here->BSIM4DPdpPtr ) += m * xcddb * s->real;
*(here->BSIM4DPdpPtr +1) += m * xcddb * s->imag;
*(here->BSIM4DPdpPtr) += m * (gdpr + gds + here->BSIM4gbd
- gdtotd + RevSum + gbdpdp - gIdtotd
+ dxpart * xgtd + T1 * ddxpart_dVd);
*(here->BSIM4DPdPtr) -= m * (gdpr + gdtot);
*(here->BSIM4DPgpPtr ) += m * xcdgb * s->real;
*(here->BSIM4DPgpPtr +1) += m * xcdgb * s->imag;
*(here->BSIM4DPgpPtr) += m * (Gm - gdtotg + gbdpg - gIdtotg
+ T1 * ddxpart_dVg + dxpart * xgtg);
*(here->BSIM4DPspPtr ) += m * xcdsb * s->real;
*(here->BSIM4DPspPtr +1) += m * xcdsb * s->imag;
*(here->BSIM4DPspPtr) -= m * (gds + FwdSum + gdtots - gbdpsp + gIdtots
- T1 * ddxpart_dVs - dxpart * xgts);
*(here->BSIM4DPbpPtr ) += m * xcdbb * s->real;
*(here->BSIM4DPbpPtr +1) += m * xcdbb * s->imag;
*(here->BSIM4DPbpPtr) -= m * (gjbd + gdtotb - Gmbs - gbdpb + gIdtotb
- T1 * ddxpart_dVb - dxpart * xgtb);
*(here->BSIM4DPdpPtr ) += mult_q * xcddb * s->real;
*(here->BSIM4DPdpPtr +1) += mult_q * xcddb * s->imag;
*(here->BSIM4DPdpPtr) += mult_i * (gdpr + gds + here->BSIM4gbd
- gdtotd + RevSum + gbdpdp - gIdtotd)
+ mult_q * (dxpart * xgtd + T1 * ddxpart_dVd);
*(here->BSIM4DPdPtr) -= mult_i * (gdpr + gdtot);
*(here->BSIM4DPgpPtr ) += mult_q * xcdgb * s->real;
*(here->BSIM4DPgpPtr +1) += mult_q * xcdgb * s->imag;
*(here->BSIM4DPgpPtr) += mult_i * (Gm - gdtotg + gbdpg - gIdtotg)
+ mult_q * (T1 * ddxpart_dVg + dxpart * xgtg);
*(here->BSIM4DPspPtr ) += mult_q * xcdsb * s->real;
*(here->BSIM4DPspPtr +1) += mult_q * xcdsb * s->imag;
*(here->BSIM4DPspPtr) -= mult_i * (gds + FwdSum + gdtots - gbdpsp + gIdtots)
- mult_q * (T1 * ddxpart_dVs + dxpart * xgts);
*(here->BSIM4DPbpPtr ) += mult_q * xcdbb * s->real;
*(here->BSIM4DPbpPtr +1) += mult_q * xcdbb * s->imag;
*(here->BSIM4DPbpPtr) -= mult_i * (gjbd + gdtotb - Gmbs - gbdpb + gIdtotb)
- mult_q * T1 * (ddxpart_dVb + dxpart * xgtb);
*(here->BSIM4DdpPtr) -= m * (gdpr - gdtotd);
*(here->BSIM4DdPtr) += m * (gdpr + gdtot);
*(here->BSIM4DdpPtr) -= mult_i * (gdpr - gdtotd);
*(here->BSIM4DdPtr) += mult_i * (gdpr + gdtot);
*(here->BSIM4SPdpPtr ) += m * xcsdb * s->real;
*(here->BSIM4SPdpPtr +1) += m * xcsdb * s->imag;
*(here->BSIM4SPdpPtr) -= m * (gds + gstotd + RevSum - gbspdp + gIstotd
- T1 * dsxpart_dVd - sxpart * xgtd);
*(here->BSIM4SPgpPtr ) += m * xcsgb * s->real;
*(here->BSIM4SPgpPtr +1) += m * xcsgb * s->imag;
*(here->BSIM4SPgpPtr) -= m * (Gm + gstotg - gbspg + gIstotg
- T1 * dsxpart_dVg - sxpart * xgtg);
*(here->BSIM4SPspPtr ) += m * xcssb * s->real;
*(here->BSIM4SPspPtr +1) += m * xcssb * s->imag;
*(here->BSIM4SPspPtr) += m * (gspr + gds + here->BSIM4gbs - gIstots
- gstots + FwdSum + gbspsp
+ sxpart * xgts + T1 * dsxpart_dVs);
*(here->BSIM4SPsPtr) -= m * (gspr + gstot);
*(here->BSIM4SPbpPtr ) += m * xcsbb * s->real;
*(here->BSIM4SPbpPtr +1) += m * xcsbb * s->imag;
*(here->BSIM4SPbpPtr) -= m * (gjbs + gstotb + Gmbs - gbspb + gIstotb
- T1 * dsxpart_dVb - sxpart * xgtb);
*(here->BSIM4SPdpPtr ) += mult_q * xcsdb * s->real;
*(here->BSIM4SPdpPtr +1) += mult_q * xcsdb * s->imag;
*(here->BSIM4SPdpPtr) -= mult_i * (gds + gstotd + RevSum - gbspdp + gIstotd)
- mult_q * (T1 * dsxpart_dVd + sxpart * xgtd);
*(here->BSIM4SPgpPtr ) += mult_q * xcsgb * s->real;
*(here->BSIM4SPgpPtr +1) += mult_q * xcsgb * s->imag;
*(here->BSIM4SPgpPtr) -= mult_i * (Gm + gstotg - gbspg + gIstotg)
- mult_q * (T1 * dsxpart_dVg + sxpart * xgtg);
*(here->BSIM4SPspPtr ) += mult_q * xcssb * s->real;
*(here->BSIM4SPspPtr +1) += mult_q * xcssb * s->imag;
*(here->BSIM4SPspPtr) += mult_i * (gspr + gds + here->BSIM4gbs - gIstots
- gstots + FwdSum + gbspsp)
+ mult_q * (sxpart * xgts + T1 * dsxpart_dVs);
*(here->BSIM4SPsPtr) -= mult_i * (gspr + gstot);
*(here->BSIM4SPbpPtr ) += mult_q * xcsbb * s->real;
*(here->BSIM4SPbpPtr +1) += mult_q * xcsbb * s->imag;
*(here->BSIM4SPbpPtr) -= mult_i * (gjbs + gstotb + Gmbs - gbspb + gIstotb)
- mult_q * (T1 * dsxpart_dVb + sxpart * xgtb);
*(here->BSIM4SspPtr) -= m * (gspr - gstots);
*(here->BSIM4SsPtr) += m * (gspr + gstot);
*(here->BSIM4SspPtr) -= mult_i * (gspr - gstots);
*(here->BSIM4SsPtr) += mult_i * (gspr + gstot);
*(here->BSIM4BPdpPtr ) += m * xcbdb * s->real;
*(here->BSIM4BPdpPtr +1) += m * xcbdb * s->imag;
*(here->BSIM4BPdpPtr) -= m * (gjbd - gbbdp + gIbtotd);
*(here->BSIM4BPgpPtr ) += m * xcbgb * s->real;
*(here->BSIM4BPgpPtr +1) += m * xcbgb * s->imag;
*(here->BSIM4BPgpPtr) -= m * (here->BSIM4gbgs + gIbtotg);
*(here->BSIM4BPspPtr ) += m * xcbsb * s->real;
*(here->BSIM4BPspPtr +1) += m * xcbsb * s->imag;
*(here->BSIM4BPspPtr) -= m * (gjbs - gbbsp + gIbtots);
*(here->BSIM4BPbpPtr ) += m * xcbbb * s->real;
*(here->BSIM4BPbpPtr +1) += m * xcbbb * s->imag;
*(here->BSIM4BPbpPtr) += m * (gjbd + gjbs - here->BSIM4gbbs
*(here->BSIM4BPdpPtr ) += mult_q * xcbdb * s->real;
*(here->BSIM4BPdpPtr +1) += mult_q * xcbdb * s->imag;
*(here->BSIM4BPdpPtr) -= mult_i * (gjbd - gbbdp + gIbtotd);
*(here->BSIM4BPgpPtr ) += mult_q * xcbgb * s->real;
*(here->BSIM4BPgpPtr +1) += mult_q * xcbgb * s->imag;
*(here->BSIM4BPgpPtr) -= mult_i * (here->BSIM4gbgs + gIbtotg);
*(here->BSIM4BPspPtr ) += mult_q * xcbsb * s->real;
*(here->BSIM4BPspPtr +1) += mult_q * xcbsb * s->imag;
*(here->BSIM4BPspPtr) -= mult_i * (gjbs - gbbsp + gIbtots);
*(here->BSIM4BPbpPtr ) += mult_q * xcbbb * s->real;
*(here->BSIM4BPbpPtr +1) += mult_q * xcbbb * s->imag;
*(here->BSIM4BPbpPtr) += mult_i * (gjbd + gjbs - here->BSIM4gbbs
- gIbtotb);
ggidld = here->BSIM4ggidld;
ggidlg = here->BSIM4ggidlg;
@ -686,63 +681,63 @@ double m;
ggislb = here->BSIM4ggislb;
/* stamp gidl */
(*(here->BSIM4DPdpPtr) += m * ggidld);
(*(here->BSIM4DPgpPtr) += m * ggidlg);
(*(here->BSIM4DPspPtr) -= m * ((ggidlg + ggidld) + ggidlb));
(*(here->BSIM4DPbpPtr) += m * ggidlb);
(*(here->BSIM4BPdpPtr) -= m * ggidld);
(*(here->BSIM4BPgpPtr) -= m * ggidlg);
(*(here->BSIM4BPspPtr) += m * ((ggidlg + ggidld) + ggidlb));
(*(here->BSIM4BPbpPtr) -= m * ggidlb);
(*(here->BSIM4DPdpPtr) += mult_i * ggidld);
(*(here->BSIM4DPgpPtr) += mult_i * ggidlg);
(*(here->BSIM4DPspPtr) -= mult_i * ((ggidlg + ggidld) + ggidlb));
(*(here->BSIM4DPbpPtr) += mult_i * ggidlb);
(*(here->BSIM4BPdpPtr) -= mult_i * ggidld);
(*(here->BSIM4BPgpPtr) -= mult_i * ggidlg);
(*(here->BSIM4BPspPtr) += mult_i * ((ggidlg + ggidld) + ggidlb));
(*(here->BSIM4BPbpPtr) -= mult_i * ggidlb);
/* stamp gisl */
(*(here->BSIM4SPdpPtr) -= m * ((ggisls + ggislg) + ggislb));
(*(here->BSIM4SPgpPtr) += m * ggislg);
(*(here->BSIM4SPspPtr) += m * ggisls);
(*(here->BSIM4SPbpPtr) += m * ggislb);
(*(here->BSIM4BPdpPtr) += m * ((ggislg + ggisls) + ggislb));
(*(here->BSIM4BPgpPtr) -= m * ggislg);
(*(here->BSIM4BPspPtr) -= m * ggisls);
(*(here->BSIM4BPbpPtr) -= m * ggislb);
(*(here->BSIM4SPdpPtr) -= mult_i * ((ggisls + ggislg) + ggislb));
(*(here->BSIM4SPgpPtr) += mult_i * ggislg);
(*(here->BSIM4SPspPtr) += mult_i * ggisls);
(*(here->BSIM4SPbpPtr) += mult_i * ggislb);
(*(here->BSIM4BPdpPtr) += mult_i * ((ggislg + ggisls) + ggislb));
(*(here->BSIM4BPgpPtr) -= mult_i * ggislg);
(*(here->BSIM4BPspPtr) -= mult_i * ggisls);
(*(here->BSIM4BPbpPtr) -= mult_i * ggislb);
if (here->BSIM4rbodyMod)
{ (*(here->BSIM4DPdbPtr ) += m * xcdbdb * s->real);
(*(here->BSIM4DPdbPtr +1) += m * xcdbdb * s->imag);
(*(here->BSIM4DPdbPtr) -= m * here->BSIM4gbd);
(*(here->BSIM4SPsbPtr ) += m * xcsbsb * s->real);
(*(here->BSIM4SPsbPtr +1) += m * xcsbsb * s->imag);
(*(here->BSIM4SPsbPtr) -= m * here->BSIM4gbs);
{ (*(here->BSIM4DPdbPtr ) += mult_q * xcdbdb * s->real);
(*(here->BSIM4DPdbPtr +1) += mult_q * xcdbdb * s->imag);
(*(here->BSIM4DPdbPtr) -= mult_i * here->BSIM4gbd);
(*(here->BSIM4SPsbPtr ) += mult_q * xcsbsb * s->real);
(*(here->BSIM4SPsbPtr +1) += mult_q * xcsbsb * s->imag);
(*(here->BSIM4SPsbPtr) -= mult_i * here->BSIM4gbs);
(*(here->BSIM4DBdpPtr ) += m * xcdbdb * s->real);
(*(here->BSIM4DBdpPtr +1) += m * xcdbdb * s->imag);
(*(here->BSIM4DBdpPtr) -= m * here->BSIM4gbd);
(*(here->BSIM4DBdbPtr ) -= m * xcdbdb * s->real);
(*(here->BSIM4DBdbPtr +1) -= m * xcdbdb * s->imag);
(*(here->BSIM4DBdbPtr) += m * (here->BSIM4gbd + here->BSIM4grbpd
(*(here->BSIM4DBdpPtr ) += mult_q * xcdbdb * s->real);
(*(here->BSIM4DBdpPtr +1) += mult_q * xcdbdb * s->imag);
(*(here->BSIM4DBdpPtr) -= mult_i * here->BSIM4gbd);
(*(here->BSIM4DBdbPtr ) -= mult_q * xcdbdb * s->real);
(*(here->BSIM4DBdbPtr +1) -= mult_q * xcdbdb * s->imag);
(*(here->BSIM4DBdbPtr) += mult_i * (here->BSIM4gbd + here->BSIM4grbpd
+ here->BSIM4grbdb));
(*(here->BSIM4DBbpPtr) -= m * here->BSIM4grbpd);
(*(here->BSIM4DBbPtr) -= m * here->BSIM4grbdb);
(*(here->BSIM4DBbpPtr) -= mult_i * here->BSIM4grbpd);
(*(here->BSIM4DBbPtr) -= mult_i * here->BSIM4grbdb);
(*(here->BSIM4BPdbPtr) -= m * here->BSIM4grbpd);
(*(here->BSIM4BPbPtr) -= m * here->BSIM4grbpb);
(*(here->BSIM4BPsbPtr) -= m * here->BSIM4grbps);
(*(here->BSIM4BPbpPtr) += m * (here->BSIM4grbpd + here->BSIM4grbps
(*(here->BSIM4BPdbPtr) -= mult_i * here->BSIM4grbpd);
(*(here->BSIM4BPbPtr) -= mult_i * here->BSIM4grbpb);
(*(here->BSIM4BPsbPtr) -= mult_i * here->BSIM4grbps);
(*(here->BSIM4BPbpPtr) += mult_i * (here->BSIM4grbpd + here->BSIM4grbps
+ here->BSIM4grbpb));
/* WDL: (-here->BSIM4gbbs) already added to BPbpPtr */
(*(here->BSIM4SBspPtr ) += m * xcsbsb * s->real);
(*(here->BSIM4SBspPtr +1) += m * xcsbsb * s->imag);
(*(here->BSIM4SBspPtr) -= m * here->BSIM4gbs);
(*(here->BSIM4SBbpPtr) -= m * here->BSIM4grbps);
(*(here->BSIM4SBbPtr) -= m * here->BSIM4grbsb);
(*(here->BSIM4SBsbPtr ) -= m * xcsbsb * s->real);
(*(here->BSIM4SBsbPtr +1) -= m * xcsbsb * s->imag);
(*(here->BSIM4SBsbPtr) += m * (here->BSIM4gbs
(*(here->BSIM4SBspPtr ) += mult_q * xcsbsb * s->real);
(*(here->BSIM4SBspPtr +1) += mult_q * xcsbsb * s->imag);
(*(here->BSIM4SBspPtr) -= mult_i * here->BSIM4gbs);
(*(here->BSIM4SBbpPtr) -= mult_i * here->BSIM4grbps);
(*(here->BSIM4SBbPtr) -= mult_i * here->BSIM4grbsb);
(*(here->BSIM4SBsbPtr ) -= mult_q * xcsbsb * s->real);
(*(here->BSIM4SBsbPtr +1) -= mult_q * xcsbsb * s->imag);
(*(here->BSIM4SBsbPtr) += mult_i * (here->BSIM4gbs
+ here->BSIM4grbps + here->BSIM4grbsb));
(*(here->BSIM4BdbPtr) -= m * here->BSIM4grbdb);
(*(here->BSIM4BbpPtr) -= m * here->BSIM4grbpb);
(*(here->BSIM4BsbPtr) -= m * here->BSIM4grbsb);
(*(here->BSIM4BbPtr) += m * (here->BSIM4grbsb + here->BSIM4grbdb
(*(here->BSIM4BdbPtr) -= mult_i * here->BSIM4grbdb);
(*(here->BSIM4BbpPtr) -= mult_i * here->BSIM4grbpb);
(*(here->BSIM4BsbPtr) -= mult_i * here->BSIM4grbsb);
(*(here->BSIM4BbPtr) += mult_i * (here->BSIM4grbsb + here->BSIM4grbdb
+ here->BSIM4grbpb));
}

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
@ -144,12 +140,6 @@ BSIM4instance **InstArray;
if (!model->BSIM4geoModGiven)
model->BSIM4geoMod = 0;
if (!model->BSIM4rgeoModGiven)
model->BSIM4rgeoMod = 0;
else if ((model->BSIM4rgeoMod != 0) && (model->BSIM4rgeoMod != 1))
{ model->BSIM4rgeoMod = 1;
printf("Warning: rgeoMod has been set to its default value: 1.\n");
}
if (!model->BSIM4fnoiModGiven)
model->BSIM4fnoiMod = 1;
else if ((model->BSIM4fnoiMod != 0) && (model->BSIM4fnoiMod != 1))
@ -211,9 +201,8 @@ BSIM4instance **InstArray;
{ model->BSIM4tempMod = 0;
printf("Warning: tempMod has been set to its default value: 0.\n");
}
if (!model->BSIM4versionGiven)
model->BSIM4version = copy("4.8.2");
model->BSIM4version = copy("4.8.3");
if (!model->BSIM4toxrefGiven)
model->BSIM4toxref = 30.0e-10;
if (!model->BSIM4eotGiven)
@ -240,7 +229,6 @@ BSIM4instance **InstArray;
model->BSIM4dtox = 0.0;
if (!model->BSIM4epsroxGiven)
model->BSIM4epsrox = 3.9;
if (!model->BSIM4cdscGiven)
model->BSIM4cdsc = 2.4e-4; /* unit Q/V/m^2 */
if (!model->BSIM4cdscbGiven)
@ -267,6 +255,8 @@ BSIM4instance **InstArray;
model->BSIM4a2 = 1.0;
if (!model->BSIM4ketaGiven)
model->BSIM4keta = -0.047; /* unit / V */
if (!model->BSIM4ketacGiven)
model->BSIM4ketac = model->BSIM4keta; /* unit / V */
if (!model->BSIM4nsubGiven)
model->BSIM4nsub = 6.0e16; /* unit 1/cm3 */
if (!model->BSIM4phigGiven)
@ -351,9 +341,11 @@ BSIM4instance **InstArray;
model->BSIM4eu = (model->BSIM4type == NMOS) ? 1.67 : 1.0;
if (!model->BSIM4ucsGiven)
model->BSIM4ucs = (model->BSIM4type == NMOS) ? 1.67 : 1.0;
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) &&
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)))
{ /* check only for version <= 4.80 */
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) &&
(strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4)))
{
if (!model->BSIM4uaGiven)
model->BSIM4ua = ((model->BSIM4mobMod == 2)) ? 1.0e-15 : 1.0e-9; /* unit m/V */
if (!model->BSIM4ucGiven)
@ -365,12 +357,12 @@ BSIM4instance **InstArray;
{
if (!model->BSIM4uaGiven)
model->BSIM4ua = ((model->BSIM4mobMod == 2 || model->BSIM4mobMod == 6)) ? 1.0e-15 : 1.0e-9; /* unit m/V */
/*printf("warning:ua=%g",model->BSIM4ua);*/
if (!model->BSIM4ucGiven)
model->BSIM4uc = (model->BSIM4mobMod == 1 || model->BSIM4mobMod == 5) ? -0.0465 : -0.0465e-9;
if (!model->BSIM4uc1Given)
model->BSIM4uc1 = (model->BSIM4mobMod == 1 || model->BSIM4mobMod == 5) ? -0.056 : -0.056e-9;
}
if (!model->BSIM4ua1Given)
model->BSIM4ua1 = 1.0e-9; /* unit m/V */
if (!model->BSIM4ubGiven)
@ -535,6 +527,7 @@ BSIM4instance **InstArray;
model->BSIM4kgisl = model->BSIM4kgidl;
if (!model->BSIM4fgislGiven) /* v4.7 New GIDL/GISL */
model->BSIM4fgisl = model->BSIM4fgidl;
if (!model->BSIM4aigcGiven)
model->BSIM4aigc = (model->BSIM4type == NMOS) ? 1.36e-2 : 9.80e-3;
if (!model->BSIM4bigcGiven)
@ -816,6 +809,8 @@ BSIM4instance **InstArray;
model->BSIM4la2 = 0.0;
if (!model->BSIM4lketaGiven)
model->BSIM4lketa = 0.0;
if (!model->BSIM4lketacGiven)
model->BSIM4lketac = model->BSIM4lketa;
if (!model->BSIM4lnsubGiven)
model->BSIM4lnsub = 0.0;
if (!model->BSIM4lndepGiven)
@ -1193,6 +1188,8 @@ BSIM4instance **InstArray;
model->BSIM4wa2 = 0.0;
if (!model->BSIM4wketaGiven)
model->BSIM4wketa = 0.0;
if (!model->BSIM4wketacGiven)
model->BSIM4wketac = model->BSIM4wketa;
if (!model->BSIM4wnsubGiven)
model->BSIM4wnsub = 0.0;
if (!model->BSIM4wndepGiven)
@ -1357,7 +1354,6 @@ BSIM4instance **InstArray;
model->BSIM4wkgidl = 0.0;
if (!model->BSIM4wfgidlGiven) /* v4.7 New GIDL/GISL */
model->BSIM4wfgidl = 0.0;
/*if (!model->BSIM4wagislGiven)
{
if (model->BSIM4wagidlGiven)
@ -1562,7 +1558,6 @@ BSIM4instance **InstArray;
model->BSIM4pat = 0.0;
if (!model->BSIM4pa0Given)
model->BSIM4pa0 = 0.0;
if (!model->BSIM4pagsGiven)
model->BSIM4pags = 0.0;
if (!model->BSIM4pa1Given)
@ -1571,6 +1566,8 @@ BSIM4instance **InstArray;
model->BSIM4pa2 = 0.0;
if (!model->BSIM4pketaGiven)
model->BSIM4pketa = 0.0;
if (!model->BSIM4pketacGiven)
model->BSIM4pketac = model->BSIM4pketa;
if (!model->BSIM4pnsubGiven)
model->BSIM4pnsub = 0.0;
if (!model->BSIM4pndepGiven)
@ -1796,6 +1793,7 @@ BSIM4instance **InstArray;
model->BSIM4pkgisl = model->BSIM4pkgidl;
if (!model->BSIM4pfgislGiven) /* v4.7 New GIDL/GISL */
model->BSIM4pfgisl = model->BSIM4pfgidl;
if (!model->BSIM4paigcGiven)
model->BSIM4paigc = 0.0;
if (!model->BSIM4pbigcGiven)
@ -1895,7 +1893,6 @@ BSIM4instance **InstArray;
model->BSIM4pteta0 = 0.0;
if (!model->BSIM4ptvoffcvGiven) /* v4.7 temp dep of leakage current */
model->BSIM4ptvoffcv = 0.0;
if (!model->BSIM4pcgslGiven)
model->BSIM4pcgsl = 0.0;
if (!model->BSIM4pcgdlGiven)
@ -1920,7 +1917,6 @@ BSIM4instance **InstArray;
model->BSIM4pnoff = 0.0;
if (!model->BSIM4pvoffcvGiven)
model->BSIM4pvoffcv = 0.0;
if (!model->BSIM4gamma1Given)
model->BSIM4gamma1 = 0.0;
if (!model->BSIM4lgamma1Given)
@ -2167,13 +2163,15 @@ BSIM4instance **InstArray;
model->BSIM4vtsswgd = model->BSIM4vtsswgs;
if (!model->BSIM4oxideTrapDensityAGiven)
{ if (model->BSIM4type == NMOS)
{
if (model->BSIM4type == NMOS)
model->BSIM4oxideTrapDensityA = 6.25e41;
else
model->BSIM4oxideTrapDensityA= 6.188e40;
}
if (!model->BSIM4oxideTrapDensityBGiven)
{ if (model->BSIM4type == NMOS)
{
if (model->BSIM4type == NMOS)
model->BSIM4oxideTrapDensityB = 3.125e26;
else
model->BSIM4oxideTrapDensityB = 1.5e25;
@ -2305,11 +2303,9 @@ BSIM4instance **InstArray;
for (here = BSIM4instances(model); here != NULL ;
here=BSIM4nextInstance(here))
{
/* allocate a chunk of the state vector */
{ /* allocate a chunk of the state vector */
here->BSIM4states = *states;
*states += BSIM4numStates;
/* perform the parameter defaulting */
if (!here->BSIM4lGiven)
here->BSIM4l = 5.0e-6;
@ -2317,6 +2313,12 @@ BSIM4instance **InstArray;
here->BSIM4w = 5.0e-6;
if (!here->BSIM4mGiven)
here->BSIM4m = 1.0;
if (!here->BSIM4mult_iGiven)
here->BSIM4mult_i = 1.0;
if (!here->BSIM4mult_qGiven)
here->BSIM4mult_q = 1.0;
if (!here->BSIM4mult_fnGiven)
here->BSIM4mult_fn = here->BSIM4mult_i;
if (!here->BSIM4nfGiven)
here->BSIM4nf = 1.0;
if (!here->BSIM4minGiven)
@ -2352,13 +2354,14 @@ BSIM4instance **InstArray;
here->BSIM4rbpd = model->BSIM4rbpd;
if (!here->BSIM4delvtoGiven)
here->BSIM4delvto = 0.0;
if (!here->BSIM4mulu0Given)
here->BSIM4mulu0 = 1.0;
if (!here->BSIM4xgwGiven)
here->BSIM4xgw = model->BSIM4xgw;
if (!here->BSIM4ngconGiven)
here->BSIM4ngcon = model->BSIM4ngcon;
here->BSIM4mult_i = here->BSIM4mult_i * here->BSIM4m;
here->BSIM4mult_q = here->BSIM4mult_q * here->BSIM4m;
here->BSIM4mult_fn = here->BSIM4mult_fn * here->BSIM4m;
/* Process instance model selectors, some
* may override their global counterparts
@ -2382,15 +2385,8 @@ BSIM4instance **InstArray;
if (!here->BSIM4geoModGiven)
here->BSIM4geoMod = model->BSIM4geoMod;
if (!here->BSIM4rgeoModGiven)
here->BSIM4rgeoMod = model->BSIM4rgeoMod;
else if ((here->BSIM4rgeoMod != 0) && (here->BSIM4rgeoMod != 1))
{ here->BSIM4rgeoMod = model->BSIM4rgeoMod;
printf("Warning: rgeoMod has been set to its global value %d.\n",
model->BSIM4rgeoMod);
}
here->BSIM4rgeoMod = 0;
if (!here->BSIM4trnqsModGiven)
here->BSIM4trnqsMod = model->BSIM4trnqsMod;
else if ((here->BSIM4trnqsMod != 0) && (here->BSIM4trnqsMod != 1))
@ -2439,7 +2435,7 @@ BSIM4instance **InstArray;
} else if (!here->BSIM4drainSquaresGiven
&& (here->BSIM4rgeoMod != 0))
{
BSIM4RdseffGeo(here->BSIM4nf*here->BSIM4m, here->BSIM4geoMod,
BSIM4RdseffGeo(here->BSIM4nf, here->BSIM4geoMod,
here->BSIM4rgeoMod, here->BSIM4min,
here->BSIM4w, model->BSIM4sheetResistance,
DMCGeff, DMCIeff, DMDGeff, 0, &Rtot);
@ -2447,8 +2443,7 @@ BSIM4instance **InstArray;
createNode = 1;
}
}
if ( createNode != 0 )
{ if ( here->BSIM4dNodePrime == 0 )
if ( createNode != 0 && (here->BSIM4dNodePrime == 0))
{ error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"drain");
if(error) return(error);
here->BSIM4dNodePrime = tmp->number;
@ -2463,7 +2458,6 @@ BSIM4instance **InstArray;
}
}
}
}
else
{ here->BSIM4dNodePrime = here->BSIM4dNode;
}
@ -2483,7 +2477,7 @@ BSIM4instance **InstArray;
} else if (!here->BSIM4sourceSquaresGiven
&& (here->BSIM4rgeoMod != 0))
{
BSIM4RdseffGeo(here->BSIM4nf*here->BSIM4m, here->BSIM4geoMod,
BSIM4RdseffGeo(here->BSIM4nf, here->BSIM4geoMod,
here->BSIM4rgeoMod, here->BSIM4min,
here->BSIM4w, model->BSIM4sheetResistance,
DMCGeff, DMCIeff, DMDGeff, 1, &Rtot);
@ -2491,8 +2485,7 @@ BSIM4instance **InstArray;
createNode = 1;
}
}
if ( createNode != 0 )
{ if ( here->BSIM4sNodePrime == 0 )
if ( createNode != 0 && here->BSIM4sNodePrime == 0)
{ error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"source");
if(error) return(error);
here->BSIM4sNodePrime = tmp->number;
@ -2507,12 +2500,10 @@ BSIM4instance **InstArray;
}
}
}
}
else
here->BSIM4sNodePrime = here->BSIM4sNode;
if ( here->BSIM4rgateMod > 0 )
{ if ( here->BSIM4gNodePrime == 0 )
if ((here->BSIM4rgateMod > 0) && (here->BSIM4gNodePrime == 0))
{ error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"gate");
if(error) return(error);
here->BSIM4gNodePrime = tmp->number;
@ -2527,17 +2518,14 @@ BSIM4instance **InstArray;
}
}
}
}
else
here->BSIM4gNodePrime = here->BSIM4gNodeExt;
if ( here->BSIM4rgateMod == 3 )
{ if ( here->BSIM4gNodeMid == 0 )
if ((here->BSIM4rgateMod == 3) && (here->BSIM4gNodeMid == 0))
{ error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"midgate");
if(error) return(error);
here->BSIM4gNodeMid = tmp->number;
}
}
else
here->BSIM4gNodeMid = here->BSIM4gNodeExt;
@ -2575,17 +2563,14 @@ BSIM4instance **InstArray;
= here->BSIM4bNode;
/* NQS node */
if ( here->BSIM4trnqsMod )
{ if ( here->BSIM4qNode == 0 )
if ((here->BSIM4trnqsMod) && (here->BSIM4qNode == 0))
{ error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"charge");
if(error) return(error);
here->BSIM4qNode = tmp->number;
}
}
else
here->BSIM4qNode = 0;
/* set Sparse Matrix Pointers
* macro to make elements with built-in out-of-memory test */
#define TSTALLOC(ptr,first,second) \
@ -2725,7 +2710,6 @@ BSIM4unsetup(
GENmodel *inModel,
CKTcircuit *ckt)
{
#ifndef HAS_BATCHSIM
BSIM4model *model;
BSIM4instance *here;
@ -2780,6 +2764,5 @@ CKTcircuit *ckt)
here->BSIM4dNodePrime = 0;
}
}
#endif
return OK;
}

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,8 +17,10 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
*/
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
#include "ngspice/smpdefs.h"
#include "ngspice/cktdefs.h"
@ -94,6 +89,7 @@ double n,n0, Vgsteff, Vgs_eff, niter, toxpf, toxpi, Tcen, toxe, epsrox, vddeot;
double vtfbphi2eot, phieot, TempRatioeot, Vtm0eot, Vtmeot,vbieot;
int Size_Not_Found, i;
int Fatal_Flag = 0;
/* loop through all the BSIM4 device models */
for (; model != NULL; model = BSIM4nextModel(model))
@ -139,10 +135,8 @@ int Size_Not_Found, i;
if (!model->BSIM4toxmGiven) /* v4.7 */
model->BSIM4toxm = model->BSIM4toxe;
}
if (!model->BSIM4cfGiven) /* v4.8.2 */
model->BSIM4cf = 2.0 * model->BSIM4epsrox * EPS0 / PI
* log(1.0 + 0.4e-6 / model->BSIM4toxe);
}
else if(model->BSIM4mtrlCompatMod != 0) /* v4.7 */
{
T0 = model->BSIM4epsrox / 3.9;
@ -172,7 +166,9 @@ int Size_Not_Found, i;
toxe = model->BSIM4toxe;
epssub = EPSSI;
}
if(!model->BSIM4cfGiven)
model->BSIM4cf = 2.0 * epsrox * EPS0 / PI
* log(1.0 + 0.4e-6 /toxe);
model->BSIM4coxe = epsrox * EPS0 / toxe;
if(model->BSIM4mtrlMod == 0 || model->BSIM4mtrlCompatMod != 0)
@ -194,13 +190,6 @@ int Size_Not_Found, i;
}
if (!model->BSIM4cgboGiven)
model->BSIM4cgbo = 2.0 * model->BSIM4dwc * model->BSIM4coxe;
struct bsim4SizeDependParam *p = model->pSizeDependParamKnot;
while (p) {
struct bsim4SizeDependParam *next_p = p->pNext;
FREE(p);
p = next_p;
}
model->pSizeDependParamKnot = NULL;
pLastKnot = NULL;
@ -351,26 +340,26 @@ int Size_Not_Found, i;
model->BSIM4PhiBSWS = model->BSIM4SsidewallJctPotential
- model->BSIM4tpbsw * delTemp;
if (model->BSIM4PhiBSWS <= 0.01)
if (model->BSIM4PhiBSWS < 0.01)
{ model->BSIM4PhiBSWS = 0.01;
fprintf(stderr, "Temperature effect has caused pbsws to be less than 0.01. Pbsws is clamped to 0.01.\n");
}
model->BSIM4PhiBSWD = model->BSIM4DsidewallJctPotential
- model->BSIM4tpbsw * delTemp;
if (model->BSIM4PhiBSWD <= 0.01)
if (model->BSIM4PhiBSWD < 0.01)
{ model->BSIM4PhiBSWD = 0.01;
fprintf(stderr, "Temperature effect has caused pbswd to be less than 0.01. Pbswd is clamped to 0.01.\n");
}
model->BSIM4PhiBSWGS = model->BSIM4SGatesidewallJctPotential
- model->BSIM4tpbswg * delTemp;
if (model->BSIM4PhiBSWGS <= 0.01)
if (model->BSIM4PhiBSWGS < 0.01)
{ model->BSIM4PhiBSWGS = 0.01;
fprintf(stderr, "Temperature effect has caused pbswgs to be less than 0.01. Pbswgs is clamped to 0.01.\n");
}
model->BSIM4PhiBSWGD = model->BSIM4DGatesidewallJctPotential
- model->BSIM4tpbswg * delTemp;
if (model->BSIM4PhiBSWGD <= 0.01)
if (model->BSIM4PhiBSWGD < 0.01)
{ model->BSIM4PhiBSWGD = 0.01;
fprintf(stderr, "Temperature effect has caused pbswgd to be less than 0.01. Pbswgd is clamped to 0.01.\n");
} /* End of junction capacitance */
@ -425,8 +414,7 @@ int Size_Not_Found, i;
/* loop through all the instances of the model */
for (here = BSIM4instances(model); here != NULL;
here = BSIM4nextInstance(here))
{
pSizeDependParamKnot = model->pSizeDependParamKnot;
{ pSizeDependParamKnot = model->pSizeDependParamKnot;
Size_Not_Found = 1;
while ((pSizeDependParamKnot != NULL) && Size_Not_Found)
{ if ((here->BSIM4l == pSizeDependParamKnot->Length)
@ -447,7 +435,8 @@ int Size_Not_Found, i;
Wdrn = here->BSIM4w / here->BSIM4nf;
if (Size_Not_Found)
{ pParam = TMALLOC(struct bsim4SizeDependParam, 1);
{ pParam = (struct bsim4SizeDependParam *)malloc(
sizeof(struct bsim4SizeDependParam));
if (pLastKnot == NULL)
model->pSizeDependParamKnot = pParam;
else
@ -482,46 +471,56 @@ int Size_Not_Found, i;
pParam->BSIM4leff = Lnew - 2.0 * pParam->BSIM4dl;
if (pParam->BSIM4leff <= 0.0)
{
SPfrontEnd->IFerrorf(ERR_FATAL,
{ IFuid namarray[2];
namarray[0] = model->BSIM4modName;
namarray[1] = here->BSIM4name;
(*(SPfrontEnd->IFerror))(ERR_FATAL,
"BSIM4: mosfet %s, model %s: Effective channel length <= 0",
model->BSIM4modName, here->BSIM4name);
namarray);
return(E_BADPARM);
}
pParam->BSIM4weff = Wnew - 2.0 * pParam->BSIM4dw;
if (pParam->BSIM4weff <= 0.0)
{
SPfrontEnd->IFerrorf(ERR_FATAL,
{ IFuid namarray[2];
namarray[0] = model->BSIM4modName;
namarray[1] = here->BSIM4name;
(*(SPfrontEnd->IFerror))(ERR_FATAL,
"BSIM4: mosfet %s, model %s: Effective channel width <= 0",
model->BSIM4modName, here->BSIM4name);
namarray);
return(E_BADPARM);
}
pParam->BSIM4leffCV = Lnew - 2.0 * pParam->BSIM4dlc;
if (pParam->BSIM4leffCV <= 0.0)
{
SPfrontEnd->IFerrorf(ERR_FATAL,
{ IFuid namarray[2];
namarray[0] = model->BSIM4modName;
namarray[1] = here->BSIM4name;
(*(SPfrontEnd->IFerror))(ERR_FATAL,
"BSIM4: mosfet %s, model %s: Effective channel length for C-V <= 0",
model->BSIM4modName, here->BSIM4name);
namarray);
return(E_BADPARM);
}
pParam->BSIM4weffCV = Wnew - 2.0 * pParam->BSIM4dwc;
if (pParam->BSIM4weffCV <= 0.0)
{
SPfrontEnd->IFerrorf(ERR_FATAL,
{ IFuid namarray[2];
namarray[0] = model->BSIM4modName;
namarray[1] = here->BSIM4name;
(*(SPfrontEnd->IFerror))(ERR_FATAL,
"BSIM4: mosfet %s, model %s: Effective channel width for C-V <= 0",
model->BSIM4modName, here->BSIM4name);
namarray);
return(E_BADPARM);
}
pParam->BSIM4weffCJ = Wnew - 2.0 * pParam->BSIM4dwj;
if (pParam->BSIM4weffCJ <= 0.0)
{
SPfrontEnd->IFerrorf(ERR_FATAL,
{ IFuid namarray[2];
namarray[0] = model->BSIM4modName;
namarray[1] = here->BSIM4name;
(*(SPfrontEnd->IFerror))(ERR_FATAL,
"BSIM4: mosfet %s, model %s: Effective channel width for S/D junctions <= 0",
model->BSIM4modName, here->BSIM4name);
namarray);
return(E_BADPARM);
}
@ -598,6 +597,10 @@ int Size_Not_Found, i;
+ model->BSIM4lketa * Inv_L
+ model->BSIM4wketa * Inv_W
+ model->BSIM4pketa * Inv_LW;
pParam->BSIM4ketac = model->BSIM4ketac
+ model->BSIM4lketac * Inv_L
+ model->BSIM4wketac * Inv_W
+ model->BSIM4pketac * Inv_LW;
pParam->BSIM4nsub = model->BSIM4nsub
+ model->BSIM4lnsub * Inv_L
+ model->BSIM4wnsub * Inv_W
@ -1181,7 +1184,6 @@ int Size_Not_Found, i;
+ model->BSIM4lku0we * Inv_L
+ model->BSIM4wku0we * Inv_W
+ model->BSIM4pku0we * Inv_LW;
pParam->BSIM4abulkCVfactor = 1.0 + pow((pParam->BSIM4clc
/ pParam->BSIM4leffCV),
pParam->BSIM4cle);
@ -1316,6 +1318,15 @@ int Size_Not_Found, i;
pParam->BSIM4phi = Vtm0 * log(pParam->BSIM4ndep / ni)
+ pParam->BSIM4phin + 0.4;
if(pParam->BSIM4phi <= 0.0)
{
printf("Fatal: Phi = %g is not positive. Please check Phin and Ndep\n",
pParam->BSIM4phi);
printf(" Phin = %g Ndep = %g \n",
pParam->BSIM4phin, pParam->BSIM4ndep);
Fatal_Flag = 1;
}
pParam->BSIM4sqrtPhi = sqrt(pParam->BSIM4phi);
pParam->BSIM4phis3 = pParam->BSIM4sqrtPhi * pParam->BSIM4phi;
@ -1363,16 +1374,19 @@ int Size_Not_Found, i;
/ (toxe * pParam->BSIM4poxedge)))
/ toxe / toxe
/ pParam->BSIM4poxedge / pParam->BSIM4poxedge;
pParam->BSIM4Aechvb = (model->BSIM4type == NMOS) ? 4.97232e-7 : 3.42537e-7;
pParam->BSIM4Bechvb = (model->BSIM4type == NMOS) ? 7.45669e11 : 1.16645e12;
if ((strcmp(model->BSIM4version, "4.8.1")) && (strncmp(model->BSIM4version, "4.81", 4)) &&
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)))
(strcmp(model->BSIM4version, "4.8.2")) && (strncmp(model->BSIM4version, "4.82", 4)) &&
(strcmp(model->BSIM4version, "4.8.3")) && (strncmp(model->BSIM4version, "4.83", 4)))
{
pParam->BSIM4AechvbEdgeS = pParam->BSIM4Aechvb * pParam->BSIM4weff
* model->BSIM4dlcig * pParam->BSIM4ToxRatioEdge;
pParam->BSIM4AechvbEdgeD = pParam->BSIM4Aechvb * pParam->BSIM4weff
* model->BSIM4dlcigd * pParam->BSIM4ToxRatioEdge;
}
else
{
@ -1390,6 +1404,7 @@ int Size_Not_Found, i;
}
pParam->BSIM4AechvbEdgeD = pParam->BSIM4Aechvb * pParam->BSIM4weff
* model->BSIM4dlcigd * pParam->BSIM4ToxRatioEdge;
}
pParam->BSIM4BechvbEdge = -pParam->BSIM4Bechvb
@ -1399,6 +1414,8 @@ int Size_Not_Found, i;
pParam->BSIM4Bechvb *= -toxe;
pParam->BSIM4mstar = 0.5 + atan(pParam->BSIM4minv) / PI;
pParam->BSIM4mstarcv = 0.5 + atan(pParam->BSIM4minvcv) / PI;
pParam->BSIM4voffcbn = pParam->BSIM4voff + model->BSIM4voffl / pParam->BSIM4leff;
@ -1411,18 +1428,13 @@ int Size_Not_Found, i;
if (model->BSIM4k1Given || model->BSIM4k2Given)
{ if (!model->BSIM4k1Given)
{
if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) /* don't print in sensitivity */
fprintf(stdout, "Warning: k1 should be specified with k2.\n");
{ fprintf(stdout, "Warning: k1 should be specified with k2.\n");
pParam->BSIM4k1 = 0.53;
}
if (!model->BSIM4k2Given)
{
if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) /* don't print in sensitivity */
fprintf(stdout, "Warning: k2 should be specified with k1.\n");
{ fprintf(stdout, "Warning: k2 should be specified with k1.\n");
pParam->BSIM4k2 = -0.0186;
}
if ((!ckt->CKTcurJob) || (ckt->CKTcurJob->JOBtype < 9)) { /* don't print in sensitivity */
if (model->BSIM4nsubGiven)
fprintf(stdout, "Warning: nsub is ignored because k1 or k2 is given.\n");
if (model->BSIM4xtGiven)
@ -1434,7 +1446,6 @@ int Size_Not_Found, i;
if (model->BSIM4gamma2Given)
fprintf(stdout, "Warning: gamma2 is ignored because k1 or k2 is given.\n");
}
}
else
{ if (!model->BSIM4vbxGiven)
pParam->BSIM4vbx = pParam->BSIM4phi - 7.7348e-4
@ -1757,9 +1768,6 @@ int Size_Not_Found, i;
here->BSIM4vth0 += here->BSIM4delvto;
here->BSIM4vfb = pParam->BSIM4vfb + model->BSIM4type * here->BSIM4delvto;
/* low field mobility multiplier */
here->BSIM4u0temp = pParam->BSIM4u0temp * here->BSIM4mulu0;
/* Instance variables calculation */
T3 = model->BSIM4type * here->BSIM4vth0
- here->BSIM4vfb - pParam->BSIM4phi;
@ -1864,6 +1872,7 @@ int Size_Not_Found, i;
here->BSIM4rbpb = rbpbx*rbpby/(rbpbx + rbpby);
}
if ((here->BSIM4rbodyMod == 1 ) || ((here->BSIM4rbodyMod == 2 ) && (bodymode == 5)) )
{ if (here->BSIM4rbdb < 1.0e-3)
here->BSIM4grbdb = 1.0e3; /* in mho */
@ -2267,6 +2276,15 @@ int Size_Not_Found, i;
* pParam->BSIM4ndep / (ni * ni));
phieot = Vtm0eot * log(pParam->BSIM4ndep / ni)
+ pParam->BSIM4phin + 0.4;
if(phieot <= 0.0)
{
printf("Fatal: phieot = %g is not positive. Please Check Phin and Ndep\n",
pParam->BSIM4phi);
printf("phieot = %g Ndep = %g \n",
pParam->BSIM4phin, pParam->BSIM4ndep);
Fatal_Flag = 1;
}
tmp2 = here->BSIM4vfb + phieot;
vddeot = model->BSIM4type * model->BSIM4vddeot;
T0 = model->BSIM4epsrgate * EPS0;
@ -2375,18 +2393,22 @@ int Size_Not_Found, i;
} while ((niter<=4)&&(ABS(toxpf-toxpi)>1e-12));
here->BSIM4toxp = toxpf;
here->BSIM4coxp = epsrox * EPS0 / here->BSIM4toxp;
} else {
here->BSIM4toxp = model->BSIM4toxp;
here->BSIM4coxp = model->BSIM4coxp;
}
if (BSIM4checkModel(model, here, ckt))
{
SPfrontEnd->IFerrorf(ERR_FATAL,
"detected during BSIM4.8.2 parameter checking for \n model %s of device instance %s\n", model->BSIM4modName, here->BSIM4name);
{ IFuid namarray[2];
namarray[0] = model->BSIM4modName;
namarray[1] = here->BSIM4name;
(*(SPfrontEnd->IFerror)) (ERR_FATAL, "Fatal error(s) detected during BSIM4.6.0 parameter checking for %s in model %s", namarray);
return(E_BADPARM);
}
} /* End instance */
}
return(OK);
}

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#include "ngspice/ngspice.h"
@ -32,7 +28,6 @@ under the License.
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
BSIM4trunc(
GENmodel *inModel,

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#ifndef BSIM4
@ -95,6 +91,7 @@ typedef struct sBSIM4instance
double BSIM4l;
double BSIM4w;
double BSIM4m;
double BSIM4drainArea;
double BSIM4sourceArea;
double BSIM4drainSquares;
@ -103,6 +100,7 @@ typedef struct sBSIM4instance
double BSIM4sourcePerimeter;
double BSIM4sourceConductance;
double BSIM4drainConductance;
/* stress effect instance param */
double BSIM4sa;
double BSIM4sb;
@ -119,12 +117,11 @@ typedef struct sBSIM4instance
double BSIM4rbpd;
double BSIM4delvto;
double BSIM4mulu0;
int BSIM4wnflag;
double BSIM4xgw;
double BSIM4ngcon;
/* added here to account stress effect instance dependence */
double BSIM4u0temp;
double BSIM4vsattemp;
double BSIM4vth0;
@ -142,9 +139,12 @@ typedef struct sBSIM4instance
double BSIM4icVDS;
double BSIM4icVGS;
double BSIM4icVBS;
double BSIM4m;
double BSIM4mult_i;
double BSIM4mult_q;
double BSIM4mult_fn;
double BSIM4nf;
int BSIM4off;
int BSIM4mode;
int BSIM4trnqsMod;
int BSIM4acnqsMod;
@ -286,6 +286,9 @@ typedef struct sBSIM4instance
unsigned BSIM4lGiven :1;
unsigned BSIM4wGiven :1;
unsigned BSIM4mGiven :1;
unsigned BSIM4mult_iGiven :1;
unsigned BSIM4mult_qGiven :1;
unsigned BSIM4mult_fnGiven :1;
unsigned BSIM4nfGiven :1;
unsigned BSIM4minGiven :1;
unsigned BSIM4drainAreaGiven :1;
@ -307,8 +310,6 @@ typedef struct sBSIM4instance
unsigned BSIM4rbpdGiven :1;
unsigned BSIM4rbpsGiven :1;
unsigned BSIM4delvtoGiven :1;
unsigned BSIM4mulu0Given :1;
unsigned BSIM4wnflagGiven :1;
unsigned BSIM4xgwGiven :1;
unsigned BSIM4ngconGiven :1;
unsigned BSIM4icVDSGiven :1;
@ -680,6 +681,7 @@ struct bsim4SizeDependParam
double BSIM4a1;
double BSIM4a2;
double BSIM4keta;
double BSIM4ketac;
double BSIM4nsub;
double BSIM4ndep;
double BSIM4nsd;
@ -927,7 +929,6 @@ typedef struct sBSIM4model
int BSIM4rgateMod;
int BSIM4perMod;
int BSIM4geoMod;
int BSIM4rgeoMod;
int BSIM4mtrlMod;
int BSIM4mtrlCompatMod; /* v4.7 */
int BSIM4gidlMod; /* v4.7 New GIDL/GISL */
@ -962,6 +963,7 @@ typedef struct sBSIM4model
double BSIM4a1;
double BSIM4a2;
double BSIM4keta;
double BSIM4ketac;
double BSIM4nsub;
double BSIM4phig;
double BSIM4epsrgate;
@ -1247,6 +1249,7 @@ typedef struct sBSIM4model
double BSIM4la1;
double BSIM4la2;
double BSIM4lketa;
double BSIM4lketac;
double BSIM4lnsub;
double BSIM4lndep;
double BSIM4lnsd;
@ -1407,6 +1410,7 @@ typedef struct sBSIM4model
double BSIM4wa1;
double BSIM4wa2;
double BSIM4wketa;
double BSIM4wketac;
double BSIM4wnsub;
double BSIM4wndep;
double BSIM4wnsd;
@ -1567,6 +1571,7 @@ typedef struct sBSIM4model
double BSIM4pa1;
double BSIM4pa2;
double BSIM4pketa;
double BSIM4pketac;
double BSIM4pnsub;
double BSIM4pndep;
double BSIM4pnsd;
@ -1823,6 +1828,7 @@ typedef struct sBSIM4model
/* Pre-calculated constants
* move to size-dependent param */
double BSIM4Eg0;
double BSIM4vtm;
double BSIM4vtm0;
@ -1872,6 +1878,7 @@ typedef struct sBSIM4model
double BSIM4vgbrMax;
double BSIM4vbsrMax;
double BSIM4vbdrMax;
double BSIM4gidlclamp;
double BSIM4idovvdsc;
struct bsim4SizeDependParam *pSizeDependParamKnot;
@ -1892,7 +1899,6 @@ typedef struct sBSIM4model
unsigned BSIM4rgateModGiven :1;
unsigned BSIM4perModGiven :1;
unsigned BSIM4geoModGiven :1;
unsigned BSIM4rgeoModGiven :1;
unsigned BSIM4paramChkGiven :1;
unsigned BSIM4trnqsModGiven :1;
unsigned BSIM4acnqsModGiven :1;
@ -1932,6 +1938,7 @@ typedef struct sBSIM4model
unsigned BSIM4a1Given :1;
unsigned BSIM4a2Given :1;
unsigned BSIM4ketaGiven :1;
unsigned BSIM4ketacGiven :1;
unsigned BSIM4nsubGiven :1;
unsigned BSIM4phigGiven :1;
unsigned BSIM4epsrgateGiven :1;
@ -2217,6 +2224,7 @@ typedef struct sBSIM4model
unsigned BSIM4la1Given :1;
unsigned BSIM4la2Given :1;
unsigned BSIM4lketaGiven :1;
unsigned BSIM4lketacGiven :1;
unsigned BSIM4lnsubGiven :1;
unsigned BSIM4lndepGiven :1;
unsigned BSIM4lnsdGiven :1;
@ -2377,6 +2385,7 @@ typedef struct sBSIM4model
unsigned BSIM4wa1Given :1;
unsigned BSIM4wa2Given :1;
unsigned BSIM4wketaGiven :1;
unsigned BSIM4wketacGiven :1;
unsigned BSIM4wnsubGiven :1;
unsigned BSIM4wndepGiven :1;
unsigned BSIM4wnsdGiven :1;
@ -2537,6 +2546,7 @@ typedef struct sBSIM4model
unsigned BSIM4pa1Given :1;
unsigned BSIM4pa2Given :1;
unsigned BSIM4pketaGiven :1;
unsigned BSIM4pketacGiven :1;
unsigned BSIM4pnsubGiven :1;
unsigned BSIM4pndepGiven :1;
unsigned BSIM4pnsdGiven :1;
@ -2807,7 +2817,6 @@ typedef struct sBSIM4model
unsigned BSIM4pku0weGiven :1;
unsigned BSIM4gidlclampGiven :1;
unsigned BSIM4idovvdscGiven :1;
} BSIM4model;
@ -2855,35 +2864,40 @@ typedef struct sBSIM4model
#define BSIM4_SCC 36
#define BSIM4_SC 37
#define BSIM4_M 38
#define BSIM4_MULU0 39
#define BSIM4_WNFLAG 40
#define BSIM4_VGSTEFF 40
#define BSIM4_VDSEFF 41
#define BSIM4_CGSO 42
#define BSIM4_CGDO 43
#define BSIM4_CGBO 44
#define BSIM4_WEFF 45
#define BSIM4_LEFF 46
/* Global parameters */
#define BSIM4_MOD_TEMPEOT 65
#define BSIM4_MOD_LEFFEOT 66
#define BSIM4_MOD_WEFFEOT 67
#define BSIM4_MOD_UCSTE 68
#define BSIM4_MOD_LUCSTE 69
#define BSIM4_MOD_WUCSTE 70
#define BSIM4_MOD_PUCSTE 71
#define BSIM4_MOD_UCS 72
#define BSIM4_MOD_LUCS 73
#define BSIM4_MOD_WUCS 74
#define BSIM4_MOD_PUCS 75
#define BSIM4_MOD_CVCHARGEMOD 76
#define BSIM4_MOD_ADOS 77
#define BSIM4_MOD_BDOS 78
#define BSIM4_MOD_TEMPMOD 79
#define BSIM4_MOD_MTRLMOD 80
#define BSIM4_MOD_IGCMOD 81
#define BSIM4_MOD_IGBMOD 82
#define BSIM4_MOD_ACNQSMOD 83
#define BSIM4_MOD_FNOIMOD 84
#define BSIM4_MOD_RDSMOD 85
#define BSIM4_MOD_DIOMOD 86
#define BSIM4_MOD_PERMOD 87
#define BSIM4_MOD_GEOMOD 88
#define BSIM4_MOD_RGEOMOD 89
#define BSIM4_MOD_TEMPEOT 66
#define BSIM4_MOD_LEFFEOT 67
#define BSIM4_MOD_WEFFEOT 68
#define BSIM4_MOD_UCSTE 69
#define BSIM4_MOD_LUCSTE 70
#define BSIM4_MOD_WUCSTE 71
#define BSIM4_MOD_PUCSTE 72
#define BSIM4_MOD_UCS 73
#define BSIM4_MOD_LUCS 74
#define BSIM4_MOD_WUCS 75
#define BSIM4_MOD_PUCS 76
#define BSIM4_MOD_CVCHARGEMOD 77
#define BSIM4_MOD_ADOS 78
#define BSIM4_MOD_BDOS 79
#define BSIM4_MOD_TEMPMOD 80
#define BSIM4_MOD_MTRLMOD 81
#define BSIM4_MOD_IGCMOD 82
#define BSIM4_MOD_IGBMOD 83
#define BSIM4_MOD_ACNQSMOD 84
#define BSIM4_MOD_FNOIMOD 85
#define BSIM4_MOD_RDSMOD 86
#define BSIM4_MOD_DIOMOD 87
#define BSIM4_MOD_PERMOD 88
#define BSIM4_MOD_GEOMOD 89
#define BSIM4_MOD_RGATEMOD 90
#define BSIM4_MOD_RBODYMOD 91
#define BSIM4_MOD_CAPMOD 92
@ -3864,6 +3878,15 @@ typedef struct sBSIM4model
/* Tuning for noise parameter BSIM4IdovVds (C.K.Dabhi) - request cadence */
#define BSIM4_MOD_IDOVVDSC 1275
/* for dynamic evaluate */
#define BSIM4_MOD_KETAC 1276
#define BSIM4_MOD_LKETAC 1277
#define BSIM4_MOD_WKETAC 1278
#define BSIM4_MOD_PKETAC 1279
#define BSIM4_MULT_I 1280
#define BSIM4_MULT_Q 1281
#define BSIM4_MULT_FN 1282
#define BSIM4_MOD_VGS_MAX 1301
#define BSIM4_MOD_VGD_MAX 1302
#define BSIM4_MOD_VGB_MAX 1303
@ -3876,14 +3899,6 @@ typedef struct sBSIM4model
#define BSIM4_MOD_VBSR_MAX 1310
#define BSIM4_MOD_VBDR_MAX 1311
#define BSIM4_VGSTEFF 1400
#define BSIM4_VDSEFF 1401
#define BSIM4_CGSO 1402
#define BSIM4_CGDO 1403
#define BSIM4_CGBO 1404
#define BSIM4_WEFF 1405
#define BSIM4_LEFF 1406
#include "bsim4ext.h"
extern void BSIM4evaluate(double,double,double,BSIM4instance*,BSIM4model*,
@ -3898,3 +3913,4 @@ extern int BSIM4RdsEndIso(double, double, double, double, double, double, int, i
extern int BSIM4RdsEndSha(double, double, double, double, double, double, int, int, double *);
#endif /*BSIM4*/

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
extern int BSIM4acLoad(GENmodel *,CKTcircuit*);

View File

@ -1,20 +1,13 @@
/* ******************************************************************************
* BSIM4 4.8.2 released by Chetan Kumar Dabhi 01/01/2020 *
* BSIM4 4.8.3 released on 05/19/2025 *
* BSIM4 Model Equations *
******************************************************************************
******************************************************************************
* Copyright (c) 2020 University of California *
* Copyright (c) 2025 University of California *
* *
* Project Director: Prof. Chenming Hu. *
* Current developers: Chetan Kumar Dabhi (Ph.D. student, IIT Kanpur) *
* Prof. Yogesh Chauhan (IIT Kanpur) *
* Dr. Pragya Kushwaha (Postdoc, UC Berkeley) *
* Dr. Avirup Dasgupta (Postdoc, UC Berkeley) *
* Ming-Yen Kao (Ph.D. student, UC Berkeley) *
* Authors: Gary W. Ng, Weidong Liu, Xuemei Xi, Mohan Dunga, Wenwei Yang *
* Ali Niknejad, Chetan Kumar Dabhi, Yogesh Singh Chauhan, *
* Sayeef Salahuddin, Chenming Hu *
* Project Directors: Prof. Sayeef Salahuddin and Prof. Chenming Hu *
* Developers list: https://www.bsim.berkeley.edu/models/bsim4/auth_bsim4/ *
******************************************************************************/
/*
@ -24,6 +17,9 @@ http://opensource.org/licenses/ECL-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations
under the License.
BSIM4 model is supported by the members of Silicon Integration Initiative's Compact Model Coalition. A link to the most recent version of this
standard can be found at: http://www.si2.org/cmc
*/
#ifndef DEV_BSIM4

View File

@ -31,8 +31,8 @@ JFET2param(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
here->JFET2tempGiven = TRUE;
break;
case JFET2_DTEMP:
here->JFET2temp = value->rValue;
here->JFET2tempGiven = TRUE;
here->JFET2dtemp = value->rValue;
here->JFET2dtempGiven = TRUE;
break;
case JFET2_AREA:
here->JFET2area = value->rValue;

View File

@ -12,7 +12,8 @@ Author: 1987 Thomas L. Quarles
IFparm MESpTable[] = { /* parameters */
OPU("off", MES_OFF, IF_FLAG ,"Device initially off"),
IOPU("area", MES_AREA, IF_REAL ,"Area factor"),
IOPUR("m", MES_AREA, IF_REAL ,"Parallel Multiplier"),
IOPUR("m", MES_M, IF_REAL ,"Parallel Multiplier"),
IOPAU("ic", MES_IC, IF_REALVEC,"Initial VDS,VGS vector"),
IOPAU("icvds", MES_IC_VDS, IF_REAL ,"Initial D-S voltage"),
IOPAU("icvgs", MES_IC_VGS, IF_REAL ,"Initial G-S voltage"),
OPU("dnode", MES_DRAINNODE, IF_INTEGER,"Number of drain node"),

View File

@ -288,8 +288,8 @@ dot_dc(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
NG_IGNORE(gnode);
/* .dc SRC1NAME Vstart1 Vstop1 Vinc1 [SRC2NAME Vstart2 */
/* Vstop2 Vinc2 */
/* .dc SRC1NAME Vstart1 Vstop1 Vinc1 [SRC2NAME Vstart2 Vstop2 Vinc2]
Return 1 upon error because of bad syntax (missing tokens).*/
which = ft_find_analysis("DC");
if (which == -1) {
LITERR("DC transfer curve analysis unsupported\n");
@ -297,25 +297,43 @@ dot_dc(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
}
IFC(newAnalysis, (ckt, which, "DC transfer characteristic", &foo, task));
INPgetTok(&line, &name, 1);
if (*name == '\0')
return 1;
INPinsert(&name, tab);
ptemp.uValue = name;
GCA(INPapName, (ckt, which, foo, "name1", &ptemp));
if (*line == '\0')
return 1;
parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vstart1 */
GCA(INPapName, (ckt, which, foo, "start1", parm));
if (*line == '\0')
return 1;
parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vstop1 */
GCA(INPapName, (ckt, which, foo, "stop1", parm));
if (*line == '\0')
return 1;
parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vinc1 */
if (parm->rValue == 0)
return 1;
GCA(INPapName, (ckt, which, foo, "step1", parm));
if (*line) {
INPgetTok(&line, &name, 1);
if (*line == '\0')
return 1;
INPinsert(&name, tab);
ptemp.uValue = name;
GCA(INPapName, (ckt, which, foo, "name2", &ptemp));
parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vstart2 */
if (*line == '\0')
return 1;
GCA(INPapName, (ckt, which, foo, "start2", parm));
parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vstop2 */
if (*line == '\0')
return 1;
GCA(INPapName, (ckt, which, foo, "stop2", parm));
parm = INPgetValue(ckt, &line, IF_REAL, tab); /* vinc2 */
if (parm->rValue == 0)
return 1;
GCA(INPapName, (ckt, which, foo, "step2", parm));
}
return 0;
@ -861,6 +879,9 @@ INP2dot(CKTcircuit *ckt, INPtables *tab, struct card *current, TSKtask *task, CK
goto quit;
} else if ((strcmp(token, ".dc") == 0)) {
rtn = dot_dc(line, ckt, tab, current, task, gnode, foo);
if (rtn == 1) {
current->error = copy("Bad syntax! ");
}
goto quit;
} else if ((strcmp(token, ".tf") == 0)) {
rtn = dot_tf(line, ckt, tab, current, task, gnode, foo);

View File

@ -34,7 +34,7 @@ void INP2N(CKTcircuit *ckt, INPtables *tab, struct card *current) {
GENmodel *mdfast; /* Pointer to the actual model. */
IFdevice *dev;
CKTnode *node;
char *c, *token = NULL, *prev = NULL, *pprev = NULL;
char *c, *token = NULL, *prev = NULL, *pprev = NULL, *eqp;
int i;
line = current->line;
@ -44,15 +44,16 @@ void INP2N(CKTcircuit *ckt, INPtables *tab, struct card *current) {
/* Find the last non-parameter token in the line. */
c = line;
for (i = 0; *c != '\0'; ++i) {
for (i = 0, eqp = NULL; *c != '\0'; ++i) {
tfree(pprev);
pprev = prev;
prev = token;
token = gettok_instance(&c);
if (strchr(token, '='))
eqp = strchr(token, '=');
if (eqp)
break;
}
if (*c) {
if (eqp) {
tfree(token); // A parameter or starts with '='.
if (*c == '=') {
/* Now prev points to a parameter pprev is the model. */

View File

@ -292,7 +292,6 @@ INPgetModBin(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab, char
for (modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel) {
/* exact: 1, with binning extension .[0-9]: 2*/
if (model_name_match(name, modtmp->INPmodName) < 2)
continue;
@ -335,8 +334,8 @@ INPgetModBin(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab, char
*model = modtmp;
return NULL;
}
fprintf(stderr, "Warning: no model found for w=%.3e and l=%.3e\n", w, l);
}
return NULL;
}

View File

@ -25,6 +25,7 @@ if $?xspice_enabled
@XSPICEINIT@ codemodel @pkglibdir@/xtradev.cm
@XSPICEINIT@ codemodel @pkglibdir@/xtraevt.cm
@XSPICEINIT@ codemodel @pkglibdir@/table.cm
@XSPICEINIT@ codemodel @pkglibdir@/tlines.cm
end

View File

@ -40,6 +40,7 @@ INTERFACES
cm_irreversible()
cm_get_node_name()
cm_get_neg_node_name()
cm_probe_node()
REFERENCED FILES
@ -852,6 +853,33 @@ const char *cm_get_node_name(const char *port_name, unsigned int index)
return NULL;
}
/* Get the neg name of a circuit node connected to a port. */
const char* cm_get_neg_node_name(const char* port_name, unsigned int index)
{
MIFinstance* instance;
Mif_Conn_Data_t* conn;
Mif_Port_Data_t* port;
int i;
instance = g_mif_info.instance;
for (i = 0; i < instance->num_conn; ++i) {
conn = instance->conn[i];
if (!strcmp(port_name, conn->name)) {
if (index >= (unsigned int)conn->size)
return NULL;
port = conn->port[index];
if (port->type == MIF_DIGITAL || port->type == MIF_USER_DEFINED) {
/* Event node, no name in port data. */
return NULL;
}
return port->neg_node_str;
}
}
return NULL;
}
/* Test the resolved value of a connected Digital/UDN node, given
* an assumed value for a particular port.
*/

View File

@ -60,6 +60,7 @@ struct coreInfo_t coreInfo =
cm_netlist_get_l,
cm_irreversible,
cm_get_node_name,
cm_get_neg_node_name,
cm_probe_node,
cm_schedule_output,
cp_getvar,

View File

@ -7,11 +7,11 @@ include makedefs
# The codemodels to make
CMDIRS = spice2poly digital analog xtradev xtraevt table
CMDIRS = spice2poly digital analog xtradev xtraevt table tlines
#Invoke $(MAKE) for each of the CMDDIRS
all: dstring.o # One common dstring object file for all code modules
all: dstring.o msline_common.o tline_common.o# Common object files for all code modules
for cm in $(CMDIRS) ; do \
$(MAKE) cm=$$cm $$cm/$$cm.cm \
|| exit 1; \
@ -36,6 +36,8 @@ uninstall:
clean:
rm -f dstring.o
rm -f msline_common.o
rm -f tline_common.o
for cm in $(CMDIRS) ; do \
$(MAKE) cm=$$cm cm-clean \
|| exit 1; \
@ -49,6 +51,12 @@ NGSRCBUILDDIR = $(CURDIR)/../..
dstring.o: $(NGSRCDIR)/misc/dstring.c $(NGSRCDIR)/include/ngspice/dstring.h
$(CC) $(CFLAGS) -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $<
msline_common.o: $(srcdir)/../tlines/msline_common.c $(srcdir)/../tlines/msline_common.h
$(CC) $(CFLAGS) -I$(srcdir)/../tlines -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $<
tline_common.o: $(srcdir)/../tlines/tline_common.c $(srcdir)/../tlines/tline_common.h
$(CC) $(CFLAGS) -I$(srcdir)/../tlines -I$(NGSRCDIR)/include -I$(NGSRCBUILDDIR)/include -fPIC -o $@ -c $<
ifdef cm
ifeq ($(OS),Windows_NT)
@ -70,6 +78,8 @@ cm-gens := \
cm-objs := \
$(cm)/dlmain.o \
dstring.o \
tline_common.o \
msline_common.o \
$(modlst:%=$(cm)/%/cfunc.o) \
$(modlst:%=$(cm)/%/ifspec.o) \
$(udnlst:%=$(cm)/%/udnfunc.o)
@ -160,11 +170,11 @@ $(cm)/dlmain.o : $(srcdir)/dlmain.c $(cm-descr)
$(do-deps)
$(cm)/%/cfunc.o : $(cm)/%/cfunc.c
$(COMPILE) $(gen_pp) -I$(srcdir)/$(<D) -o $@ -c $<
$(COMPILE) $(gen_pp) -I$(srcdir)/$(<D) -I$(srcdir)/../tlines -o $@ -c $<
$(do-deps)
$(cm)/%/ifspec.o : $(cm)/%/ifspec.c
$(COMPILE) $(gen_pp) -I$(srcdir)/$(<D) -o $@ -c $<
$(COMPILE) $(gen_pp) -I$(srcdir)/$(<D) -I$(srcdir)/../tlines -o $@ -c $<
$(do-deps)
$(cm)/%/udnfunc.o : $(srcdir)/$(cm)/%/udnfunc.c

View File

@ -350,6 +350,10 @@ const char *cm_get_node_name(const char *port, unsigned int index) {
return coreitf->dllitf_cm_get_node_name(port, index);
}
const char *cm_get_neg_node_name(const char *port, unsigned int index) {
return coreitf->dllitf_cm_get_neg_node_name(port, index);
}
bool cm_probe_node(unsigned int conn_index,
unsigned int port_index,
void *value) {

View File

@ -0,0 +1,188 @@
/* ===========================================================================
FILE cfunc.mod
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#include "msline_common.h"
#include "tline_common.h"
static void copy_complex(double complex s, Complex_t *d)
{
d->real = creal(s);
d->imag = cimag(s);
}
//cpline_state_t *sim_points = NULL;
static void cm_cpline_callback(ARGS, Mif_Callback_Reason_t reason);
void cm_cpline (ARGS)
{
Complex_t z11, z12, z13, z14;
/* how to get properties of this component, e.g. L, W */
double l = PARAM(l);
double ze = PARAM(ze);
double zo = PARAM(zo);
double ere = PARAM(ere);
double ero = PARAM(ero);
double ae = PARAM(ae);
double ao = PARAM(ao);
ae = pow(10, 0.05*ae);
ao = pow(10, 0.05*ao);
if(INIT) {
CALLBACK = cm_cpline_callback;
STATIC_VAR(sim_points_data) = NULL;
}
/* Compute the output */
if(ANALYSIS == DC) {
double V1 = INPUT(p1s);
double V2 = INPUT(p2s);
double V3 = INPUT(p3s);
double V4 = INPUT(p4s);
double I1 = INPUT(p1);
double I2 = INPUT(p2);
double I3 = INPUT(p3);
double I4 = INPUT(p4);
double z = sqrt(ze*zo);
double V2out = V1 + z*I1;
double V1out = V2 + z*I2;
OUTPUT(p1) = V1out + I1*z;
OUTPUT(p2) = V2out + I2*z;
double V3out = V4 + z*I4;
double V4out = V3 + z*I3;
OUTPUT(p3) = V3out + I3*z;
OUTPUT(p4) = V4out + I4*z;
cm_analog_auto_partial();
}
else if(ANALYSIS == AC) {
double o = RAD_FREQ;
double complex _Z11, _Z12, _Z13, _Z14;
double complex arg_e = log(ae)*l/2.0 + I*o*l/C0*sqrt(ere);
double complex arg_o = log(ao)*l/2.0 + I*o*l/C0*sqrt(ero);
_Z11 = zo / (2*ctanh(arg_o)) + ze / (2*ctanh(arg_e));
_Z12 = zo / (2*csinh(arg_o)) + ze / (2*csinh(arg_e));
_Z13 = ze / (2*csinh(arg_e)) - zo / (2*csinh(arg_o));
_Z14 = ze / (2*ctanh(arg_e)) - zo / (2*ctanh(arg_o));
copy_complex(_Z11,&z11);
copy_complex(_Z12,&z12);
copy_complex(_Z13,&z13);
copy_complex(_Z14,&z14);
AC_GAIN(p1,p1) = z11; AC_GAIN(p2,p2) = z11;
AC_GAIN(p3,p3) = z11; AC_GAIN(p4,p4) = z11;
AC_GAIN(p1,p2) = z12; AC_GAIN(p2,p1) = z12;
AC_GAIN(p3,p4) = z12; AC_GAIN(p4,p3) = z12;
AC_GAIN(p1,p3) = z13; AC_GAIN(p3,p1) = z13;
AC_GAIN(p2,p4) = z13; AC_GAIN(p4,p2) = z13;
AC_GAIN(p1,p4) = z14; AC_GAIN(p4,p1) = z14;
AC_GAIN(p2,p3) = z14; AC_GAIN(p3,p2) = z14;
}
else if(ANALYSIS == TRANSIENT) {
double t = TIME;
double Vp[PORT_NUM];
double Ip[PORT_NUM];
Vp[0] = INPUT(p1s);
Vp[1] = INPUT(p2s);
Vp[2] = INPUT(p3s);
Vp[3] = INPUT(p4s);
Ip[0] = INPUT(p1);
Ip[1] = INPUT(p2);
Ip[2] = INPUT(p3);
Ip[3] = INPUT(p4);
double delay = l/(C0);
void **sim_points = &(STATIC_VAR(sim_points_data));
cpline_state_t *last = get_cpline_last_state(*(cpline_state_t **)sim_points);
double last_time = 0;
if (last != NULL) last_time = last->time;
if (TIME < last_time) {
delete_cpline_last_state((cpline_state_t **)sim_points);
}
append_cpline_state((cpline_state_t **)sim_points, t, Vp, Ip, 1.2*delay);
if (t > delay) {
cpline_state_t *pp = find_cpline_state(*(cpline_state_t **)sim_points, t - delay);
if (pp != NULL) {
double J1e = 0.5*(Ip[3] + Ip[0]);
double J1o = 0.5*(Ip[0] - Ip[3]);
double J2e = 0.5*(Ip[1] + Ip[2]);
double J2o = 0.5*(Ip[1] - Ip[2]);
double J1et = 0.5*(pp->Ip[3] + pp->Ip[0]);
double J1ot = 0.5*(pp->Ip[0] - pp->Ip[3]);
double J2et = 0.5*(pp->Ip[1] + pp->Ip[2]);
double J2ot = 0.5*(pp->Ip[1] - pp->Ip[2]);
double V1et = 0.5*(pp->Vp[3] + pp->Vp[0]);
double V1ot = 0.5*(pp->Vp[0] - pp->Vp[3]);
double V2et = 0.5*(pp->Vp[1] + pp->Vp[2]);
double V2ot = 0.5*(pp->Vp[1] - pp->Vp[2]);
double V1e = ze*J1e + V2et + ze*J2et;
double V1o = zo*J1o + V2ot + zo*J2ot;
double V2e = ze*J2e + V1et + ze*J1et;
double V2o = zo*J2o + V1ot + zo*J1ot;
double V1 = V1o + V1e;
double V2 = V2o + V2e;
double V3 = V2e - V2o;
double V4 = V1e - V1o;
OUTPUT(p1) = V1;
OUTPUT(p2) = V2;
OUTPUT(p3) = V3;
OUTPUT(p4) = V4;
}
cm_analog_auto_partial();
} else {
cm_analog_auto_partial();
}
}
}
static void cm_cpline_callback(ARGS, Mif_Callback_Reason_t reason)
{
switch (reason) {
case MIF_CB_DESTROY:
delete_cpline_states((cpline_state_t **)&(STATIC_VAR(sim_points_data)));
break;
default: break;
}
}

View File

@ -0,0 +1,191 @@
/* ===========================================================================
FILE ifspec.ifs
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Ports connection
4 --||||||-- 3
1 --||||||-- 2
*/
NAME_TABLE:
Spice_Model_Name: cpline
C_Function_Name: cm_cpline
Description: "Generic transmission line"
PORT_TABLE:
Port_Name: p1
Description: "Terminals Line1"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p2
Description: "Terminals Line1"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p3
Description: "Terminals Line2"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p4
Description: "Terminals Line2"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p1s
Description: "Sensing terminals line 1"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p2s
Description: "Sensing terminals line 1"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p3s
Description: "Sensing terminals line 1"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p4s
Description: "Sensing terminals line 1"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PARAMETER_TABLE:
Parameter_Name: l
Description: "length"
Data_Type: real
Default_Value: 1.0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: ze
Description: "characteristic impedance of even mode"
Data_Type: real
Default_Value: 50.0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: zo
Description: "characteristic impedance of odd mode"
Data_Type: real
Default_Value: 50.0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: ae
Description: "attenuation per length (dB) even mode"
Data_Type: real
Default_Value: 0.0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: ao
Description: "attenuation per length (dB) odd mode"
Data_Type: real
Default_Value: 0.0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: ere
Description: "dielectric constant even mode"
Data_Type: real
Default_Value: 1.0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: ero
Description: "dielectric constant odd mode"
Data_Type: real
Default_Value: 1.0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
STATIC_VAR_TABLE:
Static_Var_Name: sim_points_data
Description: "local static data"
Data_Type: pointer

View File

@ -0,0 +1,541 @@
/* ===========================================================================
FILE cfunc.mod
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#include "msline_common.h"
#include "tline_common.h"
static double ae, ao, be, bo, ze, zo, ee, eo;
static void copy_complex(double complex s, Complex_t *d)
{
d->real = creal(s);
d->imag = cimag(s);
}
//static cpline_state_t *state = NULL;
static void cm_cpmline_callback(ARGS, Mif_Callback_Reason_t reason);
static void analyseQuasiStatic (double W, double h, double s,
double t, double er,
int SModel, double* Zle,
double* Zlo, double* ErEffe,
double* ErEffo);
static void analyseDispersion (double W, double h, double s,
double t, double er, double Zle,
double Zlo, double ErEffe,
double ErEffo, double frequency,
int DModel, double *ZleFreq,
double *ZloFreq,
double *ErEffeFreq,
double *ErEffoFreq);
static void calcPropagation (double W, double s,
double er, double h, double t, double tand, double rho, double D,
int SModel, int DModel, double frequency)
{
// quasi-static analysis
double Zle, ErEffe, Zlo, ErEffo;
analyseQuasiStatic (W, h, s, t, er, SModel, &Zle, &Zlo, &ErEffe, &ErEffo);
// analyse dispersion of Zl and Er
double ZleFreq, ErEffeFreq, ZloFreq, ErEffoFreq;
analyseDispersion (W, h, s, t, er, Zle, Zlo, ErEffe, ErEffo, frequency, DModel,
&ZleFreq, &ZloFreq, &ErEffeFreq, &ErEffoFreq);
// analyse losses of line
double ace, aco, ade, ado;
analyseLoss (W, t, er, rho, D, tand, Zle, Zlo, ErEffe,
frequency, HAMMERSTAD, &ace, &ade);
analyseLoss (W, t, er, rho, D, tand, Zlo, Zle, ErEffo,
frequency, HAMMERSTAD, &aco, &ado);
// compute propagation constants for even and odd mode
double k0 = 2 * M_PI * frequency / C0;
ae = ace + ade;
ao = aco + ado;
be = sqrt (ErEffeFreq) * k0;
bo = sqrt (ErEffoFreq) * k0;
ze = ZleFreq;
zo = ZloFreq;
ee = ErEffeFreq;
eo = ErEffoFreq;
}
/* The function calculates the quasi-static dielectric constants and
characteristic impedances for the even and odd mode based upon the
given line and substrate properties for parallel coupled microstrip
lines. */
static void analyseQuasiStatic (double W, double h, double s,
double t, double er,
int SModel, double* Zle,
double* Zlo, double* ErEffe,
double* ErEffo) {
// initialize default return values
*ErEffe = er; *ErEffo = er;
*Zlo = 42.2; *Zle = 55.7;
// normalized width and gap
double u = W / h;
double g = s / h;
// HAMMERSTAD and JENSEN
if (SModel == HAMMERSTAD) {
double Zl1, Fe, Fo, a, b, fo, Mu, Alpha, Beta, ErEff;
double Pe, Po, r, fo1, q, p, n, Psi, Phi, m, Theta;
// modifying equations for even mode
m = 0.2175 + pow (4.113 + pow (20.36 / g, 6.), -0.251) +
log (pow (g, 10.) / (1 + pow (g / 13.8, 10.))) / 323;
Alpha = 0.5 * exp (-g);
Psi = 1 + g / 1.45 + pow (g, 2.09) / 3.95;
Phi = 0.8645 * pow (u, 0.172);
Pe = Phi / (Psi * (Alpha * pow (u, m) + (1 - Alpha) * pow (u, -m)));
// TODO: is this ... Psi * (Alpha ... or ... Psi / (Alpha ... ?
// modifying equations for odd mode
n = (1 / 17.7 + exp (-6.424 - 0.76 * log (g) - pow (g / 0.23, 5.))) *
log ((10 + 68.3 * sqr (g)) / (1 + 32.5 * pow (g, 3.093)));
Beta = 0.2306 + log (pow (g, 10.) / (1 + pow (g / 3.73, 10.))) / 301.8 +
log (1 + 0.646 * pow (g, 1.175)) / 5.3;
Theta = 1.729 + 1.175 * log (1 + 0.627 / (g + 0.327 * pow (g, 2.17)));
Po = Pe - Theta / Psi * exp (Beta * pow (u, -n) * log (u));
// further modifying equations
r = 1 + 0.15 * (1 - exp (1 - sqr (er - 1) / 8.2) / (1 + pow (g, -6.)));
fo1 = 1 - exp (-0.179 * pow (g, 0.15) -
0.328 * pow (g, r) / log (M_E + pow (g / 7, 2.8)));
q = exp (-1.366 - g);
p = exp (-0.745 * pow (g, 0.295)) / cosh (pow (g, 0.68));
fo = fo1 * exp (p * log (u) + q * sin (M_PI * log10 (u)));
Mu = g * exp (-g) + u * (20 + sqr (g)) / (10 + sqr (g));
Hammerstad_ab (Mu, er, &a, &b);
Fe = pow (1 + 10 / Mu, -a * b);
Hammerstad_ab (u, er, &a, &b);
Fo = fo * pow (1 + 10 / u, -a * b);
// finally compute effective dielectric constants and impedances
*ErEffe = (er + 1) / 2 + (er - 1) / 2 * Fe;
*ErEffo = (er + 1) / 2 + (er - 1) / 2 * Fo;
Hammerstad_er (u, er, a, b, &ErEff); // single microstrip
// first variant
Zl1 = Z0 / (u + 1.98 * pow (u, 0.172));
Zl1 /= sqrt (ErEff);
// second variant
Hammerstad_zl (u, &Zl1);
Zl1 /= sqrt (ErEff);
*Zle = Zl1 / (1 - Zl1 * Pe / Z0);
*Zlo = Zl1 / (1 - Zl1 * Po / Z0);
}
// KIRSCHNING and JANSEN
else if (SModel == KIRSCHING) {
double a, b, ae, be, ao, bo, v, co, d, ErEff, Zl1;
double q1, q2, q3, q4, q5, q6, q7, q8, q9, q10;
// consider effect of finite strip thickness (JANSEN only)
double ue = u;
double uo = u;
if (t != 0 && s > 10 * (2 * t)) {
double dW = 0;
// SCHNEIDER, referred by JANSEN
if (u >= M_1_PI / 2 && M_1_PI / 2 > 2 * t / h)
dW = t * (1 + log (2 * h / t)) / M_PI;
else if (W > 2 * t)
dW = t * (1 + log (4 * M_PI * W / t)) / M_PI;
// JANSEN
double dt = 2 * t * h / s / er;
double We = W + dW * (1 - 0.5 * exp (-0.69 * dW / dt));
double Wo = We + dt;
ue = We / h;
uo = Wo / h;
}
// even relative dielectric constant
v = ue * (20 + sqr (g)) / (10 + sqr (g)) + g * exp (-g);
Hammerstad_ab (v, er, &ae, &be);
Hammerstad_er (v, er, ae, be, ErEffe);
// odd relative dielectric constant
Hammerstad_ab (uo, er, &a, &b);
Hammerstad_er (uo, er, a, b, &ErEff);
d = 0.593 + 0.694 * exp (-0.562 * uo);
bo = 0.747 * er / (0.15 + er);
co = bo - (bo - 0.207) * exp (-0.414 * uo);
ao = 0.7287 * (ErEff - (er + 1) / 2) * (1 - exp (-0.179 * uo));
*ErEffo = ((er + 1) / 2 + ao - ErEff) * exp (-co * pow (g, d)) + ErEff;
// characteristic impedance of single line
Hammerstad_zl (u, &Zl1);
Zl1 /= sqrt (ErEff);
// even characteristic impedance
q1 = 0.8695 * pow (ue, 0.194);
q2 = 1 + 0.7519 * g + 0.189 * pow (g, 2.31);
q3 = 0.1975 + pow (16.6 + pow (8.4 / g, 6.), -0.387) +
log (pow (g, 10.) / (1 + pow (g / 3.4, 10.))) / 241;
q4 = q1 / q2 * 2 /
(exp (-g) * pow (ue, q3) + (2 - exp (-g)) * pow (ue, -q3));
*Zle = sqrt (ErEff / *ErEffe) * Zl1 / (1 - Zl1 * sqrt (ErEff) * q4 / Z0);
// odd characteristic impedance
q5 = 1.794 + 1.14 * log (1 + 0.638 / (g + 0.517 * pow (g, 2.43)));
q6 = 0.2305 + log (pow (g, 10.) / (1 + pow (g / 5.8, 10.))) / 281.3 +
log (1 + 0.598 * pow (g, 1.154)) / 5.1;
q7 = (10 + 190 * sqr (g)) / (1 + 82.3 * cubic (g));
q8 = exp (-6.5 - 0.95 * log (g) - pow (g / 0.15, 5.));
q9 = log (q7) * (q8 + 1 / 16.5);
q10 = (q2 * q4 - q5 * exp (log (uo) * q6 * pow (uo, -q9))) / q2;
*Zlo = sqrt (ErEff / *ErEffo) * Zl1 / (1 - Zl1 * sqrt (ErEff) * q10 / Z0);
}
}
/* The function computes the dispersion effects on the dielectric
constants and characteristic impedances for the even and odd mode
of parallel coupled microstrip lines. */
static void analyseDispersion (double W, double h, double s,
double t, double er, double Zle,
double Zlo, double ErEffe,
double ErEffo, double frequency,
int DModel, double *ZleFreq,
double *ZloFreq,
double *ErEffeFreq,
double *ErEffoFreq) {
// initialize default return values
*ZleFreq = Zle;
*ErEffeFreq = ErEffe;
*ZloFreq = Zlo;
*ErEffoFreq = ErEffo;
// normalized width and gap
double u = W / h;
double g = s / h;
double ue, uo;
double B, dW, dt;
// compute u_odd, u_even
if (t > 0.0) {
if (u < 0.1592) {
B = 2 * M_PI * W;
} else {
B = h;
}
dW = t * (1.0 + log(2 * B / t)) / M_PI;
dt = t / (er * g);
ue = (W + dW * (1.0 - 0.5 * exp( -0.69 * dW / dt ))) / h;
uo = ue + dt / h;
} else {
ue = u;
uo = u;
}
// GETSINGER
if (DModel == GETSINGER) {
// even mode dispersion
Getsinger_disp (h, er, ErEffe, Zle / 2,
frequency, ErEffeFreq, ZleFreq);
*ZleFreq *= 2;
// odd mode dispersion
Getsinger_disp (h, er, ErEffo, Zlo * 2,
frequency, ErEffoFreq, ZloFreq);
*ZloFreq /= 2;
}
// KIRSCHNING and JANSEN
else if (DModel == DISP_KIRSCHING) {
double p1, p2, p3, p4, p5, p6, p7, Fe;
double fn = frequency * h * 1e-6;
// even relative dielectric constant dispersion
p1 = 0.27488 * (0.6315 + 0.525 / pow (1 + 0.0157 * fn, 20.)) * ue -
0.065683 * exp (-8.7513 * ue);
p2 = 0.33622 * (1 - exp (-0.03442 * er));
p3 = 0.0363 * exp (-4.6 * ue) * (1 - exp (- pow (fn / 38.7, 4.97)));
p4 = 1 + 2.751 * (1 - exp (- pow (er / 15.916, 8.)));
p5 = 0.334 * exp (-3.3 * cubic (er / 15)) + 0.746;
p6 = p5 * exp (- pow (fn / 18, 0.368));
p7 = 1 + 4.069 * p6 * pow (g, 0.479) *
exp (-1.347 * pow (g, 0.595) - 0.17 * pow (g, 2.5));
Fe = p1 * p2 * pow ((p3 * p4 + 0.1844 * p7) * fn, 1.5763);
*ErEffeFreq = er - (er - ErEffe) / (1 + Fe);
// odd relative dielectric constant dispersion
double p8, p9, p10, p11, p12, p13, p14, p15, Fo;
p1 = 0.27488 * (0.6315 + 0.525 / pow (1 + 0.0157 * fn, 20.)) * uo -
0.065683 * exp (-8.7513 * uo);
p3 = 0.0363 * exp (-4.6 * uo) * (1 - exp (- pow (fn / 38.7, 4.97)));
p8 = 0.7168 * (1 + 1.076 / (1 + 0.0576 * (er - 1)));
p9 = p8 - 0.7913 * (1 - exp (- pow (fn / 20, 1.424))) *
atan (2.481 * pow (er / 8, 0.946));
p10 = 0.242 * pow (er - 1, 0.55);
p11 = 0.6366 * (exp (-0.3401 * fn) - 1) *
atan (1.263 * pow (uo / 3, 1.629));
p12 = p9 + (1 - p9) / (1 + 1.183 * pow (uo, 1.376));
p13 = 1.695 * p10 / (0.414 + 1.605 * p10);
p14 = 0.8928 + 0.1072 * (1 - exp (-0.42 * pow (fn / 20, 3.215)));
p15 = fabs (1 - 0.8928 * (1 + p11) *
exp (-p13 * pow (g, 1.092)) * p12 / p14);
Fo = p1 * p2 * pow ((p3 * p4 + 0.1844) * fn * p15, 1.5763);
*ErEffoFreq = er - (er - ErEffo) / (1 + Fo);
// dispersion of even characteristic impedance
double t, q11, q12, q13, q14, q15, q16, q17, q18, q19, q20, q21;
q11 = 0.893 * (1 - 0.3 / (1 + 0.7 * (er - 1)));
t = pow (fn / 20, 4.91);
q12 = 2.121 * t / (1 + q11 * t) * exp (-2.87 * g) * pow (g, 0.902);
q13 = 1 + 0.038 * pow (er / 8, 5.1);
t = quadr (er / 15);
q14 = 1 + 1.203 * t / (1 + t);
q15 = 1.887 * exp (-1.5 * pow (g, 0.84)) * pow (g, q14) /
(1 + 0.41 * pow (fn / 15, 3.) *
pow (u, 2 / q13) / (0.125 + pow (u, 1.626 / q13)));
q16 = q15 * (1 + 9 / (1 + 0.403 * sqr (er - 1)));
q17 = 0.394 * (1 - exp (-1.47 * pow (u / 7, 0.672))) *
(1 - exp (-4.25 * pow (fn / 20, 1.87)));
q18 = 0.61 * (1 - exp (-2.31 * pow (u / 8, 1.593))) /
(1 + 6.544 * pow (g, 4.17));
q19 = 0.21 * quadr (g) / (1 + 0.18 * pow (g, 4.9)) / (1 + 0.1 * sqr (u)) /
(1 + pow (fn / 24, 3.));
q20 = q19 * (0.09 + 1 / (1 + 0.1 * pow (er - 1, 2.7)));
t = pow (u, 2.5);
q21 = fabs (1 - 42.54 * pow (g, 0.133) * exp (-0.812 * g) * t /
(1 + 0.033 * t));
double re, qe, pe, de, Ce, q0, ZlFreq, ErEffFreq;
Kirschning_er (u, fn, er, ErEffe, &ErEffFreq);
Kirschning_zl (u, fn, er, ErEffe, ErEffFreq, Zle, &q0, &ZlFreq);
re = pow (fn / 28.843, 12.);
qe = 0.016 + pow (0.0514 * er * q21, 4.524);
pe = 4.766 * exp (-3.228 * pow (u, 0.641));
t = pow (er - 1, 6.);
de = 5.086 * qe * re / (0.3838 + 0.386 * qe) *
exp (-22.2 * pow (u, 1.92)) / (1 + 1.2992 * re) * t / (1 + 10 * t);
Ce = 1 + 1.275 * (1 - exp (-0.004625 * pe * pow (er, 1.674) *
pow (fn / 18.365, 2.745))) - q12 + q16 - q17 + q18 + q20;
*ZleFreq = Zle * pow ((0.9408 * pow (ErEffFreq, Ce) - 0.9603) /
((0.9408 - de) * pow (ErEffe, Ce) - 0.9603), q0);
// dispersion of odd characteristic impedance
double q22, q23, q24, q25, q26, q27, q28, q29;
Kirschning_er (u, fn, er, ErEffo, &ErEffFreq);
Kirschning_zl (u, fn, er, ErEffo, ErEffFreq, Zlo, &q0, &ZlFreq);
q29 = 15.16 / (1 + 0.196 * sqr (er - 1));
t = sqr (er - 1);
q25 = 0.3 * sqr (fn) / (10 + sqr (fn)) * (1 + 2.333 * t / (5 + t));
t = pow ((er - 1) / 13, 12.);
q26 = 30 - 22.2 * t / (1 + 3 * t) - q29;
t = pow (er - 1, 1.5);
q27 = 0.4 * pow (g, 0.84) * (1 + 2.5 * t / (5 + t));
t = pow (er - 1, 3.);
q28 = 0.149 * t / (94.5 + 0.038 * t);
q22 = 0.925 * pow (fn / q26, 1.536) / (1 + 0.3 * pow (fn / 30, 1.536));
q23 = 1 + 0.005 * fn * q27 / (1 + 0.812 * pow (fn / 15, 1.9)) /
(1 + 0.025 * sqr (u));
t = pow (u, 0.894);
q24 = 2.506 * q28 * t / (3.575 + t) *
pow ((1 + 1.3 * u) * fn / 99.25, 4.29);
*ZloFreq = ZlFreq + (Zlo * pow (*ErEffoFreq / ErEffo, q22) - ZlFreq * q23) /
(1 + q24 + pow (0.46 * g, 2.2) * q25);
}
}
void cm_cpmline (ARGS)
{
Complex_t z11, z12, z13, z14;
/* how to get properties of this component, e.g. L, W */
double W = PARAM(w);
double l = PARAM(l);
double s = PARAM(s);
int SModel = PARAM(model);
int DModel = PARAM(disp);
int TModel = PARAM(tranmodel);
/* how to get properties of the substrate, e.g. Er, H */
double er = PARAM(er);
double h = PARAM(h);
double t = PARAM(t);
double tand = PARAM(tand);
double rho = PARAM(rho);
double D = PARAM(d);
if(INIT) {
CALLBACK = cm_cpmline_callback;
STATIC_VAR(sim_points_data) = NULL;
}
/* Compute the output */
if(ANALYSIS == DC) {
calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel,0);
double V1 = INPUT(p1s);
double V2 = INPUT(p2s);
double V3 = INPUT(p3s);
double V4 = INPUT(p4s);
double I1 = INPUT(p1);
double I2 = INPUT(p2);
double I3 = INPUT(p3);
double I4 = INPUT(p4);
double z = sqrt(ze*zo);
double V2out = V1 + z*I1;
double V1out = V2 + z*I2;
OUTPUT(p1) = V1out + I1*z;
OUTPUT(p2) = V2out + I2*z;
double V3out = V4 + z*I4;
double V4out = V3 + z*I3;
OUTPUT(p3) = V3out + I3*z;
OUTPUT(p4) = V4out + I4*z;
cm_analog_auto_partial();
}
else if(ANALYSIS == AC) {
double o = RAD_FREQ;
calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel, o/(2*M_PI));
double complex _Z11, _Z12, _Z13, _Z14;
double complex ge = ae + I*be;
double complex go = ao + I*bo;
_Z11 = zo / (2*ctanh(go*l)) + ze / (2*ctanh(ge*l));
_Z12 = zo / (2*csinh(go*l)) + ze / (2*csinh(ge*l));
_Z13 = ze / (2*csinh(ge*l)) - zo / (2*csinh(go*l));
_Z14 = ze / (2*ctanh(ge*l)) - zo / (2*ctanh(go*l));
copy_complex(_Z11,&z11);
copy_complex(_Z12,&z12);
copy_complex(_Z13,&z13);
copy_complex(_Z14,&z14);
AC_GAIN(p1,p1) = z11; AC_GAIN(p2,p2) = z11;
AC_GAIN(p3,p3) = z11; AC_GAIN(p4,p4) = z11;
AC_GAIN(p1,p2) = z12; AC_GAIN(p2,p1) = z12;
AC_GAIN(p3,p4) = z12; AC_GAIN(p4,p3) = z12;
AC_GAIN(p1,p3) = z13; AC_GAIN(p3,p1) = z13;
AC_GAIN(p2,p4) = z13; AC_GAIN(p4,p2) = z13;
AC_GAIN(p1,p4) = z14; AC_GAIN(p4,p1) = z14;
AC_GAIN(p2,p3) = z14; AC_GAIN(p3,p2) = z14;
}
else if(ANALYSIS == TRANSIENT) {
calcPropagation(W,s,er,h,t,tand,rho,D,SModel,DModel,0);
double t = TIME;
double Vp[PORT_NUM];
double Ip[PORT_NUM];
double Vnew[PORT_NUM];
Vp[0] = INPUT(p1s);
Vp[1] = INPUT(p2s);
Vp[2] = INPUT(p3s);
Vp[3] = INPUT(p4s);
Ip[0] = INPUT(p1);
Ip[1] = INPUT(p2);
Ip[2] = INPUT(p3);
Ip[3] = INPUT(p4);
double delay = l/(C0);
void **sim_points = &(STATIC_VAR(sim_points_data));
if (TModel == TRAN_FULL) {
cpline_state_t *last = get_cpline_last_state(*(cpline_state_t **)sim_points);
double last_time = 0;
if (last != NULL) last_time = last->time;
if (TIME < last_time) {
delete_cpline_last_state((cpline_state_t **)sim_points);
}
append_cpline_state((cpline_state_t **)sim_points, t, Vp, Ip, 1.2*delay);
}
if (t > delay && TModel == TRAN_FULL) {
cpline_state_t *pp = find_cpline_state(*(cpline_state_t **)sim_points, t - delay);
if (pp != NULL) {
double J1e = 0.5*(Ip[3] + Ip[0]);
double J1o = 0.5*(Ip[0] - Ip[3]);
double J2e = 0.5*(Ip[1] + Ip[2]);
double J2o = 0.5*(Ip[1] - Ip[2]);
double J1et = 0.5*(pp->Ip[3] + pp->Ip[0]);
double J1ot = 0.5*(pp->Ip[0] - pp->Ip[3]);
double J2et = 0.5*(pp->Ip[1] + pp->Ip[2]);
double J2ot = 0.5*(pp->Ip[1] - pp->Ip[2]);
double V1et = 0.5*(pp->Vp[3] + pp->Vp[0]);
double V1ot = 0.5*(pp->Vp[0] - pp->Vp[3]);
double V2et = 0.5*(pp->Vp[1] + pp->Vp[2]);
double V2ot = 0.5*(pp->Vp[1] - pp->Vp[2]);
double V1e = ze*J1e + V2et + ze*J2et;
double V1o = zo*J1o + V2ot + zo*J2ot;
double V2e = ze*J2e + V1et + ze*J1et;
double V2o = zo*J2o + V1ot + zo*J1ot;
double V1 = V1o + V1e;
double V2 = V2o + V2e;
double V3 = V2e - V2o;
double V4 = V1e - V1o;
OUTPUT(p1) = V1;
OUTPUT(p2) = V2;
OUTPUT(p3) = V3;
OUTPUT(p4) = V4;
}
cm_analog_auto_partial();
} else {
double z = sqrt(ze*zo);
double V2out = Vp[0] + z*Ip[0];
double V1out = Vp[1] + z*Ip[1];
OUTPUT(p1) = V1out + Ip[0]*z;
OUTPUT(p2) = V2out + Ip[1]*z;
double V3out = Vp[3] + z*Ip[3];
double V4out = Vp[2] + z*Ip[2];
OUTPUT(p3) = V3out + Ip[2]*z;
OUTPUT(p4) = V4out + Ip[3]*z;
cm_analog_auto_partial();
}
}
}
static void cm_cpmline_callback(ARGS, Mif_Callback_Reason_t reason)
{
switch (reason) {
case MIF_CB_DESTROY:
delete_cpline_states((cpline_state_t **)&(STATIC_VAR(sim_points_data)));
break;
default: break;
}
}

View File

@ -0,0 +1,241 @@
/* ===========================================================================
FILE ifspec.ifs
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Ports connection
4 --||||||-- 3
1 --||||||-- 2
*/
NAME_TABLE:
Spice_Model_Name: cpmlin
C_Function_Name: cm_cpmline
Description: "Generic transmission line"
PORT_TABLE:
Port_Name: p1
Description: "Terminals Line1"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p2
Description: "Terminals Line1"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p3
Description: "Terminals Line2"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p4
Description: "Terminals Line2"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p1s
Description: "Sensing terminals line 1"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p2s
Description: "Sensing terminals line 1"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p3s
Description: "Sensing terminals line 1"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: p4s
Description: "Sensing terminals line 1"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PARAMETER_TABLE:
Parameter_Name: l
Description: "length"
Data_Type: real
Default_Value: 1.0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: w
Description: "width"
Data_Type: real
Default_Value: 1e-3
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: s
Description: "gap"
Data_Type: real
Default_Value: 1e-3
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: model
Description: "Model type"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: disp
Description: "Dispersion type"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: er
Description: "Substrate dielectric permittivity"
Data_Type: real
Default_Value: 9.8
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: h
Description: "Substrate thickness"
Data_Type: real
Default_Value: 1e-3
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: t
Description: "Metal strip thickness"
Data_Type: real
Default_Value: 35e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: tand
Description: "Substrate dielectric loss"
Data_Type: real
Default_Value: 2e-4
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: rho
Description: "Metal resistance"
Data_Type: real
Default_Value: 0.022e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: d
Description: "RMS Substrate roughness"
Data_Type: real
Default_Value: 0.15e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: tranmodel
Description: "TRAN model DC/FULL"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
STATIC_VAR_TABLE:
Static_Var_Name: sim_points_data
Description: "local static data"
Data_Type: pointer

View File

@ -0,0 +1,166 @@
/* ===========================================================================
FILE cfunc.mod
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <math.h>
#include <complex.h>
#include "tline_common.h"
#include "msline_common.h"
//static tline_state_t *sim_points = NULL;
static double zl, alpha, beta, ereff;
static void cm_mline_callback(ARGS, Mif_Callback_Reason_t reason);
static void calcPropagation (double W, int SModel, int DModel,
double er, double h, double t, double tand, double rho, double D,
double frequency) {
/* local variables */
double ac, ad;
double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq;
// quasi-static effective dielectric constant of substrate + line and
// the impedance of the microstrip line
mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff);
// analyse dispersion of Zl and Er (use WEff here?)
mslineAnalyseDispersion (W, h, er, ZlEff, ErEff, frequency, DModel,
&ZlEffFreq, &ErEffFreq);
// analyse losses of line
analyseLoss (W, t, er, rho, D, tand, ZlEff, ZlEff, ErEff,
frequency, HAMMERSTAD, &ac, &ad);
// calculate propagation constants and reference impedance
zl = ZlEffFreq;
ereff = ErEffFreq;
alpha = ac + ad;
beta = sqrt (ErEffFreq) * 2 * M_PI * frequency / C0;
}
void cm_mlin (ARGS)
{
Complex_t z11, z21;
void **sim_points;
/* how to get properties of this component, e.g. L, W */
double W = PARAM(w);
double l = PARAM(l);
int SModel = PARAM(model);
int DModel = PARAM(disp);
int TModel = PARAM(tranmodel);
/* how to get properties of the substrate, e.g. Er, H */
double er = PARAM(er);
double h = PARAM(h);
double t = PARAM(t);
double tand = PARAM(tand);
double rho = PARAM(rho);
double D = PARAM(d);
/* Initialize/access instance specific storage for capacitor voltage */
if(INIT) {
CALLBACK = cm_mline_callback;
STATIC_VAR(sim_points_data) = NULL;
}
/* Compute the output */
if(ANALYSIS == DC) {
calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,0);
double V1 = INPUT(V1sens);
double V2 = INPUT(V2sens);
double I1 = INPUT(port1);
double I2 = INPUT(port2);
double V2out = V1 + zl*I1;
double V1out = V2 + zl*I2;
OUTPUT(port1) = V1out + I1*zl;
OUTPUT(port2) = V2out + I2*zl;
cm_analog_auto_partial();
}
else if(ANALYSIS == AC) {
double frequency = RAD_FREQ/(2.0*M_PI);
calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,frequency);
double complex g = alpha + beta*I;
double complex _Z11 = zl / ctanh(g*l);
double complex _Z21 = zl / csinh(g*l);
z11.real = creal(_Z11); z11.imag = cimag(_Z11);
z21.real = creal(_Z21); z21.imag = cimag(_Z21);
AC_GAIN(port1,port1) = z11; AC_GAIN(port2,port2) = z11;
AC_GAIN(port1,port2) = z21; AC_GAIN(port2,port1) = z21;
}
else if(ANALYSIS == TRANSIENT) {
calcPropagation(W,SModel,DModel,er,h,t,tand,rho,D,0);
sim_points = &(STATIC_VAR(sim_points_data));
double t = TIME;
double V1 = INPUT(V1sens);
double V2 = INPUT(V2sens);
double I1 = INPUT(port1);
double I2 = INPUT(port2);
double delay = l/(C0) * sqrt(ereff);
if (TModel == TRAN_FULL) {
tline_state_t *last = get_tline_last_state(*(tline_state_t **)sim_points);
double last_time = 0;
if (last != NULL) last_time = last->time;
if (TIME < last_time) {
//fprintf(stderr,"Rollbacki time=%g\n",TIME);
delete_tline_last_state((tline_state_t **)sim_points);
}
append_state((tline_state_t **)sim_points, t, V1, V2, I1, I2, 1.2*delay);
}
if (t > delay && TModel == TRAN_FULL) {
tline_state_t *pp = get_state(*(tline_state_t **)sim_points, t - delay);
if (pp != NULL) {
double V2out = pp->V1 + zl*(pp->I1);
double V1out = pp->V2 + zl*(pp->I2);
OUTPUT(port1) = V1out + I1*zl;
OUTPUT(port2) = V2out + I2*zl;
}
cm_analog_auto_partial();
} else {
double V2out = V1 + zl*I1;
double V1out = V2 + zl*I2;
OUTPUT(port1) = V1out + I1*zl;
OUTPUT(port2) = V2out + I2*zl;
cm_analog_auto_partial();
}
}
}
static void cm_mline_callback(ARGS, Mif_Callback_Reason_t reason)
{
switch (reason) {
case MIF_CB_DESTROY:
delete_tline_states((tline_state_t **)&(STATIC_VAR(sim_points_data)));
break;
default: break;
}
}

View File

@ -0,0 +1,186 @@
/* ===========================================================================
FILE ifspec.ifs
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
NAME_TABLE:
Spice_Model_Name: mlin
C_Function_Name: cm_mlin
Description: "Microstrip line"
PORT_TABLE:
Port_Name: port1
Description: "Microstrip terminals"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: port2
Description: "Microstrip terminals"
Direction: inout
Default_Type: hd
Allowed_Types: [hd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: V1sens
Description: "Sensing terminals"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PORT_TABLE:
Port_Name: V2sens
Description: "Sensisng terminals"
Direction: in
Default_Type: vd
Allowed_Types: [vd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PARAMETER_TABLE:
Parameter_Name: l
Description: "length"
Data_Type: real
Default_Value: 1e-2
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: w
Description: "width"
Data_Type: real
Default_Value: 1e-3
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: model
Description: "Model type"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: disp
Description: "Dispersion type"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: er
Description: "Substrate dielectric permittivity"
Data_Type: real
Default_Value: 9.8
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: h
Description: "Substrate thickness"
Data_Type: real
Default_Value: 1e-3
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: t
Description: "Metal strip thickness"
Data_Type: real
Default_Value: 35e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: tand
Description: "Substrate dielectric loss"
Data_Type: real
Default_Value: 2e-4
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: rho
Description: "Metal resistance"
Data_Type: real
Default_Value: 0.022e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: d
Description: "RMS Substrate roughness"
Data_Type: real
Default_Value: 0.15e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: tranmodel
Description: "TRAN model DC/FULL"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
STATIC_VAR_TABLE:
Static_Var_Name: sim_points_data
Description: "local static data"
Data_Type: pointer

View File

@ -0,0 +1,5 @@
mlin
tline
cpline
cpmlin
msopen

View File

@ -0,0 +1,120 @@
/* ===========================================================================
FILE cfunc.mod
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <math.h>
#include <complex.h>
#include <stdio.h>
#include "msline_common.h"
#include "tline_common.h"
#define MSOPEN_KIRSCHNING 0
#define MSOPEN_HAMMERSTAD 1
#define MSOPEN_ALEXOPOULOS 2
// Returns the microstrip open end capacitance.
static double calcCend (double frequency, double W,
double h, double t, double er,
int SModel, int DModel,
int Model) {
double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq;
mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff);
mslineAnalyseDispersion (WEff, h, er, ZlEff, ErEff, frequency, DModel,
&ZlEffFreq, &ErEffFreq);
W /= h;
double dl = 0;
/* Kirschning, Jansen and Koster */
if (Model == MSOPEN_KIRSCHNING) {
double Q6 = pow (ErEffFreq, 0.81);
double Q7 = pow (W, 0.8544);
double Q1 = 0.434907 *
(Q6 + 0.26) / (Q6 - 0.189) * (Q7 + 0.236) / (Q7 + 0.87);
double Q2 = pow (W, 0.371) / (2.358 * er + 1.0) + 1.0;
double Q3 = atan (0.084 * pow (W, 1.9413 / Q2)) *
0.5274 / pow (ErEffFreq, 0.9236) + 1.0;
double Q4 = 0.0377 * (6.0 - 5.0 * exp (0.036 * (1.0 - er))) *
atan (0.067 * pow (W, 1.456)) + 1.0;
double Q5 = 1.0 - 0.218 * exp (-7.5 * W);
dl = Q1 * Q3 * Q5 / Q4;
}
/* Hammerstad */
else if (Model == MSOPEN_HAMMERSTAD) {
dl = 0.102 * (W + 0.106) / (W + 0.264) *
(1.166 + (er + 1) / er * (0.9 + log (W + 2.475)));
}
return dl * h * sqrt (ErEffFreq) / C0 / ZlEffFreq;
}
void cm_msopen (ARGS)
{
Complex_t ac_gain;
/* how to get properties of this component, e.g. L, W */
double W = PARAM(w);
int SModel = PARAM(model);
int DModel = PARAM(disp);
int Model = PARAM(msopen_model);
/* how to get properties of the substrate, e.g. Er, H */
double er = PARAM(er);
double h = PARAM(h);
double t = PARAM(t);
/* Compute the output */
if(ANALYSIS == AC) {
if (Model == MSOPEN_ALEXOPOULOS) {
double ZlEff, ErEff, WEff, ZlEffFreq, ErEffFreq;
mslineAnalyseQuasiStatic (W, h, t, er, SModel, &ZlEff, &ErEff, &WEff);
mslineAnalyseDispersion (WEff, h, er, ZlEff, ErEff, RAD_FREQ/(2*M_PI), DModel,
&ZlEffFreq, &ErEffFreq);
if (fabs (er - 9.9) > 0.2) {
fprintf (stderr, "WARNING: Model for microstrip open end defined "
"for er = 9.9 (er = %g)\n", er);
}
double c1, c2, l2, r2;
c1 = (1.125 * tanh (1.358 * W / h) - 0.315) *
h / 2.54e-5 / 25 / ZlEffFreq * 1e-12;
c2 = (6.832 * tanh (0.0109 * W / h) + 0.919) *
h / 2.54e-5 / 25 / ZlEffFreq * 1e-12;
l2 = (0.008285 * tanh (0.5665 * W / h) + 0.0103) *
h / 2.54e-5 / 25 * ZlEffFreq * 1e-9;
r2 = (1.024 * tanh (2.025 * W / h)) * ZlEffFreq;
double complex d1 = 0 + I*c1 * RAD_FREQ;
double complex d2 = r2 + I*(l2 * RAD_FREQ - 1.0 / c2 / RAD_FREQ);
double complex y = d1 + 1.0/d2;
ac_gain.real = creal(y);
ac_gain.imag = cimag(y);
AC_GAIN(p1, p1) = ac_gain;
} else {
double Ce = calcCend(RAD_FREQ/(2*M_PI), W, h, t, er, SModel, DModel, Model);
ac_gain.real = 0.0;
ac_gain.imag = RAD_FREQ * Ce;
AC_GAIN(p1, p1) = ac_gain;
}
}
}

View File

@ -0,0 +1,140 @@
/* ===========================================================================
FILE ifspec.ifs
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
NAME_TABLE:
Spice_Model_Name: msopen
C_Function_Name: cm_msopen
Description: "Microstrip open end"
PORT_TABLE:
Port_Name: p1
Description: "terminals"
Direction: inout
Default_Type: gd
Allowed_Types: [gd]
Vector: no
Vector_Bounds: -
Null_Allowed: no
PARAMETER_TABLE:
Parameter_Name: w
Description: "width"
Data_Type: real
Default_Value: 1e-3
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: model
Description: "Model type"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: disp
Description: "Dispersion type"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: msopen_model
Description: "MSOpen model"
Data_Type: int
Default_Value: 0
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: er
Description: "Substrate dielectric permittivity"
Data_Type: real
Default_Value: 9.8
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: h
Description: "Substrate thickness"
Data_Type: real
Default_Value: 1e-3
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: t
Description: "Metal strip thickness"
Data_Type: real
Default_Value: 35e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: tand
Description: "Substrate dielectric loss"
Data_Type: real
Default_Value: 2e-4
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: rho
Description: "Metal resistance"
Data_Type: real
Default_Value: 0.022e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes
PARAMETER_TABLE:
Parameter_Name: d
Description: "RMS Substrate roughness"
Data_Type: real
Default_Value: 0.15e-6
Limits: -
Vector: no
Vector_Bounds: -
Null_Allowed: yes

View File

@ -0,0 +1,124 @@
/* ===========================================================================
FILE cfunc.mod
Copyright 2025 Vadim Kuznetsov
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <math.h>
#include <complex.h>
#include "msline_common.h"
#include "tline_common.h"
//static tline_state_t *sim_points = NULL;
static void cm_tline_callback(ARGS, Mif_Callback_Reason_t reason);
void cm_tline (ARGS)
{
Complex_t z11, z21;
void **sim_points;
/* how to get properties of this component, e.g. L, W */
double z = PARAM(z);
double l = PARAM(l);
double a = PARAM(a);
double alpha = pow(10,0.05*a);
alpha = log(alpha)/2.0;
/* Initialize/access instance specific storage for capacitor voltage */
if(INIT) {
CALLBACK = cm_tline_callback;
STATIC_VAR(sim_points_data) = NULL;
}
/* Compute the output */
if(ANALYSIS == DC) {
double V1 = INPUT(V1sens);
double V2 = INPUT(V2sens);
double I1 = INPUT(in);
double I2 = INPUT(out);
double V2out = V1 + z*I1;
double V1out = V2 + z*I2;
OUTPUT(in) = V1out + I1*z;
OUTPUT(out) = V2out + I2*z;
cm_analog_auto_partial();
}
else if(ANALYSIS == AC) {
double beta = RAD_FREQ/C0;
double complex g = alpha + beta*I;
double complex _Z11 = z / ctanh(g*l);
double complex _Z21 = z / csinh (g*l);
z11.real = creal(_Z11);
z11.imag = cimag(_Z11);
z21.real = creal(_Z21);
z21.imag = cimag(_Z21);
AC_GAIN(in, in) = z11; AC_GAIN(out,out) = z11;
AC_GAIN(in,out) = z21; AC_GAIN(out,in) = z21;
}
else if(ANALYSIS == TRANSIENT) {
sim_points = &(STATIC_VAR(sim_points_data));
double t = TIME;
double V1 = INPUT(V1sens);
double V2 = INPUT(V2sens);
double I1 = INPUT(in);
double I2 = INPUT(out);
double delay = l/(C0);
tline_state_t *last = get_tline_last_state(*(tline_state_t **)sim_points);
double last_time = 0;
if (last != NULL) last_time = last->time;
if (TIME < last_time) {
//fprintf(stderr,"Rollback time=%g\n",TIME);
delete_tline_last_state((tline_state_t **)sim_points);
}
append_state((tline_state_t **)sim_points, t, V1, V2, I1, I2, 1.2*delay);
if (t > delay) {
tline_state_t *pp = get_state(*(tline_state_t **)sim_points, t - delay);
if (pp != NULL) {
double V2out = pp->V1 + z*(pp->I1);
double V1out = pp->V2 + z*(pp->I2);
OUTPUT(in) = V1out + I1*z;
OUTPUT(out) = V2out + I2*z;
}
cm_analog_auto_partial();
} else {
double V2out = V1 + z*I1;
double V1out = V2 + z*I2;
OUTPUT(in) = V1out + I1*z;
OUTPUT(out) = V2out + I2*z;
cm_analog_auto_partial();
}
}
}
static void cm_tline_callback(ARGS, Mif_Callback_Reason_t reason)
{
switch (reason) {
case MIF_CB_DESTROY:
delete_tline_states((tline_state_t **)&(STATIC_VAR(sim_points_data)));
break;
default: break;
}
}

Some files were not shown because too many files have changed in this diff Show More