/* d_mos.c  94.12.09
 * 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 "d_diode.h"
#include "d_mos.h"
#include "d_subckt.h"
#include "error.h"
#include "io.h"
#include "mode.h"
#include "nodestat.h"
#include "options.h"
#include "status.h"
#include "types.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
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 functions_t*);
static	branch_t *copy_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	probe_mos(const branch_t*,const char*);
static 	int	tr_mos(branch_t*);
static	void	   limit_mos(struct mos*,double,double,double);
static	void	expand_mos(branch_t*);
/*--------------------------------------------------------------------------*/
extern char e_int[];
extern struct ioctrl io;
extern const int inc_mode;	/* make incremental changes		    */
extern const int sim_mode;
extern const int bypass_ok;
extern struct nodestuff ns;
extern const struct options opt;
extern const struct status stats;
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, /*more*/};
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_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, /*more*/};
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*/};
/*--------------------------------------------------------------------------*/
functions_t dev_mos = {
   (generic_t*)&defalt,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   (functions_t*)NULL,	/* super */
   4, 			/* numnodes */
   3, 			/* refnode */
   YES,			/* isdevice */
   create_std,		/* create */
   copy_std,		/* copy */
   parse_mos,		/* parse */
   print_mos,		/* print */
   expand_mos,		/* expand */
   probe_mos,		/* probe */
   NULL,		/* tr_probe */
   NULL,		/* ac_probe */
   NULL,		/* xprobe */
   tr_mos,		/* dotr */
   un_subckt,		/* untr */
   ac_subckt,		/* doac */
   NULL,		/* trfun1 */
   NULL,		/* trfun0 */
   NULL,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   tr_review_subckt	/* tr_review */
};
functions_t dev_mos_reversed = {
   (generic_t*)&defalt,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   &dev_mos,		/* super */
   4, 			/* numnodes */
   1, 			/* refnode */
   YES,			/* isdevice */
   create_std,		/* create */
   copy_std,		/* copy */
   parse_mos,		/* parse */
   print_mos,		/* print */
   expand_mos,		/* expand */
   probe_mos,		/* probe */
   NULL,		/* tr_probe */
   NULL,		/* ac_probe */
   NULL,		/* xprobe */
   tr_mos,		/* dotr */
   un_subckt,		/* untr */
   ac_subckt,		/* doac */
   NULL,		/* trfun1 */
   NULL,		/* trfun0 */
   NULL,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   tr_review_subckt	/* tr_review */
};
functions_t model_mos = {
   (generic_t*)&defaltmodel,	/* x */
   sizeof(functions_t),	/* ssize */
   sizeof(branch_t),	/* elementsize */
   (functions_t*)NULL,	/* super */
   0, 			/* numnodes */
   rnMODEL,		/* refnode */
   NO,			/* isdevice */
   create_model_mos,	/* create */
   copy_model_mos,	/* copy */
   parse_model_mos,	/* parse */
   print_model_mos,	/* print */
   NULL,		/* expand */
   NULL,		/* probe */
   NULL,		/* tr_probe */
   NULL,		/* ac_probe */
   NULL,		/* xprobe */
   NULL,		/* dotr */
   NULL,		/* untr */
   NULL,		/* doac */
   NULL,		/* trfun1 */
   NULL,		/* trfun0 */
   NULL,		/* acfun */
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
/*--------------------------------------------------------------------------*/
static void parse_mos(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);
 (void)ctostr(cmd, cnt, x->modelname, LABELEN, TOKENTERM);
 x->m = (struct mmod*)NULL;
 if (isdigit(cmd[*cnt])  ||  cmd[*cnt] == '.'){
    x->wo = 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->wo,
 	"AD",	aUDOUBLE,	&x->ad_in,
 	"AS",	aUDOUBLE,	&x->as_in,
 	"PD",	aUDOUBLE,	&x->pd,
 	"PS",	aUDOUBLE,	&x->ps,
 	"NRD",	aUDOUBLE,	&x->nrd,
 	"NRS",	aUDOUBLE,	&x->nrs,
 	""))
       ;
    else{
       syntax_check(cmd,cnt,bWARNING);
       break;
    }
 }
}
/*--------------------------------------------------------------------------*/
static void print_mos(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);
 if (x->lo != NOT_INPUT)
    mprintf(where, " l=%s ",  ftos(x->lo, "", 7, 0));
 if (x->wo != NOT_INPUT)
    mprintf(where, " w=%s ",  ftos(x->wo,  "", 7, 0));
 if (x->ad_in != NOT_INPUT)
    mprintf(where, " ad=%s ", ftos(x->ad_in, "", 7, 0));
 if (x->as_in != NOT_INPUT)
    mprintf(where, " as=%s ", ftos(x->as_in, "", 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(const functions_t *func)
{
 branch_t *brh;

 brh = create_std(func);
 brh->stprev = &modellist;
 return brh;
}
/*--------------------------------------------------------------------------*/
static branch_t *copy_model_mos(const branch_t *proto)
{
 branch_t *brh;

 brh = copy_std(proto);
 brh->stprev = &modellist;
 return brh;
}
/*--------------------------------------------------------------------------*/
static void parse_model_mos(branch_t *brh, const char *cmd, int *cnt)
{
 struct mmod *m;
 
 m = (struct mmod*)brh->x;

 (void)ctostr(cmd, cnt, brh->label, LABELEN, TOKENTERM);
 if (argparse(cmd,cnt,ONEPASS,
	"NMos",	aENUM,		&m->polarity,	pN,
	"PMos",	aENUM,		&m->polarity,	pP,
 	""))
        ;
 else
    syntax_check(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->d->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_check(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->d->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->d->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->d->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(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->d->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 probe_mos(const branch_t *brh, const char *what)
{
 struct mos *x;
 node_t ground;
 int dummy = 0;

 ground.e = ground.m = ground.t = 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("VGD")){
    return tr_volts(&(brh->nGATE),&(brh->nDRAIN));
 }else if (rematch("VBD")){
    return tr_volts(&(brh->nBULK),&(brh->nDRAIN));
 }else if (rematch("VSD")){
    return tr_volts(&(brh->nSOURCE),&(brh->nDRAIN));
 }else if (rematch("VDM")){
    return (tr_volts(&(brh->nDRAIN),&(brh->nSOURCE))
    	  + tr_volts(&(brh->nDRAIN),&(brh->nDRAIN))) / 2.;
 }else if (rematch("VGM")){
    return (tr_volts(&(brh->nGATE),&(brh->nSOURCE))
    	  + tr_volts(&(brh->nGATE),&(brh->nDRAIN))) / 2.;
 }else if (rematch("VBM")){
    return (tr_volts(&(brh->nBULK),&(brh->nSOURCE))
    	  + tr_volts(&(brh->nBULK),&(brh->nDRAIN))) / 2.;
 }else if (rematch("VSM")){
    return (tr_volts(&(brh->nSOURCE),&(brh->nSOURCE))
    	  + tr_volts(&(brh->nSOURCE),&(brh->nDRAIN))) / 2.;
 }else if (rematch("VDG")){
    return tr_volts(&(brh->nDRAIN),&(brh->nGATE));
 }else if (rematch("VBG")){
    return tr_volts(&(brh->nBULK),&(brh->nGATE));
 }else if (rematch("VSG")){
    return tr_volts(&(brh->nSOURCE),&(brh->nGATE));
 }else if (rematch("VDB")){
    return tr_volts(&(brh->nDRAIN),&(brh->nBULK));
 }else if (rematch("VGB")){
    return tr_volts(&(brh->nGATE),&(brh->nBULK));
 }else if (rematch("VSB")){
    return tr_volts(&(brh->nSOURCE),&(brh->nBULK));
 }else if (rematch("VD")){
    return tr_volts(&(brh->nDRAIN),&ground);
 }else if (rematch("VG")){
    return tr_volts(&(brh->nGATE),&ground);
 }else if (rematch("VB")){
    return tr_volts(&(brh->nBULK),&ground);
 }else if (rematch("VS")){
    return tr_volts(&(brh->nSOURCE),&ground);
 }else if (rematch("Id")){
    return (x->Rd)
	?   probe_branch(x->Rd,"I")
	:   probe_branch(x->Ids,"I")
	  + probe_branch(x->Gmf,"I")
	  + probe_branch(x->Gmr,"I")
	  + probe_branch(x->Yds,"I")
	  + probe_branch(x->Gmbf,"I")
	  + probe_branch(x->Gmbr,"I")
	  - probe_branch(x->Cgd,"I")
	  + probe_branch(x->Ddb,"I") * x->m->polarity;
 }else if (rematch("IS")){
    return (x->Rs)
	?   probe_branch(x->Rs,"I")
	: - probe_branch(x->Ids,"I")
	  - probe_branch(x->Gmf,"I")
	  - probe_branch(x->Gmr,"I")
	  - probe_branch(x->Yds,"I")
	  - probe_branch(x->Gmbf,"I")
	  - probe_branch(x->Gmbr,"I")
	  - probe_branch(x->Cgs,"I")
	  + probe_branch(x->Dsb,"I") * x->m->polarity;
 }else if (rematch("IG")){
    return probe_branch(x->Cgs,"I")
	 + probe_branch(x->Cgd,"I")
	 + probe_branch(x->Cgb,"I");
 }else if (rematch("IB")){
    return - probe_branch(x->Ddb,"I") * x->m->polarity
	   - probe_branch(x->Dsb,"I") * x->m->polarity
	   - probe_branch(x->Cgb,"I");
 }else if (rematch("CGSOvl")){
    return probe_branch(x->Cgs,"NV");
 }else if (rematch("CGDOvl")){
    return probe_branch(x->Cgd,"NV");
 }else if (rematch("CGBOvl")){
    return probe_branch(x->Cgb,"NV");
 }else if (rematch("CGST")){
    return probe_branch(x->Cgs,"EV");
 }else if (rematch("CGDT")){
    return probe_branch(x->Cgd,"EV");
 }else if (rematch("CGBT")){
    return probe_branch(x->Cgb,"EV");
 }else if (rematch("CGSm")){
    return probe_branch(x->Cgs,"EV") - probe_branch(x->Cgs,"NV");
 }else if (rematch("CGDm")){
    return probe_branch(x->Cgd,"EV") - probe_branch(x->Cgd,"NV");
 }else if (rematch("CGBm")){
    return probe_branch(x->Cgb,"EV") - probe_branch(x->Cgb,"NV");
 }else if (rematch("CBD")){
    return probe_branch(x->Ddb,"Cap");
 }else if (rematch("CBS")){
    return probe_branch(x->Dsb,"Cap");
 }else if (rematch("CGATE")){
    return x->cgate;
 }else if (rematch("GM")){
    return x->gm;
 }else if (rematch("GDS")){
    return x->gds;
 }else if (rematch("GMB")){
    return x->gmb;
 }else if (rematch("VDSAT")){
    return x->vdsat * x->m->polarity;
 }else if (rematch("VTH")){
    return x->von * x->m->polarity;
 }else if (rematch("IDS")){
    return x->ids;
 }else if (rematch("IDSTray")){
    return - probe_branch(x->Cgd,"I")
	  + probe_branch(x->Ddb,"I") * x->m->polarity;
 }else if (rematch("IDERror")){
    return  probe_branch(x->Gmf,"I")
	  + probe_branch(x->Gmr,"I")
	  + probe_branch(x->Yds,"I")
	  + probe_branch(x->Gmbf,"I")
	  + probe_branch(x->Gmbr,"I");
 }else if (rematch("P")){
    branch_t *pb, *stop;
    double power = 0.;
    stop = pb = brh->subckt;
    do {
       power += probe_branch(pb,"P");
    } while (pb=nextbranch_dev(pb), pb != stop);
    return power;
 }else if (rematch("PD")){
    branch_t *pb, *stop;
    double power = 0.;
    stop = pb = brh->subckt;
    do {
       power += probe_branch(pb,"PD");
    } while (pb=nextbranch_dev(pb), pb != stop);
    return power;
 }else if (rematch("PS")){
    branch_t *pb, *stop;
    double power = 0.;
    stop = pb = brh->subckt;
    do {
       power += probe_branch(pb,"PS");
    } 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 if (rematch("DTNew")){
    return brh->timef - brh->time0;
 }else if (rematch("DTOld")){
    return brh->time0 - brh->time1;
 }else if (rematch("TIMEF")){
    return brh->timef;
 }else if (rematch("TIME")){
    return brh->time0;
 }else if (rematch("TIMEO")){
    return brh->time1;
 }else{ /* bad parameter */
    return NOT_VALID;
 }
/*NOTREACHED*/
}
/*--------------------------------------------------------------------------*/
static int tr_mos(branch_t *brh)
{
 struct mos *x;
 struct mmod *m;
 double vds, vgs, vbs;
 
 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 = ns.nm[x->sourcenode.t];
 x->drainnode.m  = ns.nm[x->drainnode.t];

 if (stats.iter[sim_mode] <= 1){
    x->reversed = NO;
    vds = vgs = vbs = 0.;
    if (opt.mosflags & 0200){
       vgs = m->vto;
    }else if (opt.mosflags & 0400){
       vbs = -1;
    }
 }else if (x->reversed){
    vds = m->polarity * tr_volts_limited(&(x->sourcenode),&(x->drainnode));
    vgs = m->polarity * tr_volts_limited(&(brh->nGATE),&(x->drainnode));
    vbs = m->polarity * tr_volts_limited(&(brh->nBULK),&(x->drainnode));
 }else{
    vds = m->polarity * tr_volts_limited(&(x->drainnode),&(x->sourcenode));
    vgs = m->polarity * tr_volts_limited(&(brh->nGATE),&(x->sourcenode));
    vbs = m->polarity * tr_volts_limited(&(brh->nBULK),&(x->sourcenode));
 }
 
 if (bypass_ok  &&  (brh->converged  ||  opt.bypass == bVOLT)
 	&& conchk(x->vds, vds, opt.vntol)
	&& conchk(x->vgs, vgs, opt.vntol)
 /**/	&& conchk(x->vbs, vbs, opt.vntol)){
    brh->bypass = YES;
    if (!inc_mode){
       (void)tr_fill_rl(brh->subckt);
    }
    brh->converged = YES;
 }else{
    brh->bypass = NO;
    if (opt.mosflags){
       limit_mos(x, vds, vgs, vbs);
    }else{
       x->vds = vds;
       x->vgs = vgs;
       x->vbs = vbs;
    }
    if (x->vds < 0){
       x->reversed = !x->reversed;
       x->vgs -= x->vds;
       x->vbs -= x->vds;
       x->vds = -x->vds;
       if (opt.mosflags & 0040){
	 x->vbs = MIN(x->vbs,0.);
       }
    }
    switch (m->level){
       case 1:
	  eval_mos1(brh);
	  break;
       case 2:
	  eval_mos2(brh);
	  break;
       default:
	  error(bERROR, e_int, "mos level");
	  break;
    }
    brh->converged = tr_fill_rl(brh->subckt);
 }
 return brh->converged;
}
/*--------------------------------------------------------------------------*/
/* limit_mos: do Spice style voltage limiting
 */
static void limit_mos(struct mos *x, double vds, double vgs, double vbs)
{
 if (opt.mosflags & 0010 && stats.iter[sim_mode] > 1){
    if (vgs > x->vgs){			/* Spice style gate limiting */
       if (x->vgst < 0){
	  x->vgs = MIN(vgs, x->von + .5);
       }else if (x->vgst < 3.5){
	  x->vgs = MIN(vgs, x->von + 4.);
       }else{
	  x->vgs = MIN(vgs, 3. * x->vgs - 2. * x->von + 2.);
       }
    }else{
       if (x->vgst < 0){
	  x->vgs = MAX(vgs, 3. * x->vgs - 2. * x->von - 2.);
       }else if (x->vgst < 3.5){
	  x->vgs = MAX(vgs, x->von - .5);
       }else{
	  x->vgs = MAX(vgs, x->von + 2.);
       }
    }
    vds += x->vgs - vgs;
 }else{
    x->vgs = vgs;
 }
 if (opt.mosflags & 0020 && stats.iter[sim_mode] > 1){
    if (vds <= x->vds){			/* Spice style vds limiting */
       if (x->vds < 3.5)
	  x->vds = MAX(vds,-.5);
       else
	  x->vds = MAX(vds,2.);
    }else{
       if (x->vds < 3.5)
	  x->vds = MIN(vds,4.);
       else
	  x->vds = MIN(vds,3.*x->vds+2.);
    }
    x->vgs += x->vds - vds;
 }else{
    x->vds = vds;
 }
 if (opt.mosflags & 0040 && stats.iter[sim_mode] > 1){
    x->vbs = MIN(vbs,0.);
 }else{
    x->vbs = vbs;
 }
}
/*--------------------------------------------------------------------------*/
static void expand_mos(branch_t *brh)
{
 const struct mmod *m;
 struct mos *x;
 
 expandgeneric(brh,&modellist);
 x = (struct mos*)brh->x;
 m = x->m;

 if (x->lo != NOT_INPUT){
    x->le = x->lo - 2. * m->ld;
 }else{
    x->le = opt.defl - 2. * m->ld;
 }
 x->we = (x->wo != NOT_INPUT) ? x->wo : opt.defw;
 
 x->cgate = m->cox * x->we * x->le;
 if (x->cgate <= 0.)
    error(bERROR, "%s: cgate is negative?\n", printlabel(brh,NO));
 x->beta = m->kp * x->we / x->le;
 x->relxj = (m->xj != NOT_INPUT  &&  m->xj > 0.)
    ? .5 * m->xj / x->le
    : NOT_INPUT;
 x->eta_1 = (kPI/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 (opt.rstray && x->rs != 0.){
    x->sourcenode.t = newnode_model();
    if (!x->Rs)
       x->Rs = create_branch(&dev_resistor);
    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;
    (void)deletebranch(&x->Rs);
 }
 if (opt.rstray && x->rd != 0.){
    x->drainnode.t = newnode_model();
    if (!x->Rd)
       x->Rd = create_branch(&dev_resistor);
    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;
    (void)deletebranch(&x->Rd);
 }

								  /* diodes */
 x->ad = (x->ad_in != NOT_INPUT) ? x->ad_in : opt.defad;
 x->as = (x->as_in != NOT_INPUT) ? x->as_in : opt.defas;
 if (m->js == NOT_INPUT  ||  x->ad == 0.  ||  x->as == 0.){
    if (m->is == NOT_INPUT){
       x->idsat = x->issat = mDEFMODLR_is;
       error(bWARNING,"%s: ignoring js, using default is\n",printlabel(brh,0));
    }else{
       x->idsat = x->issat = m->is;	/* this convoluted logic */
    }					/* is for Spice compatibility */
 }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 = create_branch(&dev_diode);
    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;
    xd->perim = x->pd;
    xd->is = x->idsat;
    xd->cj = m->cbd;	/* if NOT_INPUT diode will calculate it */
    xd->cjsw = NOT_INPUT;
    xd->m = x->m->d;
    xd->off = YES;
    x->Ddb->next = brh->subckt;
    x->Ddb->prev = (branch_t*)NULL;
    brh->subckt = insertbranch(x->Ddb);
 }else{
    (void)deletebranch(&x->Ddb);
 }
 
 if (brh->nBULK.t != x->sourcenode.t   &&   x->issat != 0.){
    struct diode *xd;
    if (!x->Dsb)
       x->Dsb = create_branch(&dev_diode);
    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;
    xd->perim = x->ps;
    xd->is = x->issat;
    xd->cj = m->cbs;	/* if NOT_INPUT diode will calculate it */
    xd->cjsw = NOT_INPUT;
    xd->m = x->m->d;
    xd->off = YES;
    x->Dsb->next = brh->subckt;
    x->Dsb->prev = (branch_t*)NULL;
    brh->subckt = insertbranch(x->Dsb);
 }else{
    (void)deletebranch(&x->Dsb);
 }
							      /* capacitors */
 if (opt.cstray  &&  brh->nGATE.t != x->sourcenode.t){
    if (!x->Cgs){
       static functions_t *ff;
       if (!ff){
	  ff = (functions_t*)calloc(1, sizeof(functions_t));
	  *ff = dev_cap;
	  ff->expand = NULL;		/* no gate capacitance */
	  ff->trfun1 = mos_cgs1;		/* if no overlap cap */
	  ff->trfun0 = mos_cgs0;
	  ff->acfun = NULL;
	  ff->refnode = rnCOMP;
       }
       x->Cgs = create_branch(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->we;
    x->Cgs->next = brh->subckt;
    x->Cgs->prev = (branch_t*)NULL;
    brh->subckt = insertbranch(x->Cgs);
 }else{
    (void)deletebranch(&x->Cgs);
 }

 if (opt.cstray  &&  brh->nGATE.t != x->drainnode.t){
    if (!x->Cgd){
       static functions_t *ff;
       if (!ff){
	  ff = (functions_t*)calloc(1, sizeof(functions_t));
	  *ff = dev_cap;
	  ff->expand = NULL;
	  ff->trfun1 = mos_cgd1;
	  ff->trfun0 = mos_cgd0;
	  ff->acfun = NULL;
	  ff->refnode = rnCOMP;
       }
       x->Cgd = create_branch(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->we;
    x->Cgd->next = brh->subckt;
    x->Cgd->prev = (branch_t*)NULL;
    brh->subckt = insertbranch(x->Cgd);
 }else{
    (void)deletebranch(&x->Cgd);
 }

 if (opt.cstray  &&  brh->nBULK.t != brh->nGATE.t){
    if (!x->Cgb){
       static functions_t *ff;
       if (!ff){
	  ff = (functions_t*)calloc(1, sizeof(functions_t));
	  *ff = dev_cap;
	  ff->expand = NULL;
	  ff->trfun1 = mos_cgb1;
	  ff->trfun0 = mos_cgb0;
	  ff->acfun = NULL;
	  ff->refnode = rnCOMP;
       }
       x->Cgb = create_branch(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{
    (void)deletebranch(&x->Cgb);
 }
							   /* model sources */
 if (brh->nBULK.t != x->sourcenode.t){
    if (!x->Gmbf){
       static functions_t *ff;
       if (!ff){
	  ff = (functions_t*)calloc(1, sizeof(functions_t));
	  *ff = dev_vccs;
	  ff->expand = NULL;
	  ff->trfun1 = mos2_gmbf1;
	  ff->trfun0 = mos2_gmbf0;
	  ff->acfun = NULL;
	  ff->refnode = rnCOMP;
       }
       x->Gmbf = create_branch(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{
    (void)deletebranch(&x->Gmbf);
 }

 if (brh->nBULK.t != x->drainnode.t){
    if (!x->Gmbr){
       static functions_t *ff;
       if (!ff){
	  ff = (functions_t*)calloc(1, sizeof(functions_t));
	  *ff = dev_vccs;
	  ff->expand = NULL;
	  ff->trfun1 = mos2_gmbr1;
	  ff->trfun0 = mos2_gmbr0;
	  ff->acfun = NULL;
	  ff->refnode = rnCOMP;
       }
       x->Gmbr = create_branch(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{
    (void)deletebranch(&x->Gmbr);
 }

 if (!x->Yds){
    static functions_t *ff;
    if (!ff){
       ff = (functions_t*)calloc(1, sizeof(functions_t));
       *ff = dev_admittance;
       ff->expand = NULL;
       ff->trfun1 = mos2_gds1;
       ff->trfun0 = mos2_gds0;
       ff->acfun = NULL;
       ff->refnode = rnCOMP;
    }
    x->Yds = create_branch(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;
       if (!ff){
	  ff = (functions_t*)calloc(1, sizeof(functions_t));
	  *ff = dev_vccs;
	  ff->expand = NULL;
	  ff->trfun1 = mos2_gmf1;
	  ff->trfun0 = mos2_gmf0;
	  ff->acfun = NULL;
	  ff->refnode = rnCOMP;
       }
       x->Gmf = create_branch(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{
    (void)deletebranch(&x->Gmf);
 }

 if (brh->nGATE.t != x->drainnode.t){
    if (!x->Gmr){
       static functions_t *ff;
       if (!ff){
	  ff = (functions_t*)calloc(1, sizeof(functions_t));
	  *ff = dev_vccs;
	  ff->expand = NULL;
	  ff->trfun1 = mos2_gmr1;
	  ff->trfun0 = mos2_gmr0;
	  ff->acfun = NULL;
	  ff->refnode = rnCOMP;
       }
       x->Gmr = create_branch(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{
    (void)deletebranch(&x->Gmr);
 }

 if (!x->Ids){
    static functions_t *ff;
    if (!ff){
       ff = (functions_t*)calloc(1, sizeof(functions_t));
       *ff = dev_cs;
       ff->expand = NULL;
       ff->trfun1 = mos2_ids1;
       ff->trfun0 = mos2_ids0;
       ff->acfun = NULL;
       ff->refnode = rnCOMP;
    }
    x->Ids = create_branch(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;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
