home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-01-28 | 51.4 KB | 1,764 lines |
- Path: sparky!uunet!ferkel.ucsb.edu!taco!rock!stanford.edu!ames!haven.umd.edu!darwin.sura.net!ukma!cs.widener.edu!dsinc!ub!galileo.cc.rochester.edu!ee.rochester.edu!rbc!al
- From: al@rbc.uucp (Al Davis)
- Newsgroups: alt.sources
- Subject: ACS circuit simulator part 14/20
- Message-ID: <1993Jan27.040850.11696@rbc.uucp>
- Date: 27 Jan 93 04:08:50 GMT
- Sender: al@rbc.uucp (Al Davis)
- Organization: Huh?
- Lines: 1753
-
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create the files:
- # src/d_mos.c
- # src/d_mos2.c
- # src/d_mosc.c
- # This archive created: Tue Jan 26 22:51:04 1993
- export PATH; PATH=/bin:$PATH
- if test -f 'src/d_mos.c'
- then
- echo shar: will not over-write existing file "'src/d_mos.c'"
- else
- cat << \SHAR_EOF > 'src/d_mos.c'
- /* dev_mos.c 01/05/92
- * Copyright 1983-1992 Albert Davis
- * mos model basics
- * netlist syntax:
- * device: mxxxx d g s b mname <device args> <model card args>
- * model: .model mname NMOS <args>
- * or .model mname PMOS <args>
- */
- #include "ecah.h"
- #include "argparse.h"
- #include "branch.h"
- #include "convstat.h"
- #include "dev.h"
- #include "d_diode.h"
- #include "d_mos.h"
- #include "error.h"
- #include "io.h"
- #include "mode.h"
- #include "options.h"
- #include "status.h"
- #include "types.h"
- #include "declare.h"
- /*--------------------------------------------------------------------------*/
- static branch_t *create_mos(const branch_t*);
- static void parse_mos(branch_t*,const char*,int*);
- static void print_mos(const branch_t*,int,int);
- static branch_t *create_model_mos(const branch_t*);
- static void parse_model_mos(branch_t*,const char*,int*);
- static void print_model_mos(const branch_t*,int,int);
- static double trprobe_mos(const branch_t*,const char*);
- static int tr_mos(branch_t*);
- static void un_mos(branch_t*);
- static void ac_mos(branch_t*);
- static void expand_mos(branch_t*);
- static double tr_review_mos(branch_t*);
- /*--------------------------------------------------------------------------*/
- functions_t dev_mos = {
- sizeof(branch_t),
- create_mos,
- parse_mos,
- print_mos,
- expand_mos,
- trprobe_mos,
- (double(*)())NULL,/* acprobe */
- tr_mos,
- un_mos,
- ac_mos,
- (void(*)())NULL, /* trfun1 */
- (void(*)())NULL, /* trfun0 */
- (complex_t(*)())NULL,/* acfun */
- (void(*)())NULL, /* tr_guess */
- (void(*)())NULL, /* tr_advance */
- tr_review_mos
- };
- functions_t model_mos = {
- sizeof(branch_t),
- create_model_mos,
- parse_model_mos,
- print_model_mos,
- (void(*)())NULL, /* expand */
- (double(*)())NULL, /* trprobe */
- (double(*)())NULL,/* acprobe */
- (int(*)())NULL, /* dotr */
- (void(*)())NULL, /* untr */
- (void(*)())NULL, /* doac */
- (void(*)())NULL, /* trfun1 */
- (void(*)())NULL, /* trfun0 */
- (complex_t(*)())NULL,/* acfun */
- (void(*)())NULL, /* tr_guess */
- (void(*)())NULL, /* tr_advance */
- (double(*)())NULL /* tr_review */
- };
- /*--------------------------------------------------------------------------*/
- extern struct ioctrl io;
- extern const struct options opt;
- extern const struct status stats;
-
- extern const int inc_mode; /* make incremental changes */
- extern const int sim_mode;
- extern const int currents_bad;
- extern const int *nm;
-
- static struct dmod mos_diode_model = {(generic_t*)NULL, sizeof(struct dmod),
- mdDEFMOD_js, mdDEFMOD_rs, mdDEFMOD_n, mdDEFMOD_tt, mdDEFMOD_cj,
- mdDEFMOD_pb, mdDEFMOD_mj, mdDEFMOD_eg, mdDEFMOD_xti, mdDEFMOD_kf,
- mdDEFMOD_af, mdDEFMOD_fc, mdDEFMOD_bv, mdDEFMOD_ibv, mdDEFMOD_cjsw,
- mdDEFMOD_mjsw, mdDEFMOD_fcpb};
- static struct mos defalt = {(generic_t*)NULL, sizeof(struct mos),
- (struct mmod*)NULL, mDEFDEV_modelname, mDEFDEV_l, mDEFDEV_w,
- mDEFDEV_ad, mDEFDEV_as, mDEFDEV_pd, mDEFDEV_ps, mDEFDEV_nrd,
- mDEFDEV_nrs, mDEFDEV_ic_vds, mDEFDEV_ic_vgs, mDEFDEV_ic_vbs,
- NO, NO};
- static struct mmod defaltmodel = {&mos_diode_model, sizeof(struct mmod),
- mDEFMOD_vto, mDEFMOD_kp, mDEFMOD_gamma, mDEFMOD_phi, mDEFMOD_lambda,
- mDEFMOD_rd, mDEFMOD_rs, mDEFMOD_cbd, mDEFMOD_cbs, mDEFMOD_is,
- mDEFMOD_pb, mDEFMOD_cgso, mDEFMOD_cgdo, mDEFMOD_cgbo, mDEFMOD_rsh,
- mDEFMOD_js, mDEFMOD_tox, mDEFMOD_nsub, mDEFMOD_nss, mDEFMOD_nfs,
- mDEFMOD_xj, mDEFMOD_ld, mDEFMOD_uo, mDEFMOD_ucrit, mDEFMOD_uexp,
- mDEFMOD_utra, mDEFMOD_vmax, mDEFMOD_neff, mDEFMOD_kf, mDEFMOD_af,
- mDEFMOD_delta, mDEFMOD_theta, mDEFMOD_eta, mDEFMOD_kappa,
- mDEFMOD_level, mDEFMOD_tpg, mDEFMOD_polarity, mDEFMOD_xd,
- mDEFMOD_cox, mDEFMOD_vfb, mDEFMOD_vbi, mDEFMOD_xwb, mDEFMOD_vbp,
- mDEFMOD_cfsox};
- static branch_t modellist = {(generic_t*)&defaltmodel, sizeof(branch_t),
- &model_mos, &modellist, &modellist, &modellist, &modellist,
- (branch_t*)NULL, (branch_t*)NULL, mDEFMOD_modelname, /* more */};
- /*--------------------------------------------------------------------------*/
- static branch_t *create_mos(proto)
- const branch_t *proto;
- {
- return createbranch(proto,(generic_t*)&defalt,&dev_mos);
- }
- /*--------------------------------------------------------------------------*/
- static void parse_mos(brh,cmd,cnt)
- branch_t *brh;
- const char *cmd;
- int *cnt;
- {
- struct mos *x;
-
- x = (struct mos*)brh->x;
-
- parselabel(brh,cmd,cnt);
- (void)parsenodes(brh,cmd,cnt,4);
- (void)ctostr(cmd, cnt, x->modelname, LABELEN);
- x->m = (struct mmod*)NULL;
- if (isdigit(cmd[*cnt]) || cmd[*cnt] == '.'){
- x->w = fabs(ctof(cmd,cnt)) * SCALE;
- if (cmd[*cnt] == '/'){
- (*cnt)++;
- x->lo = fabs(ctof(cmd,cnt)) * SCALE;
- }
- }
-
- for (;;){
- if (argparse(cmd,cnt,REPEAT,
- "L", aUDOUBLE, &x->lo,
- "W", aUDOUBLE, &x->w,
- "AD", aUDOUBLE, &x->ad,
- "AS", aUDOUBLE, &x->as,
- "PD", aUDOUBLE, &x->pd,
- "PS", aUDOUBLE, &x->ps,
- "NRD", aUDOUBLE, &x->nrd,
- "NRS", aUDOUBLE, &x->nrs,
- ""))
- ;
- else{
- syntax(cmd,cnt,bWARNING);
- break;
- }
- }
- }
- /*--------------------------------------------------------------------------*/
- static void print_mos(brh,where,detail)
- const branch_t *brh;
- int where;
- int detail;
- {
- struct mos *x;
-
- x = (struct mos*)brh->x;
-
- (void)printlabel(brh,where);
- printnodes(brh,where);
- mprintf(where, " %s ", x->modelname);
- mprintf(where, " l=%s ", ftos(x->lo, "", 7, 0));
- mprintf(where, " w=%s ", ftos(x->w, "", 7, 0));
- if (x->ad != NOT_INPUT)
- mprintf(where, " ad=%s ", ftos(x->ad, "", 7, 0));
- if (x->as != NOT_INPUT)
- mprintf(where, " as=%s ", ftos(x->as, "", 7, 0));
- if (x->pd != 0.)
- mprintf(where, " pd=%s ", ftos(x->pd, "", 7, 0));
- if (x->ps != 0.)
- mprintf(where, " ps=%s ", ftos(x->ps, "", 7, 0));
- mprintf(where, " nrd=%s ",ftos(x->nrd,"", 7, 0));
- mprintf(where, " nrs=%s ",ftos(x->nrs,"", 7, 0));
-
- if (x->icset){
- int i;
- mprintf(where, " IC=");
- for (i=0; i<NUM_INIT_COND; i++)
- mprintf(where, "%s ",ftos(x->ic[i],"", 7, 0));
- }
- mprintf(where, "\n");
- }
- /*--------------------------------------------------------------------------*/
- static branch_t *create_model_mos(proto)
- const branch_t *proto;
- {
- branch_t *brh;
-
- brh = createbranch(proto,(generic_t*)&defaltmodel,&model_mos);
- brh->stprev = &modellist;
- return brh;
- }
- /*--------------------------------------------------------------------------*/
- static void parse_model_mos(brh,cmd,cnt)
- branch_t *brh;
- const char *cmd;
- int *cnt;
- {
- struct mmod *m;
-
- m = (struct mmod*)brh->x;
-
- (void)ctostr(cmd, cnt, brh->label, LABELEN);
- if (argparse(cmd,cnt,ONEPASS,
- "NMos", aENUM, &m->polarity, pN,
- "PMos", aENUM, &m->polarity, pP,
- ""))
- ;
- else
- syntax(cmd,cnt,bWARNING);
-
- (void)skiplparen(cmd,cnt);
- for (;;){
- if (argparse(cmd,cnt,REPEAT,
- "LEvel",aFINT, &m->level,
- "VTO", aSDOUBLE, &m->vto, (double)m->polarity,
- "KP", aDOUBLE, &m->kp,
- "GAmma",aDOUBLE, &m->gamma,
- "PHI", aUDOUBLE, &m->phi,
- "LAmbda",aDOUBLE, &m->lambda,
- "RD", aDOUBLE, &m->rd,
- "RS", aDOUBLE, &m->rs,
- "CBD", aDOUBLE, &m->cbd,
- "CBS", aDOUBLE, &m->cbs,
- "IS", aDOUBLE, &m->is,
- "PB", aUDOUBLE, &m->pb,
- "CGSo", aDOUBLE, &m->cgso,
- "CGDo", aDOUBLE, &m->cgdo,
- "CGBo", aDOUBLE, &m->cgbo,
- "RSH", aDOUBLE, &m->rsh,
- "CJ", aDOUBLE, &m->d->cj,
- "MJ", aDOUBLE, &m->d->mj,
- "CJSw", aDOUBLE, &m->d->cjsw,
- "MJSw", aDOUBLE, &m->d->mjsw,
- "JS", aDOUBLE, &m->js,
- ""))
- ;
- else if (argparse(cmd,cnt,REPEAT,
- "TOX", aUDOUBLE, &m->tox,
- "NSUb", aSDOUBLE, &m->nsub, ICM2M3,
- "NSS", aSDOUBLE, &m->nss, ICM2M2,
- "NFS", aSDOUBLE, &m->nfs, ICM2M2,
- "TPG", aFINT, &m->tpg,
- "XJ", aUDOUBLE, &m->xj,
- "LD", aDOUBLE, &m->ld,
- "UO", aSDOUBLE, &m->uo, CM2M2,
- "UCRit",aSDOUBLE, &m->ucrit, ICM2M,
- "UEXp", aDOUBLE, &m->uexp,
- "UTRa", aDOUBLE, &m->utra,
- "VMAx", aDOUBLE, &m->vmax,
- "NEFf", aUDOUBLE, &m->neff,
- "KF", aDOUBLE, &m->kf,
- "AF", aDOUBLE, &m->af,
- "FC", aDOUBLE, &m->d->fc,
- "DELta",aDOUBLE, &m->delta,
- "THEta",aDOUBLE, &m->theta,
- "ETA", aDOUBLE, &m->eta,
- "KAPpa",aDOUBLE, &m->kappa,
- ""))
- ;
- else{
- (void)skiprparen(cmd,cnt);
- syntax(cmd,cnt,bWARNING);
- break;
- }
- }
-
- if ((m->rs == NOT_INPUT) && (m->rd != NOT_INPUT)){
- error(bWARNING, "%s: rd input, but not rs. setting rs = 0.\n",
- printlabel(brh,NO));
- m->rs = 0.;
- }else if ((m->rd == NOT_INPUT) && (m->rs != NOT_INPUT)){
- error(bWARNING, "%s: rs input, but not rd. setting rd = 0.\n",
- printlabel(brh,NO));
- m->rd = 0.;
- }
-
- if ((m->rsh != NOT_INPUT) && (m->rd != NOT_INPUT)){
- error(bWARNING, "%s: rsh - rs - rd conflict: using %s\n",
- printlabel(brh,NO),
- ((m->rd <= 0.) && (m->rs <= 0.)) ? "rsh" : "rs,rd" );
- }else if ((m->rsh == NOT_INPUT) && (m->rd == NOT_INPUT)){
- m->rsh = 0.;
- }
-
- if (m->tox == 0.){
- error(bWARNING, "%s: tox == 0: using %s\n",
- printlabel(brh,NO),
- ftos(mDEFMOD_tox, "", 7, 0));
- m->tox = mDEFMOD_tox;
- }
- m->cox = E_OX / m->tox;
-
- if (m->kp == NOT_INPUT){
- m->kp = m->uo * m->cox;
- m->calc.kp = YES;
- }
-
- if (m->is == NOT_INPUT && m->js == NOT_INPUT){
- m->is = mDEFMODLR_is;
- }else if (m->is != NOT_INPUT && m->js != NOT_INPUT){
- error(bWARNING, "%s: is - js conflict\n", printlabel(brh,NO));
- }
-
- if (m->nsub != NOT_INPUT){
- m->nsub = fabs(m->nsub);
- if (m->nsub < NI){
- error(bWARNING, "%s: nsub < ni\n", printlabel(brh,NO));
- m->nsub = NI;
- }
-
- if (m->d->cj == NOT_INPUT){
- m->d->cj = sqrt(E_SI * Q * m->nsub / (2. * m->pb));
- m->calc.cj = YES;
- }
-
- if (m->phi == NOT_INPUT){
- m->phi = (2.*K/Q)*opt.tempamb*log(m->nsub/NI);
- if (m->phi < .1){
- error(bWARNING, "%s: calculated phi too small, using .1\n",
- printlabel(brh,NO));
- m->phi = .1;
- }
- m->calc.phi = YES;
- }
-
- if (m->gamma == NOT_INPUT){
- m->gamma = sqrt(2. * E_SI * Q * m->nsub) / m->cox;
- m->calc.gamma = YES;
- }
-
- if (m->vto == NOT_INPUT){
- double phi_ms;
- double eg;
- eg = 1.16 - (7.02e-4 * opt.tempamb*opt.tempamb) / (opt.tempamb + 1108.);
-
- if (m->tpg == gMETAL)
- phi_ms = -.05 - (eg + m->polarity * m->phi) / 2.;
- else
- phi_ms = -m->polarity * (m->tpg * eg + m->phi) / 2.;
-
- m->vfb = phi_ms - Q * m->nss / m->cox;
- m->vto = m->vfb + m->polarity * (m->phi + m->gamma * sqrt(m->phi));
- m->calc.vto = YES;
- }
- m->xd = sqrt((2. * E_SI / Q) / m->nsub);
- m->xwb = m->xd * sqrt(m->pb);
- }else{
- if (m->vto == NOT_INPUT)
- m->vto = mDEFMODLR_vto;
- if (m->gamma == NOT_INPUT)
- m->gamma = mDEFMODLR_gamma;
- if (m->phi == NOT_INPUT)
- m->phi = mDEFMODLR_phi;
- if (m->d->cj == NOT_INPUT)
- m->d->cj = mDEFMODLR_cj;
- m->xd = m->xwb / sqrt(m->pb);
- }
- if (m->lambda != NOT_INPUT && m->lambda > .2)
- error(bWARNING, "%s: lambda too large (> .2)\n", printlabel(brh,NO));
- if (m->vfb == NOT_INPUT)
- m->vfb = m->vto - (m->phi + m->gamma * sqrt(m->phi));
- m->vbi = m->vfb + m->phi;
- m->vbp = m->ucrit * E_SI / m->cox;
- m->cfsox = Q * m->nfs / m->cox;
- m->d->fcpb = m->d->fc * m->d->pb;
- }
- /*--------------------------------------------------------------------------*/
- static void print_model_mos(brh,where,detail)
- const branch_t *brh;
- int where;
- int detail;
- {
- struct mmod *m;
- m = (struct mmod*)brh->x;
-
- mprintf(where, ".model %s ", brh->label);
- mprintf(where, " %s (", (m->polarity < 0) ? "pmos" : "nmos");
- mprintf(where, " level=%d ", m->level);
- if (!m->calc.vto)
- mprintf(where, " vto=%s ", ftos(m->vto*m->polarity,"", 7, 0));
- if (!m->calc.kp)
- mprintf(where, " kp=%s ", ftos(m->kp, "", 7, 0));
- if (!m->calc.gamma)
- mprintf(where, " gamma=%s ", ftos(m->gamma, "", 7, 0));
- if (!m->calc.phi)
- mprintf(where, " phi=%s ", ftos(m->phi, "", 7, 0));
- if (m->lambda != NOT_INPUT)
- mprintf(where, " lambda=%s ",ftos(m->lambda, "", 7, 0));
- if (m->rd != NOT_INPUT)
- mprintf(where, " rd=%s ", ftos(m->rd, "", 7, 0));
- if (m->rs != NOT_INPUT)
- mprintf(where, " rs=%s ", ftos(m->rs, "", 7, 0));
- if (m->cbd != NOT_INPUT)
- mprintf(where, " cbd=%s ", ftos(m->cbd, "", 7, 0));
- if (m->cbs != NOT_INPUT)
- mprintf(where, " cbs=%s ", ftos(m->cbs, "", 7, 0));
- if (m->is != NOT_INPUT)
- mprintf(where, " is=%s ", ftos(m->is, "", 7, 0));
- mprintf(where, " pb=%s ", ftos(m->pb, "", 7, 0));
- mprintf(where, " cgso=%s ", ftos(m->cgso, "", 7, 0));
- mprintf(where, " cgdo=%s ", ftos(m->cgdo, "", 7, 0));
- mprintf(where, " cgbo=%s ", ftos(m->cgbo, "", 7, 0));
- if (m->rsh != NOT_INPUT)
- mprintf(where, " rsh=%s ", ftos(m->rsh, "", 7, 0));
- if (!m->calc.cj)
- mprintf(where, " cj=%s ", ftos(m->d->cj, "", 7, 0));
- mprintf(where, " mj=%s ", ftos(m->d->mj, "", 7, 0));
- mprintf(where, " cjsw=%s ", ftos(m->d->cjsw, "", 7, 0));
- mprintf(where, " mjsw=%s ", ftos(m->d->mjsw, "", 7, 0));
- if (m->js != NOT_INPUT)
- mprintf(where, " js=%s ", ftos(m->js, "", 7, 0));
- mprintf(where, " tox=%s ", ftos(m->tox, "", 7, 0));
- if (m->nsub != NOT_INPUT)
- mprintf(where, " nsub=%s ", ftos(m->nsub/ICM2M3,"", 7, 0));
- if (m->nss != mDEFMOD_nss || m->nsub != NOT_INPUT)
- mprintf(where, " nss=%s ", ftos(m->nss /ICM2M2,"", 7, 0));
- mprintf(where, " nfs=%s ", ftos(m->nfs /ICM2M2,"", 7, 0));
- mprintf(where, " tpg=%d ", m->tpg);
- if (m->xj != NOT_INPUT)
- mprintf(where, " xj=%s ", ftos(m->xj, "", 7, 0));
- mprintf(where, " ld=%s ", ftos(m->ld, "", 7, 0));
- mprintf(where, " uo=%s ", ftos(m->uo /CM2M2,"", 7, 0));
- if (m->ucrit != mDEFMOD_ucrit || m->uexp != NOT_INPUT)
- mprintf(where, " ucrit=%s ", ftos(m->ucrit/ICM2M,"", 7, 0));
- if (m->uexp != NOT_INPUT)
- mprintf(where, " uexp=%s ", ftos(m->uexp, "", 7, 0));
- if (m->utra != NOT_INPUT)
- mprintf(where, " utra=%s ", ftos(m->utra, "", 7, 0));
- if (m->vmax != NOT_INPUT)
- mprintf(where, " vmax=%s ", ftos(m->vmax, "", 7, 0));
- if (m->neff != mDEFMOD_neff || m->lambda == NOT_INPUT)
- mprintf(where, " neff=%s ", ftos(m->neff, "", 7, 0));
- if (m->kf != NOT_INPUT)
- mprintf(where, " kf=%s ", ftos(m->kf, "", 7, 0));
- if (m->af != NOT_INPUT)
- mprintf(where, " af=%s ", ftos(m->af, "", 7, 0));
- mprintf(where, " fc=%s ", ftos(m->d->fc, "", 7, 0));
- mprintf(where, " delta=%s ", ftos(m->delta, "", 7, 0));
- if (m->theta != NOT_INPUT)
- mprintf(where, " theta=%s ", ftos(m->theta, "", 7, 0));
- if (m->eta != NOT_INPUT)
- mprintf(where, " eta=%s ", ftos(m->eta, "", 7, 0));
- if (m->kappa != NOT_INPUT)
- mprintf(where, " kappa=%s ", ftos(m->kappa, "", 7, 0));
- mprintf(where, ")\n*+(");
- mprintf(where, "* vfb=%s ", ftos(m->vfb, "", 7, 0));
- if (m->calc.vto)
- mprintf(where, "* vto=%s ", ftos(m->vto*m->polarity, "", 7, 0));
- if (m->calc.kp)
- mprintf(where, "* kp=%s ", ftos(m->kp, "", 7, 0));
- if (m->calc.gamma)
- mprintf(where, "* gamma=%s ", ftos(m->gamma, "", 7, 0));
- if (m->calc.phi)
- mprintf(where, "* phi=%s ", ftos(m->phi, "", 7, 0));
- if (m->calc.cj)
- mprintf(where, "* cj=%s ", ftos(m->d->cj, "", 7, 0));
- mprintf(where, ")\n");
- }
- /*--------------------------------------------------------------------------*/
- static double trprobe_mos(brh,what)
- const branch_t *brh;
- const char *what;
- {
- struct mos *x;
- int dummy = 0;
-
- x = (struct mos*)brh->x;
- if (!x->m || !brh->subckt)
- error(bERROR, "internal error: %s not expanded\n", printlabel(brh,NO));
-
- setmatch(what,&dummy);
- if (rematch("Vds")){
- return tr_volts(brh->nDRAIN,brh->nSOURCE);
- }else if (rematch("VGS")){
- return tr_volts(brh->nGATE,brh->nSOURCE);
- }else if (rematch("VBS")){
- return tr_volts(brh->nBULK,brh->nSOURCE);
- }else if (rematch("VDG")){
- return tr_volts(brh->nDRAIN,brh->nGATE);
- }else if (rematch("Id")){
- return (x->Rd)
- ? trprobe_branch(x->Rd,"I")
- : trprobe_branch(x->Ids,"I")
- + trprobe_branch(x->Gmf,"I")
- + trprobe_branch(x->Gmr,"I")
- + trprobe_branch(x->Yds,"I")
- + trprobe_branch(x->Gmbf,"I")
- + trprobe_branch(x->Gmbr,"I")
- - trprobe_branch(x->Cgd,"I")
- + trprobe_branch(x->Ddb,"I") * x->m->polarity;
- }else if (rematch("IS")){
- return (x->Rd)
- ? trprobe_branch(x->Rs,"I")
- : - trprobe_branch(x->Ids,"I")
- - trprobe_branch(x->Gmf,"I")
- - trprobe_branch(x->Gmr,"I")
- - trprobe_branch(x->Yds,"I")
- - trprobe_branch(x->Gmbf,"I")
- - trprobe_branch(x->Gmbr,"I")
- - trprobe_branch(x->Cgs,"I")
- + trprobe_branch(x->Dsb,"I") * x->m->polarity;
- }else if (rematch("IG")){
- return trprobe_branch(x->Cgs,"I")
- + trprobe_branch(x->Cgd,"I")
- + trprobe_branch(x->Cgb,"I");
- }else if (rematch("IB")){
- return - trprobe_branch(x->Ddb,"I") * x->m->polarity
- - trprobe_branch(x->Dsb,"I") * x->m->polarity
- - trprobe_branch(x->Cgb,"I");
- }else if (rematch("P")){
- branch_t *pb, *stop;
- double power = 0.;
- stop = pb = brh->subckt;
- do {
- power += trprobe_branch(pb,"P");
- } while (pb=nextbranch_dev(pb), pb != stop);
- return power;
- }else if (rematch("REgion")){
- return (double)(
- (!x->cutoff)
- + (!x->subthreshold * 2)
- + (x->saturated * 4)
- + (x->sbfwd * 10)
- + (x->dbfwd * 20)
- ) * ((x->reversed)? -1 : 1);
- }else{ /* bad parameter */
- return NOT_VALID;
- }
- /*NOTREACHED*/
- }
- /*--------------------------------------------------------------------------*/
- static int tr_mos(brh)
- branch_t *brh;
- {
- struct mos *x;
- struct mmod *m;
- double vds, vgs, vbs;
-
- if (brh->iter == stats.iter[iTOTAL]){
- return brh->status;
- }else{
- brh->iter = stats.iter[iTOTAL];
- }
- x = (struct mos*)brh->x;
- if (!(x->m && brh->subckt))
- error(bERROR, "internal error: %s not expanded\n", printlabel(brh,NO));
- m = x->m;
-
- x->sourcenode.m = nm[x->sourcenode.t];
- x->drainnode.m = nm[x->drainnode.t];
-
- vds = m->polarity * tr_volts_limited(x->drainnode,x->sourcenode);
- x->reversed = vds < 0.;
- if (x->reversed){
- vds = -vds;
- vgs = m->polarity * tr_volts_limited(brh->nGATE,x->drainnode);
- vbs = m->polarity * tr_volts_limited(brh->nBULK,x->drainnode);
- if (!io.suppresserrors)
- error(bTRACE, "%s: reversed\n", printlabel(brh,NO));
- }else{
- vgs = m->polarity * tr_volts_limited(brh->nGATE,x->sourcenode);
- vbs = m->polarity * tr_volts_limited(brh->nBULK,x->sourcenode);
- }
-
- if (!opt.bypass || currents_bad){
- brh->bypass = NO;
- x->vds = vds;
- x->vgs = vgs;
- x->vbs = vbs;
- eval_mos2(brh);
- brh->status = tr_fill_rl(brh->subckt);
- }else{
- if (brh->status == cGOOD){
- brh->status = conchk(x->vds, vds, opt.vntol);
- brh->status |= conchk(x->vgs, vgs, opt.vntol);
- brh->status |= conchk(x->vbs, vbs, opt.vntol);
- if (brh->status & cNONCONVERGE){
- error(bTRACE, "%s: deconverged\n", printlabel(brh,0));
- brh->bypass = NO;
- x->vds = vds;
- x->vgs = vgs;
- x->vbs = vbs;
- eval_mos2(brh);
- brh->status = tr_fill_rl(brh->subckt);
- }else{
- brh->bypass = YES;
- if (!inc_mode){
- (void)tr_fill_rl(brh->subckt);
- }
- }
- }else{ /* not converged */
- if (opt.bypass == bVOLT){
- brh->status = conchk(x->vds, vds, opt.vntol);
- brh->status |= conchk(x->vgs, vgs, opt.vntol);
- brh->status |= conchk(x->vbs, vbs, opt.vntol);
- }
- if (brh->status & cNONCONVERGE){
- brh->bypass = NO;
- x->vds = vds;
- x->vgs = vgs;
- x->vbs = vbs;
- eval_mos2(brh);
- brh->status = tr_fill_rl(brh->subckt);
- }else{
- error(bWARNING, "%s: ambitious bypass\n", printlabel(brh,0));
- brh->bypass = YES;
- if (!inc_mode){
- (void)tr_fill_rl(brh->subckt);
- }
- }
- }
- }
-
- return brh->status;
- }
- /*--------------------------------------------------------------------------*/
- static void un_mos(brh)
- branch_t *brh;
- {
- tr_unfill_rl(brh->subckt);
- }
- /*--------------------------------------------------------------------------*/
- static void ac_mos(brh)
- branch_t *brh;
- {
- struct mos *x;
- x = (struct mos*)brh->x;
- if (!(x->m && brh->subckt))
- error(bERROR, "internal error: %s not expanded\n", printlabel(brh,NO));
- ac_fill_rl(brh->subckt);
- }
- /*--------------------------------------------------------------------------*/
- static void expand_mos(brh)
- branch_t *brh;
- {
- const struct mmod *m;
- struct mos *x;
-
- expandgeneric(brh,&modellist);
- x = (struct mos*)brh->x;
- m = x->m;
-
- if (m->level != 2)
- error(bWARNING, "%s: level %d not supported, using level 2\n",
- printlabel(brh,NO), m->level);
-
- x->le = x->lo - 2. * m->ld; /* calculate parameters */
- x->cgate = m->cox * x->w * x->le;
- if (x->cgate <= 0.)
- error(bERROR, "%s: cgate is negative?\n", printlabel(brh,NO));
- x->beta = m->kp * x->w / x->le;
- x->relxj = (m->xj != NOT_INPUT && m->xj > 0.)
- ? .5 * m->xj / x->le
- : NOT_INPUT;
- x->eta_1 = (PI/4.) * E_SI * m->delta / x->cgate * x->le;
- x->eta = x->eta_1 + 1.;
- x->eta_2 = x->eta / 2.;
- /* build subckt */
- /* resistors */
- if (m->rsh != NOT_INPUT && m->rd <= 0. && m->rs <= 0.){
- x->rd = m->rsh * x->nrd;
- x->rs = m->rsh * x->nrs;
- }else{
- x->rd = (m->rd != NOT_INPUT) ? m->rd : 0.;
- x->rs = (m->rs != NOT_INPUT) ? m->rs : 0.;
- }
- if (x->rs != 0.){
- x->sourcenode.t = newnode_model();
- x->Rs = (*(dev_resistor.create))((branch_t*)NULL);
- x->Rs->parent = brh;
- strcpy(x->Rs->label,"Rs");
- x->Rs->n[OUT1] = brh->nSOURCE;
- x->Rs->n[OUT2] = x->sourcenode;
- x->Rs->val = x->rs;
- x->Rs->next = brh->subckt;
- brh->subckt = insertbranch(x->Rs);
- }else{
- x->sourcenode = brh->nSOURCE;
- x->Rs = (branch_t*)NULL;
- }
- if (x->rd != 0.){
- x->drainnode.t = newnode_model();
- x->Rd = (*(dev_resistor.create))((branch_t*)NULL);
- x->Rd->parent = brh;
- strcpy(x->Rd->label,"Rd");
- x->Rd->n[OUT1] = brh->nDRAIN;
- x->Rd->n[OUT2] = x->drainnode;
- x->Rd->val = x->rd;
- x->Rd->next = brh->subckt;
- brh->subckt = insertbranch(x->Rd);
- }else{
- x->drainnode = brh->nDRAIN;
- x->Rd = (branch_t*)NULL;
- }
-
- /* diodes */
- if (m->js == NOT_INPUT || x->ad == NOT_INPUT || x->as == NOT_INPUT){
- x->idsat = x->issat = m->is;
- }else{
- x->idsat = m->js * x->ad;
- x->issat = m->js * x->as;
- }
- if (brh->nBULK.t != x->drainnode.t && x->idsat != 0.){
- struct diode *xd;
- if (!x->Ddb)
- x->Ddb = (*(dev_diode.create))((branch_t*)NULL);
- x->Ddb->parent = brh;
- xd = (struct diode*)x->Ddb->x;
- strcpy(x->Ddb->label,"Ddb");
- if (m->polarity == pN){
- x->Ddb->n[OUT1] = brh->nBULK;
- x->Ddb->n[OUT2] = x->drainnode;
- }else{ /* m->polarity == pP */
- x->Ddb->n[OUT2] = brh->nBULK;
- x->Ddb->n[OUT1] = x->drainnode;
- }
- strcpy(xd->modelname,mdDEFMOD_modelname);
- xd->area = (x->ad != NOT_INPUT) ? x->ad : 1.;
- xd->perim = x->pd;
- xd->is = x->idsat;
- xd->m = x->m->d;
- x->Ddb->next = brh->subckt;
- x->Ddb->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Ddb);
- }else{
- x->Ddb = (branch_t*)NULL;
- }
-
- if (brh->nBULK.t != x->sourcenode.t && x->issat != 0.){
- struct diode *xd;
- if (!x->Dsb)
- x->Dsb = (*(dev_diode.create))((branch_t*)NULL);
- x->Dsb->parent = brh;
- xd = (struct diode*)x->Dsb->x;
- strcpy(x->Dsb->label,"Dsb");
- if (m->polarity == pN){
- x->Dsb->n[OUT1] = brh->nBULK;
- x->Dsb->n[OUT2] = x->sourcenode;
- }else{ /* m->polarity == pP */
- x->Dsb->n[OUT2] = brh->nBULK;
- x->Dsb->n[OUT1] = x->sourcenode;
- }
- strcpy(xd->modelname,mdDEFMOD_modelname);
- xd->area = (x->as != NOT_INPUT) ? x->as : 1.;
- xd->perim = x->ps;
- xd->is = x->issat;
- xd->m = x->m->d;
- x->Dsb->next = brh->subckt;
- x->Dsb->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Dsb);
- }else{
- x->Dsb = (branch_t*)NULL;
- }
- /* capacitors */
- if (brh->nGATE.t != x->sourcenode.t && m->cgso != 0.){
- if (!x->Cgs){
- static functions_t *ff;
- x->Cgs = (*(dev_cap.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Cgs->f);
- ff->expand = (void(*)())NULL; /* no gate capacitance */
- ff->trfun1 = mos_cgs1; /* if no overlap cap */
- ff->trfun0 = mos_cgs0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Cgs->f = ff;
- }
- x->Cgs->parent = brh;
- strcpy(x->Cgs->label,"Cgs");
- x->Cgs->n[OUT1] = brh->nGATE;
- x->Cgs->n[OUT2] = x->sourcenode;
- x->Cgs->val = m->cgso * x->w;
- x->Cgs->next = brh->subckt;
- x->Cgs->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Cgs);
- }else{
- x->Cgs = (branch_t*)NULL;
- }
-
- if (brh->nGATE.t != x->drainnode.t && m->cgdo != 0.){
- if (!x->Cgd){
- static functions_t *ff;
- x->Cgd = (*(dev_cap.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Cgd->f);
- ff->expand = (void(*)())NULL;
- ff->trfun1 = mos_cgd1;
- ff->trfun0 = mos_cgd0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Cgd->f = ff;
- }
- x->Cgd->parent = brh;
- strcpy(x->Cgd->label,"Cgd");
- x->Cgd->n[OUT1] = brh->nGATE;
- x->Cgd->n[OUT2] = x->drainnode;
- x->Cgd->val = m->cgdo * x->w;
- x->Cgd->next = brh->subckt;
- x->Cgd->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Cgd);
- }else{
- x->Cgd = (branch_t*)NULL;
- }
-
- if (brh->nBULK.t != brh->nGATE.t && m->cgbo != 0.){
- if (!x->Cgb){
- static functions_t *ff;
- x->Cgb = (*(dev_cap.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Cgb->f);
- ff->expand = (void(*)())NULL;
- ff->trfun1 = mos_cgb1;
- ff->trfun0 = mos_cgb0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Cgb->f = ff;
- }
- x->Cgb->parent = brh;
- strcpy(x->Cgb->label,"Cgb");
- x->Cgb->n[OUT1] = brh->nGATE;
- x->Cgb->n[OUT2] = brh->nBULK;
- x->Cgb->val = m->cgbo * x->le;
- x->Cgb->next = brh->subckt;
- x->Cgb->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Cgb);
- }else{
- x->Cgb = (branch_t*)NULL;
- }
- /* model sources */
- if (brh->nBULK.t != x->sourcenode.t){
- if (!x->Gmbf){
- static functions_t *ff;
- x->Gmbf = (*(dev_vccs.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Gmbf->f);
- ff->expand = (void(*)())NULL;
- ff->trfun1 = mos2_gmbf1;
- ff->trfun0 = mos2_gmbf0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Gmbf->f = ff;
- }
- x->Gmbf->parent = brh;
- strcpy(x->Gmbf->label,"Gmbf");
- x->Gmbf->n[OUT1] = x->drainnode;
- x->Gmbf->n[OUT2] = x->sourcenode;
- x->Gmbf->n[IN1] = brh->nBULK;
- x->Gmbf->n[IN2] = x->sourcenode;
- x->Gmbf->next = brh->subckt;
- x->Gmbf->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Gmbf);
- }else{
- x->Gmbf = (branch_t*)NULL;
- }
-
- if (brh->nBULK.t != x->drainnode.t){
- if (!x->Gmbr){
- static functions_t *ff;
- x->Gmbr = (*(dev_vccs.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Gmbr->f);
- ff->expand = (void(*)())NULL;
- ff->trfun1 = mos2_gmbr1;
- ff->trfun0 = mos2_gmbr0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Gmbr->f = ff;
- }
- x->Gmbr->parent = brh;
- strcpy(x->Gmbr->label,"Gmbr");
- x->Gmbr->n[OUT1] = x->sourcenode;
- x->Gmbr->n[OUT2] = x->drainnode;
- x->Gmbr->n[IN1] = brh->nBULK;
- x->Gmbr->n[IN2] = x->drainnode;
- x->Gmbr->next = brh->subckt;
- x->Gmbr->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Gmbr);
- }else{
- x->Gmbr = (branch_t*)NULL;
- }
-
- if (!x->Yds){
- static functions_t *ff;
- x->Yds = (*(dev_admittance.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Yds->f);
- ff->expand = (void(*)())NULL;
- ff->trfun1 = mos2_gds1;
- ff->trfun0 = mos2_gds0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Yds->f = ff;
- }
- x->Yds->parent = brh;
- strcpy(x->Yds->label,"Yds");
- x->Yds->n[OUT1] = x->drainnode;
- x->Yds->n[OUT2] = x->sourcenode;
- x->Yds->next = brh->subckt;
- x->Yds->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Yds);
-
- if (brh->nGATE.t != x->sourcenode.t){
- if (!x->Gmf){
- static functions_t *ff;
- x->Gmf = (*(dev_vccs.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Gmf->f);
- ff->expand = (void(*)())NULL;
- ff->trfun1 = mos2_gmf1;
- ff->trfun0 = mos2_gmf0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Gmf->f = ff;
- }
- x->Gmf->parent = brh;
- strcpy(x->Gmf->label,"Gmf");
- x->Gmf->n[OUT1] = x->drainnode;
- x->Gmf->n[OUT2] = x->sourcenode;
- x->Gmf->n[IN1] = brh->nGATE;
- x->Gmf->n[IN2] = x->sourcenode;
- x->Gmf->next = brh->subckt;
- x->Gmf->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Gmf);
- }else{
- x->Gmf = (branch_t*)NULL;
- }
-
- if (brh->nGATE.t != x->drainnode.t){
- if (!x->Gmr){
- static functions_t *ff;
- x->Gmr = (*(dev_vccs.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Gmr->f);
- ff->expand = (void(*)())NULL;
- ff->trfun1 = mos2_gmr1;
- ff->trfun0 = mos2_gmr0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Gmr->f = ff;
- }
- x->Gmr->parent = brh;
- strcpy(x->Gmr->label,"Gmr");
- x->Gmr->n[OUT1] = x->sourcenode;
- x->Gmr->n[OUT2] = x->drainnode;
- x->Gmr->n[IN1] = brh->nGATE;
- x->Gmr->n[IN2] = x->drainnode;
- x->Gmr->prev = (branch_t*)NULL;
- x->Gmr->next = brh->subckt;
- brh->subckt = insertbranch(x->Gmr);
- }else{
- x->Gmr = (branch_t*)NULL;
- }
-
- if (!x->Ids){
- static functions_t *ff;
- x->Ids = (*(dev_cs.create))((branch_t*)NULL);
- if (!ff){
- ff = (functions_t*)calloc(1, sizeof(functions_t));
- *ff = *(x->Ids->f);
- ff->expand = (void(*)())NULL;
- ff->trfun1 = mos2_ids1;
- ff->trfun0 = mos2_ids0;
- ff->acfun = (complex_t(*)())NULL;
- }
- x->Ids->f = ff;
- }
- x->Ids->parent = brh;
- strcpy(x->Ids->label,"Ids");
- x->Ids->n[OUT1] = x->drainnode;
- x->Ids->n[OUT2] = x->sourcenode;
- x->Ids->next = brh->subckt;
- x->Ids->prev = (branch_t*)NULL;
- brh->subckt = insertbranch(x->Ids);
- brh->tracesubckt = NO;
- }
- /*--------------------------------------------------------------------------*/
- static double tr_review_mos(brh)
- branch_t *brh;
- {
- return tr_review_rl(brh->subckt);
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- SHAR_EOF
- fi # end of overwriting check
- if test -f 'src/d_mos2.c'
- then
- echo shar: will not over-write existing file "'src/d_mos2.c'"
- else
- cat << \SHAR_EOF > 'src/d_mos2.c'
- /* dev_mos2 03/27/92
- * Copyright 1983-1992 Albert Davis
- * mos model equations: spice level 2 equivalent
- */
- #include "ecah.h"
- #include "branch.h"
- #include "d_mos.h"
- #include "error.h"
- #include "io.h"
- #include "declare.h"
- /*--------------------------------------------------------------------------*/
- void eval_mos2(branch_t*);
- /*--------------------------------------------------------------------------*/
- #define short_channel (m->xj != NOT_INPUT && m->xj > 0.)
- #define do_subthreshold (m->nfs != 0.)
-
- extern const struct ioctrl io;
- extern const double temp;
- /*--------------------------------------------------------------------------*/
- void eval_mos2(brh)
- branch_t *brh;
- {
- static struct mos *x;
- static struct mmod *m;
- double sarg, dsarg_dvbs/*ds*/;
- double bargx;
- double gamma_s/*mb*/, dgamma_s_dvds/*ds*/, dgamma_s_dvbs/*mb*/;
- double beta;
- double body;
- double dvdsat_dvgs = 0./*m*/;
- double dvdsat_dvbs = 0./*mb*/;
- double vdsx;
- double vgst;
- double ufact;
- double dudvgs/*m*/, dudvds/*ds*/, dudvbs/*mb*/;
- double clfact;
- double dldvgs/*m*/, dldvds/*ds*/, dldvbs/*mb*/;
- double dodvbs/*mb*/;
- double xn = 0.;
- double vtxn = 0.;
- double expg;
- double dxndvb =0./*mb*/; /* subthreshold only */
- double ids_on, didvds;
- double vt/*ds*/;
- double v_phi_d, v_phi_s, v_phi_ds;
- double d2sdb2;
- double barg, dbarg_dvbs, d2bdb2;
- double bsarg, dbsarg_dvbs;
- double vbdsat;
- double dgddb2;
- double vc, vbin, vc_eta;
- double bodys;
- double lambda;
- double vbd;
- double von;
- double ueff = 0.;
-
- int use_vmax;
-
- x = (struct mos*)brh->x;
- m = x->m;
-
- use_vmax = m->vmax != NOT_INPUT;
- vt = (K/Q) * temp;
-
- v_phi_s = m->phi - x->vbs;
- if (x->vbs <= 0.){
- sarg = sqrt(v_phi_s);
- dsarg_dvbs = -.5 / sarg;
- d2sdb2 = .5 * dsarg_dvbs / v_phi_s;
- x->sbfwd = NO;
- }else{
- double sphi3 = pow(m->phi, 1.5);
- sarg = sqrt(m->phi) / (1. + .5 * x->vbs / m->phi);
- dsarg_dvbs = -.5 * sarg * sarg / sphi3;
- d2sdb2 = -dsarg_dvbs * sarg / sphi3;
- x->sbfwd = YES;
- if (!io.suppresserrors){
- error((x->vbs < -.01) ? bPICKY : bTRACE,
- "%s: source fwd biased. vbs=%g\n", printlabel(brh,NO), x->vbs);
- }
- }
-
- vbd = x->vbs - x->vds;
- v_phi_d = m->phi - vbd;
- if (vbd <= 0.){
- barg = sqrt(v_phi_d);
- dbarg_dvbs = -.5 / barg;
- d2bdb2 = .5 * dbarg_dvbs / v_phi_d;
- x->dbfwd = NO;
- }else{
- double sphi3 = pow(m->phi, 1.5);
- barg = sqrt(m->phi) / (1. + .5 * vbd / m->phi);
- dbarg_dvbs = -.5 * barg * barg / sphi3;
- d2bdb2 = -dbarg_dvbs * barg / sphi3;
- x->dbfwd = YES;
- if (!io.suppresserrors){
- error((vbd < -.01) ? bPICKY : bTRACE,
- "%s: drain fwd biased. vbd=%g\n", printlabel(brh,NO), vbd);
- }
- }
-
- if (short_channel){
- double wd, ws;
- double alpha_d, alpha_s;
- double dalpha_d_dvds, dalpha_d_dvbs;
- double dalpha_s_dvbs;
- double argxs, argxd;
- double args, argd;
- double dasdb2, daddb2;
-
- wd = m->xd * barg;
- argxd = 1. + 2.*wd/m->xj;
- argd = sqrt(argxd);
- alpha_d = x->relxj * (argd - 1.);
- dalpha_d_dvds = m->xd / (4. * x->le * argd * barg);
- dalpha_d_dvbs = -dalpha_d_dvds;
-
- ws = m->xd * sarg;
- argxs = 1. + 2.*ws/m->xj;
- args = sqrt(argxs);
- alpha_s = x->relxj * (args - 1.);
- dalpha_s_dvbs = -m->xd / (4. * x->le * args * sarg);
-
- gamma_s = m->gamma * (1. - alpha_s - alpha_d);
- dgamma_s_dvds = -m->gamma * dalpha_d_dvds;
- dgamma_s_dvbs = -m->gamma * (dalpha_d_dvbs + dalpha_s_dvbs);
-
- dasdb2 = -m->xd*(d2sdb2 + dsarg_dvbs*dsarg_dvbs*m->xd / (m->xj*argxs))
- / (x->le*args);
- daddb2 = -m->xd*(d2bdb2 + dbarg_dvbs*dbarg_dvbs*m->xd / (m->xj*argxd))
- / (x->le*argd);
- dgddb2 = -.5 * m->gamma * (dasdb2 + daddb2);
-
- if (gamma_s <= 0. && m->gamma > 0.){
- error(bWARNING, "%s: gamma is negative\n", printlabel(brh,NO));
- error(bTRACE , "+ gamma_s=%g, alpha_s=%g, alpha_d=%g\n",
- gamma_s, alpha_s, alpha_d);
- }
- }else{
- gamma_s = m->gamma;
- dgamma_s_dvds = dgamma_s_dvbs = 0.;
- dgddb2 = 0.;
- }
-
-
- vbin = m->vbi + x->eta_1 * v_phi_s;
- von = vbin + gamma_s * sarg;
-
- dodvbs = -x->eta_1 + dgamma_s_dvbs * sarg + gamma_s * dsarg_dvbs;
- if (do_subthreshold){
- double cdonco;
- dxndvb = 2. * dgamma_s_dvbs * dsarg_dvbs
- + gamma_s * d2sdb2 + dgddb2 * sarg;
- dodvbs += vt * dxndvb;
- cdonco = - (gamma_s * dsarg_dvbs + dgamma_s_dvbs * sarg) + x->eta_1;
- xn = 1. + m->cfsox + cdonco;
- vtxn = vt * xn;
- von += vtxn;
- x->subthreshold = (x->vgs < von);
- x->cutoff = NO;
- }else if (x->vgs < von){
- x->cutoff = YES;
- x->ids = 0.;
- x->gm = 0.;
- x->gds = 0.;
- x->gmb = 0.;
- return;
- }else{
- x->cutoff = x->subthreshold = NO;
- }
-
- x->vgsx = (x->subthreshold) ? von : x->vgs;
- vc = x->vgsx - vbin;
- vc_eta = vc / x->eta;
- vgst = x->vgs - von;
-
- if (m->uexp != NOT_INPUT && vgst > m->vbp){
- ufact = pow(m->vbp/vgst, m->uexp);
- dudvgs = -ufact * m->uexp / vgst;
- dudvds = 0.; /* wrong, but as per spice2 */
- dudvbs = dodvbs * ufact * m->uexp / vgst;
- }else{
- ufact = 1.;
- dudvgs = dudvds = dudvbs = 0.;
- }
-
- if (use_vmax){
- double sarg3, gammad;
- double v1, v2, xv, a1, b1, c1, d1;
- double a, b, c, r, s, r3, s2, p, p0, p2, y3;
- double xvalid = 0.;
- double x4[8];
- int iknt, j;
- int root_count;
- sarg3 = sarg*sarg*sarg;
- gammad = gamma_s / x->eta;
- ueff = m->uo * ufact;
- v1 = vc_eta + v_phi_s;
- v2 = v_phi_s;
- xv = m->vmax * x->le / ueff;
- a1 = gammad * (4./3.);
- b1 = -2. * (v1+xv);
- c1 = -2. * gammad * xv; /* end of scope */
- d1 = 2.*v1*(v2+xv) - v2*v2 - (4./3.)*gammad*sarg3; /* xv, v1, v2, sarg3 */
- a = -b1;
- b = a1 * c1 - 4. * d1;
- c = -d1 * (a1*a1 - 4.*b1) - c1*c1;
- r = -a*a / 3. + b;
- s = 2. * a*a*a / 27. - a*b / 3. + c; /* b, c */
- r3 = r*r*r; /* r */
- s2 = s*s;
- p = s2 / 4. + r3 / 27.; /* r3 */
- p0 = fabs(p);
- p2 = sqrt(p0);
- if (p < 0.){ /* p */
- double ro, fi;
- ro = pow((s2 / 4. + p0), (1./6.)); /* s2, p0 */
- fi = atan(-2. * p2 / s);
- y3 = 2. * ro * cos(fi/3.) - a / 3.;
- }else{
- double p3, p4;
- p3 = pow((fabs(-s/2.+p2)), (1./3.));
- p4 = pow((fabs(-s/2.-p2)), (1./3.)); /* s, p2 */
- y3 = p3 + p4 - a / 3.; /* a */
- }
-
- iknt = 0;
- if (a1*a1 / 4. - b1 + y3 < 0. && y3*y3 / 4. - d1 < 0.){
- error(bWARNING,
- "%s: internal error: a3,b4, a1=%g, b1=%g, y3=%g, d1=%g\n",
- printlabel(brh,NO), a1, b1, y3, d1);
- }else{
- double a3, b3;
- int i;
- a3 = sqrt(a1*a1 / 4. - b1 + y3);
- b3 = sqrt(y3*y3 / 4. - d1);
- for (i = 0; i < 4; i++){
- double delta4;
- double a4, b4;
- static const double sig1[4] = {1., -1., 1., -1.};
- static const double sig2[4] = {1., 1., -1., -1.};
- a4 = a1 / 2. + sig1[i] * a3;
- b4 = y3 / 2. + sig2[i] * b3; /* y3 */
- delta4 = a4*a4 / 4. - b4;
- if (delta4 >= 0.){
- x4[iknt++] = - a4 / 2. + sqrt(delta4);
- x4[iknt++] = - a4 / 2. - sqrt(delta4); /* i */
- }
- }
- }
-
- root_count = 0;
- for (j = 0; j < iknt; j++){ /* iknt */
- if (x4[j] > 0.){
- double poly4;
- poly4 = x4[j]*x4[j]*x4[j]*x4[j] /* ~= 0, used as check */
- + a1 * x4[j]*x4[j]*x4[j] /* roundoff error not */
- + b1 * x4[j]*x4[j] /* propagated, so ok */
- + c1 * x4[j]
- + d1; /* a1, b1, c1, d1 */
- if (fabs(poly4) <= 1e-6){
- root_count++;
- if (root_count <= 1) /* xvalid = min(x4[j]) */
- xvalid=x4[j];
- if (x4[j] <= xvalid)
- xvalid=x4[j]; /* x4[], j */
- }else{
- }
- }
- }
- if (root_count <= 0){ /* root_count */
- if (!io.suppresserrors)
- error(bDEBUG, "%s: Baum's theory rejected\n", printlabel(brh,NO));
- use_vmax = NO;
- }else{
- x->vdsat = xvalid*xvalid - v_phi_s;
- }
- }
-
- if (!use_vmax){
- if (gamma_s > 0.){
- double argv;
- argv = vc_eta + v_phi_s;
- if (argv > 0.){
- double gammad, gammd2, arg;
- gammad = gamma_s / x->eta;
- gammd2 = gammad * gammad;
- arg = sqrt(1. + 4. * argv / gammd2);
- x->vdsat = vc_eta + gammd2 * (1.-arg) / 2.;
- dvdsat_dvgs = (1. - 1./arg) / x->eta;
- dvdsat_dvbs = (gammad * (1.-arg) + 2.*argv / (gammad*arg))
- / x->eta * dgamma_s_dvbs
- + 1./arg + x->eta_1 * dvdsat_dvgs;
- }else{
- x->vdsat = 0.;
- dvdsat_dvgs = dvdsat_dvbs = 0.;
- error(bWARNING, "%s: vdsat: argv is negative\n", printlabel(brh,NO));
- error(bTRACE , "+ vc=%g, argv=%g, vdsat=%g\n",
- vc, argv, x->vdsat);
- }
- }else{
- x->vdsat = vc_eta;
- dvdsat_dvgs = 1.;
- dvdsat_dvbs = 0.;
- }
- }
-
- if (x->vdsat < 0.){
- error(bWARNING, "%s: calculated vdsat (%g) < 0. using vdsat = 0.\n",
- printlabel(brh,NO), x->vdsat);
- x->vdsat = 0.;
- }
-
- vbdsat = x->vbs - x->vdsat;
- v_phi_ds = m->phi - vbdsat;
- if (vbdsat <= 0.){
- bsarg = sqrt(v_phi_ds);
- dbsarg_dvbs = -.5 / bsarg;
- }else{
- double sphi3 = pow(m->phi, 1.5);
- bsarg = sqrt(m->phi) / (1. + .5 * vbdsat / m->phi);
- dbsarg_dvbs = -.5 * bsarg * bsarg / sphi3;
- }
- bodys = bsarg*bsarg*bsarg - sarg*sarg*sarg;
-
- if (use_vmax){
- double argv, vqchan, dqdsat, vl, dfunds, dfundg, dfundb, gdbdvs;
- gdbdvs = 2. * gamma_s * (bsarg*bsarg*dbsarg_dvbs - sarg*sarg*dsarg_dvbs);
- argv = vc_eta - x->vdsat;
- vqchan = argv - gamma_s * bsarg;
- dqdsat = -1. + gamma_s * dbsarg_dvbs;
- vl = m->vmax * x->le;
- dfunds = vl * dqdsat - ueff * vqchan;
- dfundg = (vl - ueff * x->vdsat) / x->eta;
- dfundb = -vl * (1. + dqdsat - x->eta_1 / x->eta)
- + ueff * (gdbdvs - dgamma_s_dvbs * bodys / 1.5) / x->eta;
- dvdsat_dvgs = -dfundg / dfunds;
- dvdsat_dvbs = -dfundb / dfunds;
- }
-
- if (m->lambda == NOT_INPUT){
- if (x->vds != 0.){
- double dldsat;
- if (use_vmax){
- double xdv, xlv, argv, xls;
- xdv = m->xd / sqrt(m->neff);
- xlv = m->vmax * xdv / (2. * ueff);
- argv = x->vds - x->vdsat;
- if (argv < 0.)
- argv = 0.;
- xls = sqrt(xlv*xlv + argv);
- lambda = (xls-xlv) * xdv / (x->le * x->vds);
- dldsat = xdv / (2. * xls * x->le);
- }else{
- double argv, sargv, dl;
- argv = (x->vds - x->vdsat) / 4.;
- sargv = sqrt(1. + argv*argv);
- if (argv + sargv >= 0.){
- dl = m->xd * sqrt(argv + sargv);
- lambda = dl / (x->le * x->vds);
- dldsat = lambda * x->vds / (8. * sargv);
- }else{
- lambda = 0.;
- dldsat = 0.;
- error(bWARNING, "%s: internal error: vds(%g) < vdsat(%g)\n",
- printlabel(brh,NO), x->vds, x->vdsat);
- }
- }
- dldvgs = dvdsat_dvgs * dldsat;
- dldvds = - dldsat;
- dldvbs = dvdsat_dvbs * dldsat;
- }else{
- lambda = 0.;
- dldvgs = dldvds = dldvbs = 0.;
- }
- }else{
- lambda = m->lambda;
- dldvgs = dldvbs = 0.;
- dldvds = -lambda;
- }
-
- clfact = (1. - lambda * x->vds);
- if (clfact < m->xwb/x->le){
- double leff, dfact;
- leff = m->xwb / (2. - (clfact * x->le / m->xwb));
- clfact = leff / x->le;
- dfact = (leff * leff) / (m->xwb * m->xwb);
- dldvgs *= dfact;
- dldvds *= dfact;
- dldvbs *= dfact;
- }
-
- x->saturated = (x->vds > x->vdsat);
- vdsx = (x->saturated) ? x->vdsat : x->vds;
- bargx = (x->saturated) ? bsarg : barg;
- body = bargx*bargx*bargx - sarg*sarg*sarg;
- expg = (x->subthreshold) ? exp(vgst / vtxn) : 1.;
- beta = x->beta * ufact / clfact;
-
- ids_on = beta * ((vc - x->eta_2 * vdsx) * vdsx - (2./3.) * gamma_s * body);
- didvds = beta * (vc - x->eta * vdsx - gamma_s * bargx);
-
- x->ids = ids_on * expg;
-
- x->gm = beta * vdsx;
- x->gm += ids_on * (dudvgs/ufact - dldvgs/clfact);
- if (x->saturated)
- x->gm += didvds * dvdsat_dvgs;
- if (x->subthreshold){
- x->gm = ids_on / vtxn;
- if (x->saturated)
- x->gm += didvds * dvdsat_dvgs;
- x->gm *= expg;
- }
- x->gds = (x->saturated) ? 0.: didvds;
- x->gds += ids_on * (dudvds/ufact - dldvds/clfact);
- if (short_channel)
- x->gds -= beta * (2./3.) * body * dgamma_s_dvds;
- if (x->subthreshold){
- double dodvds, dxndvd, gmw;
- dxndvd = dgamma_s_dvds * dsarg_dvbs;
- dodvds = dgamma_s_dvds * sarg + vt * dxndvd;
- gmw = x->ids * vgst / (vtxn * xn);
- x->gds *= expg;
- x->gds -= x->gm * dodvds + gmw * dxndvd;
- }
- x->gmb = beta * (x->eta_1 * vdsx - gamma_s * (sarg - bargx));
- x->gmb += ids_on * (dudvbs/ufact - dldvbs/clfact);
- if (short_channel)
- x->gmb -= beta * (2./3.) * body * dgamma_s_dvbs;
- if (x->saturated)
- x->gmb += didvds * dvdsat_dvbs;
- if (x->subthreshold){
- double gmw;
- gmw = x->ids * vgst / (vtxn * xn);
- x->gmb += beta * dodvbs * vdsx;
- x->gmb *= expg;
- x->gmb -= x->gm * dodvbs + gmw * dxndvb;
- }
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- SHAR_EOF
- fi # end of overwriting check
- if test -f 'src/d_mosc.c'
- then
- echo shar: will not over-write existing file "'src/d_mosc.c'"
- else
- cat << \SHAR_EOF > 'src/d_mosc.c'
- /* dev_mosc 03/31/92
- * Copyright 1983-1992 Albert Davis
- * mos model subcircuit functions
- */
- #include "ecah.h"
- #include "branch.h"
- #include "d_mos.h"
- #include "declare.h"
- /*--------------------------------------------------------------------------*/
- void mos2_ids0(branch_t*);
- void mos2_gmf0(branch_t*);
- void mos2_gmr0(branch_t*);
- void mos2_gds0(branch_t*);
- void mos2_gmbf0(branch_t*);
- void mos2_gmbr0(branch_t*);
- void mos_cgb0(branch_t*);
- void mos_cgd0(branch_t*);
- void mos_cgs0(branch_t*);
- void mos2_ids1(branch_t*);
- void mos2_gmf1(branch_t*);
- void mos2_gmr1(branch_t*);
- void mos2_gds1(branch_t*);
- void mos2_gmbf1(branch_t*);
- void mos2_gmbr1(branch_t*);
- void mos_cgb1(branch_t*);
- void mos_cgd1(branch_t*);
- void mos_cgs1(branch_t*);
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /* mos2_ids: drain-source current calculations
- * returns ids
- */
- /*--------------------------------------------------------------------------*/
- void mos2_ids0(brh)
- branch_t *brh;
- {
- brh->y0.f0 = brh->y0.x * brh->y0.f1;
- }
- /*--------------------------------------------------------------------------*/
- void mos2_ids1(brh)
- branch_t *brh;
- {
- struct mos *x;
- struct mmod *m;
-
- x = (struct mos*)brh->parent->x;
- m = x->m;
- if (brh->bypass){
- brh->y0 = brh->y1;
- brh->y1 = brh->y2;
- }else{
- double ids = (x->reversed) ? -x->ids : x->ids;
- brh->y0.f1 = m->polarity * ids;
- brh->y0.f0 = brh->y0.x * brh->y0.f1;
- brh->y0.f0 = LINEAR;
- }
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /* mos2_gmf: gate transconductance calculations forward mode
- * returns gm or 0
- */
- /*--------------------------------------------------------------------------*/
- /*ARGSUSED*/
- void mos2_gmf0(brh)
- branch_t *brh;
- {;}
- /*--------------------------------------------------------------------------*/
- void mos2_gmf1(brh)
- branch_t *brh;
- {
- struct mos *x;
-
- x = (struct mos*)brh->parent->x;
- if (brh->bypass){
- brh->y0 = brh->y1;
- brh->y1 = brh->y2;
- }else{
- brh->y0.f1 = (x->reversed) ? 0. : x->gm;
- brh->y0.f0 = 0.;
- }
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /* mos2_gmr: gate transconductance calculations reversed mode
- * returns gm or 0
- */
- /*--------------------------------------------------------------------------*/
- /*ARGSUSED*/
- void mos2_gmr0(brh)
- branch_t *brh;
- {;}
- /*--------------------------------------------------------------------------*/
- void mos2_gmr1(brh)
- branch_t *brh;
- {
- struct mos *x;
-
- x = (struct mos*)brh->parent->x;
- if (brh->bypass){
- brh->y0 = brh->y1;
- brh->y1 = brh->y2;
- }else{
- brh->y0.f1 = (x->reversed) ? x->gm : 0.;
- brh->y0.f0 = 0.;
- }
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /* mos2_gds: self-conductance calculations
- * returns gds
- */
- /*--------------------------------------------------------------------------*/
- /*ARGSUSED*/
- void mos2_gds0(brh)
- branch_t *brh;
- {;}
- /*--------------------------------------------------------------------------*/
- void mos2_gds1(brh)
- branch_t *brh;
- {
- struct mos *x;
-
- x = (struct mos*)brh->parent->x;
- if (brh->bypass){
- brh->y0 = brh->y1;
- brh->y1 = brh->y2;
- }else{
- brh->y0.f1 = x->gds;
- brh->y0.f0 = 0.;
- }
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /* mos2_gmbf: bulk transconductance calculations, forward mode
- * returns gmb or 0
- */
- /*--------------------------------------------------------------------------*/
- /*ARGSUSED*/
- void mos2_gmbf0(brh)
- branch_t *brh;
- {;}
- /*--------------------------------------------------------------------------*/
- void mos2_gmbf1(brh)
- branch_t *brh;
- {
- struct mos *x;
-
- x = (struct mos*)brh->parent->x;
- if (brh->bypass){
- brh->y0 = brh->y1;
- brh->y1 = brh->y2;
- }else{
- brh->y0.f1 = (x->reversed) ? 0. : x->gmb;
- brh->y0.f0 = 0.;
- }
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /* mos2_gmbr: bulk transconductance calculations, reversed mode
- * returns gmb or 0
- */
- /*--------------------------------------------------------------------------*/
- /*ARGSUSED*/
- void mos2_gmbr0(brh)
- branch_t *brh;
- {;}
- /*--------------------------------------------------------------------------*/
- void mos2_gmbr1(brh)
- branch_t *brh;
- {
- struct mos *x;
-
- x = (struct mos*)brh->parent->x;
- if (brh->bypass){
- brh->y0 = brh->y1;
- brh->y1 = brh->y2;
- }else{
- brh->y0.f1 = (x->reversed) ? x->gmb : 0.;
- brh->y0.f0 = 0.;
- }
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- void mos_cgb0(brh)
- branch_t *brh;
- {
- brh->y0.f0 = brh->y0.x * brh->y0.f1;
- }
- /*--------------------------------------------------------------------------*/
- void mos_cgb1(brh)
- branch_t *brh;
- {
- double c;
- struct mos *x;
- struct mmod *m;
-
- x = (struct mos*)brh->parent->x;
- m = x->m;
-
- c = brh->val;
- if (x->vgsx <= -m->phi){
- c += x->cgate;
- }else if (x->vgsx <= 0.){
- c -= x->vgsx * x->cgate / m->phi;
- }
-
- brh->y0.f1 = c;
- brh->y0.f0 = brh->y0.x * brh->y0.f1;
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- void mos_cgd0(brh)
- branch_t *brh;
- {
- brh->y0.f0 = brh->y0.x * brh->y0.f1;
- }
- /*--------------------------------------------------------------------------*/
- void mos_cgd1(brh)
- branch_t *brh;
- {
- double c;
- double vdbsat;
- double vdb;
- struct mos *x;
-
- x = (struct mos*)brh->parent->x;
- vdbsat = x->vdsat - x->vbs;
- vdb = x->vds - x->vbs;
-
- c = brh->val;
- if (vdbsat > vdb){
- double vddif = 2. * vdbsat - vdb;
- c += x->cgate * (1. - (vdbsat*vdbsat)/(vddif*vddif))/1.5;
- }
- brh->y0.f1 = c;
- brh->y0.f0 = brh->y0.x * brh->y0.f1;
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- void mos_cgs0(brh)
- branch_t *brh;
- {
- brh->y0.f0 = brh->y0.x * brh->y0.f1;
- }
- /*--------------------------------------------------------------------------*/
- void mos_cgs1(brh)
- branch_t *brh;
- {
- double c;
- double vdbsat;
- double vdb;
- struct mos *x;
- struct mmod *m;
-
- x = (struct mos*)brh->parent->x;
- m = x->m;
- vdbsat = x->vdsat - x->vbs;
- vdb = x->vds - x->vbs;
-
- c = brh->val;
- if (x->vgsx > 0.){
- if (vdbsat > vdb){
- double vddif = 2. * vdbsat - vdb;
- double vddif1 = vdbsat - vdb - 1.e-12; /* fudge??? */
- c += x->cgate * (1. - (vddif1*vddif1)/(vddif*vddif))/1.5;
- }else{
- c += x->cgate / 1.5;
- }
- }else if (x->vgsx > -m->phi/2.){
- c += x->cgate / (.75*m->phi) * x->vgsx + x->cgate / 1.5;
- }
-
- brh->y0.f1 = c;
- brh->y0.f0 = brh->y0.x * brh->y0.f1;
- }
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- /*--------------------------------------------------------------------------*/
- SHAR_EOF
- fi # end of overwriting check
- # End of shell archive
- exit 0
-