You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

250 lines
8.8 KiB

/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1988 Jaijeet S Roychowdhury
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/devdefs.h"
#include "vdmosdefs.h"
#include "ngspice/distodef.h"
#include "ngspice/const.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
int
VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
/* actually load the current value into the
* sparse matrix previously provided
*/
{
VDMOSmodel *model = (VDMOSmodel *) inModel;
VDMOSinstance *here;
double Beta;
double OxideCap;
double gm;
double gds;
double vgst;
double vds;
double vdsat;
double vgd;
double vgs;
double gm2;
double gds2;
double gmds;
double gm3;
double gds3;
double gm2ds;
double gmds2;
double lcapgs2;
double lcapgs3;
double lcapgd2;
double lcapgd3;
/* loop through all the VDMOS device models */
for( ; model != NULL; model = VDMOSnextModel(model)) {
/* loop through all the instances of the model */
for (here = VDMOSinstances(model); here != NULL ;
here=VDMOSnextInstance(here)) {
Beta = here->VDMOStTransconductance;
OxideCap = model->VDMOSoxideCapFactor * here->VDMOSm;
vgs = model->VDMOStype * (
*(ckt->CKTrhsOld+here->VDMOSgNode) -
*(ckt->CKTrhsOld+here->VDMOSsNodePrime));
vds = model->VDMOStype * (
*(ckt->CKTrhsOld+here->VDMOSdNodePrime) -
*(ckt->CKTrhsOld+here->VDMOSsNodePrime));
/* now some common crunching for some more useful quantities */
vgd=vgs-vds;
/* now to determine whether the user was able to correctly
* identify the source and drain of his device
*/
if(vds >= 0) {
/* normal mode */
here->VDMOSmode = 1;
} else {
/* inverse mode */
here->VDMOSmode = -1;
}
/*
* this block of code evaluates the drain current and its
* derivatives using the shichman-hodges model and the
* charges associated with the gate and channel for
* mosfets
*
*/
/* the following variables are local to this code block until
* it is obvious that they can be made global
*/
{
double von = here->VDMOStVth * model->VDMOStype;
vgst = (here->VDMOSmode == 1 ? vgs : vgd) - von;
vdsat = MAX(vgst, 0);
double slope = model->VDMOSksubthres;
double lambda = model->VDMOSlambda;
double theta = model->VDMOStheta;
double shift = model->VDMOSsubshift;
double mtr = model->VDMOSmtr;
/* scale vds with mtr (except with lambda) */
double vdss = vds*mtr*here->VDMOSmode;
double t0 = 1 + lambda*vds;
double t1 = 1 + theta*vgst;
double betap = Beta*t0/t1;
double dbetapdvgs = -Beta*theta*t0/(t1*t1);
double dbetapdvds = Beta*lambda/t1;
double t2 = exp((vgst-shift)/slope);
vgst = slope * log(1 + t2);
double dvgstdvgs = t2/(t2+1);
if (vgst <= vdss) {
/* saturation region */
gm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst;
gds = .5*dbetapdvds*vgst*vgst;
gm2 = betap;
gds2 = 0;
gmds = Beta*lambda*vgst;
gm3 = 0;
gds3 = 0;
gm2ds = Beta*lambda;
gmds2 = 0;
}
else {
/* linear region */
gm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss);
gds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr;
gm2 = 0;
gds2 = 2*Beta * lambda*(vgst - vds*here->VDMOSmode) - betap;
gmds = Beta * lambda * vds * here->VDMOSmode + betap;
gm3=0;
gds3 = -Beta*lambda*3.;
gm2ds=0;
gmds2 = 2*lambda*Beta;
}
/*
* finished
*/
} /* code block */
/*
* COMPUTE EQUIVALENT DRAIN CURRENT SOURCE
*/
/*
* meyer's capacitor model
*/
/*
* the meyer capacitance equations are in DEVqmeyer
* these expressions are derived from those equations.
* these expressions are incorrect; they assume just one
* controlling variable for each charge storage element
* while actually there are several; the VDMOS small
* signal ac linear model is also wrong because it
* ignores controlled capacitive elements. these can be
* corrected (as can the linear ss ac model) if the
* expressions for the charge are available
*/
{
double phi;
double cox;
double vddif;
double vddif1;
double vddif2;
/* von, vgst and vdsat have already been adjusted for
possible source-drain interchange */
phi = here->VDMOStPhi;
cox = OxideCap; /*FIXME: using a guess for the oxide thickness of 1e-07 in vdmostemp.c */
lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
if (vgst <= 0) {
lcapgs2 = cox/(3*phi);
} else { /* the VDMOSmodes are around because
vds has not been adjusted */
if (vdsat <= here->VDMOSmode*vds) {
lcapgs2=lcapgs3=lcapgd2=lcapgd3=0;
} else {
vddif = 2.0*vdsat-here->VDMOSmode*vds;
vddif1 = vdsat-here->VDMOSmode*vds/*-1.0e-12*/;
vddif2 = vddif*vddif;
lcapgd2 = -vdsat*here->VDMOSmode*vds*cox/(3*vddif*vddif2);
lcapgd3 = - here->VDMOSmode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2);
lcapgs2 = -vddif1*here->VDMOSmode*vds*cox/(3*vddif*vddif2);
lcapgs3 = - here->VDMOSmode*vds*cox*(vddif - 6*vddif1)/(9*vddif2*vddif2);
}
}
}
/*
* process to get Taylor coefficients, taking into
* account type and mode.
*/
if (here->VDMOSmode == 1)
{
/* normal mode - no source-drain interchange */
here->cdr_x2 = gm2;
here->cdr_y2 = gds2;;
here->cdr_xy = gmds;
here->cdr_x3 = gm3;
here->cdr_y3 = gds3;
here->cdr_x2y = gm2ds;
here->cdr_xy2 = gmds2;
/* the gate caps have been divided and made into
Taylor coeffs., but not adjusted for type */
here->capgs2 = model->VDMOStype*lcapgs2;
here->capgs3 = lcapgs3;
here->capgd2 = model->VDMOStype*lcapgd2;
here->capgd3 = lcapgd3;
} else {
/*
* inverse mode - source and drain interchanged
*/
here->cdr_x2 = -gm2;
here->cdr_y2 = -(gm2 + gds2 + 2*(gmds));
here->cdr_xy = gm2 + gmds;
here->cdr_x3 = -gm3;
here->cdr_y3 = gm3 + gds3 +
3*(gm2ds + gmds2) ;
here->cdr_x2y = gm3 + gm2ds;
here->cdr_xy2 = -(gm3 + 2*(gm2ds) +
gmds2);
here->capgs2 = model->VDMOStype*lcapgd2;
here->capgs3 = lcapgd3;
here->capgd2 = model->VDMOStype*lcapgs2;
here->capgd3 = lcapgs3;
}
/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */
here->cdr_x2 = 0.5*model->VDMOStype*here->cdr_x2;
here->cdr_y2 = 0.5*model->VDMOStype*here->cdr_y2;
here->cdr_xy = model->VDMOStype*here->cdr_xy;
here->cdr_x3 = here->cdr_x3/6.;
here->cdr_y3 = here->cdr_y3/6.;
here->cdr_x2y = 0.5*here->cdr_x2y;
here->cdr_xy2 = 0.5*here->cdr_xy2;
}
}
return(OK);
}