home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk1.iso
/
altsrc
/
articles
/
10852
< prev
next >
Wrap
Text File
|
1994-07-11
|
61KB
|
1,993 lines
Newsgroups: alt.sources
Path: wupost!crcnis1.unl.edu!news.mid.net!newsfeed.ksu.ksu.edu!moe.ksu.ksu.edu!vixen.cso.uiuc.edu!howland.reston.ans.net!cs.utexas.edu!convex!news.duke.edu!eff!news.kei.com!travelers.mail.cornell.edu!newstand.syr.edu!galileo.cc.rochester.edu!ee.rochester.edu!atd.rochester.ny.us!al
From: al@atd.rochester.ny.us (Al Davis)
Subject: ACS (Al's Circuit Simulator) version 0.14 part14/21
Message-ID: <1994Jul6.032705.13506@atd.rochester.ny.us>
Organization: Huh?
Date: Wed, 6 Jul 1994 03:27:05 GMT
Lines: 1983
Archive-name: acs-0.14/part14
Submitted-by: atd@cs.rit.edu
Supercedes: acs-0.13
Environment: UNIX, MS-DOS
#! /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_mos1.c
# src/d_mos2.c
# src/d_mos3.c
# src/d_mosc.c
# src/d_res.c
# src/d_subckt.c
# src/d_trln.c
# src/d_vccs.c
# src/d_vcvs.c
# src/d_vs.c
# This archive created: Tue Jul 5 15:24:08 1994
export PATH; PATH=/bin:$PATH
if test -f 'src/d_mos1.c'
then
echo shar: will not over-write existing file "'src/d_mos1.c'"
else
cat << \SHAR_EOF > 'src/d_mos1.c'
/* d_mos1.c 93.12.19
* mos model equations: spice level 1 equivalent
*/
#include "ecah.h"
#include "branch.h"
#include "d_mos.h"
#include "error.h"
#include "io.h"
#include "options.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
void eval_mos1(branch_t*);
/*--------------------------------------------------------------------------*/
extern const struct ioctrl io;
extern const struct options opt;
/*--------------------------------------------------------------------------*/
void eval_mos1(branch_t *brh)
{
static struct mos *x;
static struct mmod *m;
double sarg;
double dsarg_dvbs;
x = (struct mos*)brh->x;
m = x->m;
if (x->vbs <= 0.){
sarg = sqrt(m->phi - x->vbs);
dsarg_dvbs = -.5 / sarg;
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; /* is wrong!! */
x->sbfwd = YES;
if (!io.suppresserrors){
error((sarg <= 0.) ? bPICKY : bTRACE,
"%s: source fwd biased. vbs=%g\n", printlabel(brh,NO), x->vbs);
}
}
x->von = m->vto + m->gamma * (sarg - sqrt(m->phi));
x->vgst = x->vdsat = x->vgs - x->von;
if (x->vdsat < 0.)
x->vdsat = 0.;
x->cutoff = (x->vgst < 0.);
x->saturated = (x->vds > x->vdsat);
if (x->cutoff){
x->gm = x->ids = x->gmb = 0.;
x->gds = opt.gmin;
}else if (x->saturated){
x->gm = x->beta * x->vgst * (1. + m->lambda * x->vds);
x->ids = x->gm * (.5 * x->vgst);
x->gds = .5 * x->beta * m->lambda * x->vgst * x->vgst;
x->gmb = - x->gm * m->gamma * dsarg_dvbs;
}else{ /* linear */
x->gm = x->beta * x->vds * (1. + m->lambda * x->vds);
x->ids = x->gm * (x->vgst - .5*x->vds);
x->gds = x->beta *
((x->vgst - x->vds) + m->lambda * x->vds * (2.*x->vgst - 1.5*x->vds));
x->gmb = - x->gm * m->gamma * dsarg_dvbs;
}
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
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'
/* d_mos2.c 94.04.28
* 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 "options.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 struct options opt;
extern const double temp;
/*--------------------------------------------------------------------------*/
void eval_mos2(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 vgsx;
double vdsx;
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, vbs;
double ueff = 0.;
int use_vmax;
x = (struct mos*)brh->x;
m = x->m;
use_vmax = m->vmax != NOT_INPUT;
vt = (K/Q) * temp;
vbs = x->vbs;
v_phi_s = m->phi - vbs;
if (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);
if (opt.mosflags & 0001 && vbs > m->phi){
error(bDANGER,"%s: vbs(%g) > phi(%g)\n", printlabel(brh,0),vbs,m->phi);
vbs = m->phi;
v_phi_s = 0.;
}
sarg = sqrt(m->phi) / (1. + .5 * vbs / m->phi);
dsarg_dvbs = -.5 * sarg * sarg / sphi3;
d2sdb2 = -dsarg_dvbs * sarg / sphi3;
x->sbfwd = YES;
if (!io.suppresserrors){
error((x->vbs > m->phi) ? bPICKY : bTRACE,
"%s: source fwd biased. vbs=%g\n", printlabel(brh,NO), x->vbs);
}
}
if (opt.mosflags & 0004){
vbd = vbs - x->vds;
}else{
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);
if (opt.mosflags & 0002 && vbd > m->phi){
error(bDANGER,"%s: vbd(%g) > phi(%g)\n", printlabel(brh,0),vbd,m->phi);
vbd = m->phi;
v_phi_d = 0.;
}
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 > m->phi) ? bPICKY : bTRACE,
"%s: drain fwd biased. vbd=%g\n",printlabel(brh,NO), x->vbs-x->vds);
}
}
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. && !io.suppresserrors){
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;
x->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;
x->von += vtxn;
x->subthreshold = (x->vgs < x->von);
x->cutoff = NO;
}else if (x->vgs < x->von){
x->cutoff = YES;
x->subthreshold = NO;
x->ids = 0.;
x->gm = 0.;
if (opt.mosflags == 0100){
x->gds = opt.gmin;
}else{
x->gds = 0.;
}
x->gmb = 0.;
x->vgst = x->vgs - x->von;
return;
}else{
x->cutoff = x->subthreshold = NO;
}
vgsx = (x->subthreshold) ? x->von : x->vgs;
vc = vgsx - vbin;
vc_eta = vc / x->eta;
x->vgst = x->vgs - x->von;
if (m->uexp != NOT_INPUT && x->vgst > m->vbp){
ufact = pow(m->vbp/x->vgst, m->uexp);
dudvgs = -ufact * m->uexp / x->vgst;
dudvds = 0.; /* wrong, but as per spice2 */
dudvbs = dodvbs * ufact * m->uexp / x->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(bWARNING, "%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.;
if (!io.suppresserrors){
error(bWARNING, "%s: argv is negative\n", printlabel(brh,NO));
error(bTRACE , "+ vc=%g, argv=%g, vdsat=%g\n",
vc, argv, x->vdsat);
error(bTRACE , "+ vds=%g, vgs=%g, vbs=%g\n",
x->vds, x->vgs, x->vbs);
}
}
}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 = 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(x->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 * x->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 * x->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_mos3.c'
then
echo shar: will not over-write existing file "'src/d_mos3.c'"
else
cat << \SHAR_EOF > 'src/d_mos3.c'
/* dev_mos3 07/30/91 (XZ) 12/19/93, 94.01.13, 94.02.11
* mos model equations: spice level 3 equivalent
*/
#include "ecah.h"
#include "branch.h"
#include "d_diode.h"
#include "d_mos.h"
#include "error.h"
#include "io.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
extern const struct ioctrl io;
/*--------------------------------------------------------------------------*/
void eval_mos3(branch_t *brh)
{
static struct mos *x;
static struct mmod *m;
double phi_0, phi_vbs, phi_vbd, vbd;
double beta;
double sigma;
double ids;
double us, ueff;
double fb, fs, fn;
double wc, wp;
double va, vb;
double ep, ep_xd;
double theta_vgs;
double cox_w_le;
double fb_1;
double xd_2;
double gamma_fs;
double us2_vmax_le;
double us_vds_vmax, us_vds_vmax2;
double us_vdsat_vmax, us_vdsat_vmax2;
double xjwp_sq, xjwp_sqrt;
double vgs_vth_vdsat, ueff_sat, dueff_dvdsat, gdsat;
double del_le, lfac;
double vgs_vth_vds;
double dus_dvgs;
double dfs_dvbs;
double dueff_dvds, dueff_dvgs;
double dwp_dvbs, dwc_dvbs;
double dvth_dvbs;
double dbeta_dvds, dbeta_dvgs;
double dids_dvds, dids_dvgs, dids_dvbs;
double a = 0.0631354;
double b = 0.8013292;
double c = 0.01110777;
double vdsx, vgsx;
int use_vmax;
int use_xj;
x = (struct mos*)brh->x;
m = x->m;
use_vmax = (m->vmax != NOT_INPUT && m->vmax != 0.);
use_xj = (m->xj != NOT_INPUT && m->xj > 0.);
phi_0 = sqrt(m->phi);
if (x->vbs <= 0.){
phi_vbs = sqrt(m->phi - x->vbs);
x->sbfwd = NO;
}else{
phi_vbs = sqrt(m->phi) / (1. + .5 * x->vbs / m->phi);
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;
if (vbd <= 0.){
phi_vbd = sqrt(m->phi - vbd);
x->dbfwd = NO;
}else{
phi_vbd = sqrt(m->phi) / (1. + .5 * vbd / m->phi);
x->dbfwd = YES;
if (!io.suppresserrors){
error((vbd < -.01) ? bPICKY : bTRACE,
"%s: drain fwd biased. vbd=%g\n", printlabel(brh,NO), vbd);
}
}
/* threshold voltage */
sigma = 8.15e-22 * m->eta / (m->cox * x->le * x->le * x->le);
fn = (kPI * E_SI * m->delta) / (4. * m->cox * x->we);
wp = m->xd * sqrt(m->d->pb - x->vbs);
wc = use_xj ? a*m->xj + b*wp - c*wp*wp/m->xj : 0.;
xjwp_sq = wp / (m->xj + wp);
xjwp_sq *= xjwp_sq;
xjwp_sqrt = sqrt(1. - xjwp_sq);
fs = use_xj ? 1. - m->xj/x->le * ((m->ld + wc)/m->xj * xjwp_sqrt - m->ld/m->xj)
: 1.;
fb = m->gamma * fs / (2. * phi_vbs) + fn;
fb_1 = .5 * (1. + fb);
gamma_fs = m->gamma*fs*phi_vbs + fn*(m->phi - x->vbs);
x->von = m->vfb + m->phi - sigma*x->vds + gamma_fs;
x->vgst = x->vgs - x->von;
/* mobility modulation */
theta_vgs = 1. + m->theta * x->vgst;
us = m->uo / theta_vgs;
us_vds_vmax = use_vmax ? 1. + us * x->vds / (m->vmax * x->le)
: 1.;
us_vds_vmax2 = us_vds_vmax * us_vds_vmax;
us2_vmax_le = use_vmax ? -us*us / (m->vmax*x->le)
: 1.;
ueff = us / us_vds_vmax;
cox_w_le = m->cox * x->we / x->le;
beta = ueff * cox_w_le;
/* saturation voltage */
va = x->vgst / (1. + fb);
vb = use_vmax ? m->vmax * x->le / us : 0.;
x->vdsat = use_vmax ? va + vb - sqrt(va*va + vb*vb) : va;
vdsx = MIN(x->vds, x->vdsat);
vgsx = MAX(x->vgs, x->von);
ids = beta * (vgsx - x->von - fb_1*vdsx) * vdsx;
x->saturated = (x->vds > x->vdsat);
x->cutoff = (x->vgst < 0.);
if (x->cutoff){
lfac = 0.;
}else if (!x->saturated){
lfac = 1.;
}else{ /* channel-length modulation */
us_vdsat_vmax = use_vmax ? 1. + us * x->vdsat/(m->vmax * x->le)
: 1.;
us_vdsat_vmax2 = us_vdsat_vmax * us_vdsat_vmax;
ueff_sat = us / us_vdsat_vmax;
dueff_dvdsat = use_vmax ? us2_vmax_le / us_vdsat_vmax2
: 0.;
vgs_vth_vdsat = vgsx - x->von - fb_1*x->vdsat;
gdsat = (cox_w_le*dueff_dvdsat*x->vdsat + beta) * vgs_vth_vdsat -
beta * x->vdsat * (fb_1 - sigma);
xd_2 = m->xd * m->xd;
ep = m->kappa * ids / (gdsat * x->le);
ep_xd = .5 * ep * xd_2;
del_le = sqrt(m->kappa*xd_2*(x->vds - x->vdsat) + ep_xd*ep_xd) - ep_xd;
lfac = 1. / (1. - (del_le/x->le));
}
/* (trans)conductances */
vgs_vth_vds = vgsx - x->von - fb_1*x->vds;
dwp_dvbs = -.5 * m->xd / phi_vbs;
dwc_dvbs = use_xj ? (b - 2.*c*wp/m->xj) * dwp_dvbs : 0.;
dfs_dvbs = use_xj ? (m->ld + wc) * xjwp_sq / (x->le * m->xj * xjwp_sqrt) *
dwp_dvbs - xjwp_sqrt / x->le * dwc_dvbs
: 0.;
dus_dvgs = -m->uo * m->theta / (theta_vgs * theta_vgs);
dueff_dvgs = dus_dvgs / us_vds_vmax2;
dueff_dvds = use_vmax ? us2_vmax_le / us_vds_vmax2 : 0.;
dbeta_dvgs = dueff_dvgs * cox_w_le;
dbeta_dvds = cox_w_le * dueff_dvds;
dvth_dvbs = m->gamma * (phi_vbs*dfs_dvbs - .5*fs/phi_vbs);
dids_dvds = (dbeta_dvds + beta)*vgs_vth_vds - beta*x->vds*(fb_1 - sigma);
dids_dvgs = (dbeta_dvgs*vgs_vth_vds + beta) * x->vds;
dids_dvbs = -beta * x->vds * (dvth_dvbs + x->vds*m->gamma/(4.*phi_vbs)*
dfs_dvbs);
x->ids = ids * lfac;
x->gds = dids_dvds * lfac;
x->gm = dids_dvgs * lfac;
x->gmb = dids_dvbs * lfac;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
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'
/* d_mosc.c 93.12.19
* 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(branch_t *brh)
{
brh->y0.f0 = brh->y0.x * brh->y0.f1;
}
/*--------------------------------------------------------------------------*/
void mos2_ids1(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(branch_t *brh)
{;}
/*--------------------------------------------------------------------------*/
void mos2_gmf1(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(branch_t *brh)
{;}
/*--------------------------------------------------------------------------*/
void mos2_gmr1(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(branch_t *brh)
{;}
/*--------------------------------------------------------------------------*/
void mos2_gds1(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(branch_t *brh)
{;}
/*--------------------------------------------------------------------------*/
void mos2_gmbf1(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(branch_t *brh)
{;}
/*--------------------------------------------------------------------------*/
void mos2_gmbr1(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.;
}
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/* gate capacitors. Meyer model.
* Refs: Antognetti, Divekar, Spice 2 & 3 code
* final ref was Spice 2g6 code.
* all agree except for typos and smoothing. (yup!!)
*/
/*--------------------------------------------------------------------------*/
void mos_cgb0(branch_t *brh)
{
brh->y0.f0 = brh->y0.x * brh->y0.f1;
}
/*--------------------------------------------------------------------------*/
void mos_cgb1(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->vgst < - m->phi){ /* accumulation */
c += x->cgate;
}else if (x->vgst < 0.){ /* depletion */
c += x->cgate * (-x->vgst) / m->phi;
} /* active, overlap only */
brh->y0.f1 = c;
brh->y0.f0 = brh->y0.x * brh->y0.f1;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
void mos_cgd0(branch_t *brh)
{
brh->y0.f0 = brh->y0.x * brh->y0.f1;
}
/*--------------------------------------------------------------------------*/
void mos_cgd1(branch_t *brh)
{
double c;
struct mos *x;
x = (struct mos*)brh->parent->x;
c = brh->val; /* start with overlap cap */
if (x->vgst > x->vds){ /* linear */
double vdif = 2. * x->vgst - x->vds;
c += (2./3.) * x->cgate * (1. - (x->vgst*x->vgst)/(vdif*vdif));
} /* else overlap only */
brh->y0.f1 = c;
brh->y0.f0 = brh->y0.x * brh->y0.f1;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
void mos_cgs0(branch_t *brh)
{
brh->y0.f0 = brh->y0.x * brh->y0.f1;
}
/*--------------------------------------------------------------------------*/
void mos_cgs1(branch_t *brh)
{
double c;
struct mos *x;
struct mmod *m;
x = (struct mos*)brh->parent->x;
m = x->m;
c = brh->val; /* start with overlap cap */
if (x->vgst > x->vds){ /* linear */
double numer = x->vgst - x->vds;
double denom = 2. * x->vgst - x->vds;
c += (2./3.) * x->cgate * (1. - (numer*numer)/(denom*denom));
}else if (x->vgst > 0.){ /* saturation */
c += (2./3.) * x->cgate;
}else if (x->vgst > -m->phi/2.){ /* depletion */
c += (2./3.) * x->cgate * ((x->vgst / (m->phi/2.)) + 1.);
} /* accum. = overlap only */
brh->y0.f1 = c;
brh->y0.f0 = brh->y0.x * brh->y0.f1;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
SHAR_EOF
fi # end of overwriting check
if test -f 'src/d_res.c'
then
echo shar: will not over-write existing file "'src/d_res.c'"
else
cat << \SHAR_EOF > 'src/d_res.c'
/* d_res.c 94.05.30
* Copyright 1983-1992 Albert Davis
* functions for resistor.
* x = amps, y.f0 = volts, ev = y.f1 = ohms
*/
#include "ecah.h"
#include "branch.h"
#include "error.h"
#include "mode.h"
#include "options.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static void expand_resistor(branch_t*);
static int tr_resistor_lin(branch_t*);
static int tr_resistor_nl(branch_t*);
static void ac_resistor_lin(branch_t*);
static void ac_resistor_nl(branch_t*);
/*--------------------------------------------------------------------------*/
extern const struct options opt;
/*--------------------------------------------------------------------------*/
functions_t dev_resistor = {
(generic_t*)NULL, /* x */
sizeof(functions_t), /* ssize */
sizeof(branch_t), /* elementsize */
(functions_t*)NULL, /* super */
2, /* numnodes */
rnONEPORT, /* refnode */
rnONEPORT, /* isdevice */
create_std, /* create */
copy_std, /* copy */
parse_std, /* parse */
print_std, /* print */
expand_resistor, /* expand */
probe_std, /* probe */
tr_resistor_nl, /* dotr */
unloadpassive, /* untr */
ac_resistor_nl, /* doac */
trfix1, /* trfun1 */
trfix0, /* trfun0 */
acfix, /* acfun */
NULL, /* tr_guess */
NULL, /* tr_advance */
NULL /* tr_review */
};
functions_t dev_resistor_lin = {
(generic_t*)NULL, /* x */
sizeof(functions_t), /* ssize */
sizeof(branch_t), /* elementsize */
&dev_resistor, /* super */
2, /* numnodes */
rnLINEAR, /* refnode */
rnONEPORT, /* isdevice */
create_std, /* create */
copy_std, /* copy */
parse_std, /* parse */
print_std, /* print */
expand_resistor, /* expand */
probe_std, /* probe */
tr_resistor_lin, /* dotr */
unloadpassive, /* untr */
ac_resistor_lin, /* doac */
NULL, /* trfun1 */
NULL, /* trfun0 */
NULL, /* acfun */
NULL, /* tr_guess */
NULL, /* tr_advance */
NULL /* tr_review */
};
/*--------------------------------------------------------------------------*/
static void expand_resistor(branch_t *brh)
{
if (!brh->x){
brh->f = &dev_resistor_lin;
if (brh->val == 0.){
error(bPICKY, "%s: short circuit\n", printlabel(brh,NO));
brh->y0.f1 = opt.shortckt;
}else{
brh->y0.f1 = brh->val;
}
brh->y0.f0 = LINEAR;
brh->m0.f1 = 1./brh->y0.f1;
brh->m0.c0 = 0.;
brh->ev.x = brh->val;
brh->ev.y = 0.;
brh->acg.x = brh->m0.f1;
brh->acg.y = 0.;
}
}
/*--------------------------------------------------------------------------*/
static int tr_resistor_lin(branch_t *brh)
{
trloadpassive(brh);
return brh->converged = YES;
}
/*--------------------------------------------------------------------------*/
static int tr_resistor_nl(branch_t *brh)
{
brh->m0.x = tr_volts_limited(&(brh->n[OUT1]),&(brh->n[OUT2]));
brh->y0.x = brh->m0.c0 + brh->m0.f1 * brh->m0.x;
if (brh->f->trfun1){
(*brh->f->trfun1)(brh);
brh->m0.c0 = brh->y0.x - brh->y0.f0 / brh->y0.f1;
}else{
brh->y0.f1 = brh->val;
brh->y0.f0 = brh->y0.x * brh->y0.f1;
brh->m0.c0 = 0.;
}
if (brh->y0.f1 == 0.){
error(bPICKY, "%s: short circuit\n", printlabel(brh,NO));
brh->y0.f1 = opt.shortckt;
}
brh->m0.f1 = 1./brh->y0.f1;
brh->m0.c0 = brh->y0.x - brh->y0.f0 / brh->y0.f1;
trloadpassive(brh);
return brh->converged = conv_check(brh);
}
/*--------------------------------------------------------------------------*/
static void ac_resistor_lin(branch_t *brh)
{
acloadpassivereal(brh);
}
/*--------------------------------------------------------------------------*/
static void ac_resistor_nl(branch_t *brh)
{
if (brh->f->acfun){
double dcvolts = dc_volts(&(brh->n[OUT1]),&(brh->n[OUT2]));
brh->acbias = brh->m0.c0 + brh->m0.f1*dcvolts;
brh->ev = (*brh->f->acfun)(brh);
if (brh->ev.y == 0.){
if (brh->ev.x == 0.){
error(bPICKY, "%s: short circuit\n", printlabel(brh,NO));
brh->ev.x = opt.shortckt;
}
brh->acg.x = 1. / brh->ev.x;
brh->acg.y = 0.;
}else{
brh->acg = cflip(brh->ev);
}
acloadpassive(brh);
}else{
brh->ev.x = brh->y0.f1;
brh->ev.y = 0.;
brh->acg.x = 1. / brh->ev.x;
brh->acg.y = 0.;
acloadpassivereal(brh);
}
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
SHAR_EOF
fi # end of overwriting check
if test -f 'src/d_subckt.c'
then
echo shar: will not over-write existing file "'src/d_subckt.c'"
else
cat << \SHAR_EOF > 'src/d_subckt.c'
/* d_subckt.c 94.01.01
* Copyright 1983-1992 Albert Davis
* subcircuit stuff
* netlist syntax:
* device: Xxxxx <nodelist> <subckt-name>
* model: .subckt <subckt-name> <nodelist>
* (device cards)
* .ends <subckt-name>
*/
#include "ecah.h"
#include "branch.h"
#include "d_subckt.h"
#include "error.h"
#include "mode.h"
#include "types.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
void cmd_ends(const char*,int*);
static branch_t *create_subckt(const functions_t*);
static branch_t *copy_subckt(const branch_t*);
static void parse_subckt(branch_t*,const char*,int*);
static void print_subckt(const branch_t*,int,int);
static branch_t *create_model_subckt(const functions_t*);
static branch_t *copy_model_subckt(const branch_t*);
static void parse_model_subckt(branch_t*,const char*,int*);
static void print_model_subckt(const branch_t*,int,int);
static void expand_subckt(branch_t*);
void expandsubckt(branch_t*,const char*);
static double probe_subckt(const branch_t*,const char*);
static int tr_subckt(branch_t*);
static void un_subckt(branch_t*);
static void ac_subckt(branch_t*);
static double tr_review_subckt(branch_t*);
/*--------------------------------------------------------------------------*/
static struct subckt defalt = {(generic_t*)NULL, sizeof(struct subckt),
(generic_t*)NULL, sDEFAULT_modelname, /*more*/};
static struct smod defaltmodel = {(generic_t*)NULL, sizeof(struct smod),
(generic_t*)NULL, sDEFAULT_modelname, /*more*/};
static branch_t modellist = {(generic_t*)NULL, sizeof(branch_t),
&model_subckt, &modellist, &modellist, &modellist, &modellist,
(branch_t*)NULL, (branch_t*)NULL, sDEFAULT_modelname, /*more*/};
static branch_t *(neststack[RECURSE]);
static char namestack[LABELEN+1][RECURSE];
static int nestlevel;
extern branch_t *insertbefore;
extern const char e_int[];
/*--------------------------------------------------------------------------*/
functions_t dev_subckt = {
(generic_t*)&defalt, /* x */
sizeof(functions_t), /* ssize */
sizeof(branch_t), /* elementsize */
(functions_t*)NULL, /* super */
PORTSPERSUBCKT, /* numnodes */
rnALL, /* refnode */
YES, /* isdevice */
create_subckt, /* create */
copy_subckt, /* copy */
parse_subckt, /* parse */
print_subckt, /* print */
expand_subckt, /* expand */
probe_subckt, /* probe */
tr_subckt, /* 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_subckt = {
(generic_t*)&defaltmodel, /* x */
sizeof(functions_t), /* ssize */
sizeof(branch_t), /* elementsize */
(functions_t*)NULL, /* super */
PORTSPERSUBCKT, /* numnodes */
rnMODEL, /* refnode */
NO, /* isdevice */
create_model_subckt, /* create */
copy_model_subckt, /* copy */
parse_model_subckt, /* parse */
print_model_subckt, /* print */
NULL, /* expand */
NULL, /* probe */
NULL, /* dotr */
NULL, /* untr */
NULL, /* doac */
NULL, /* trfun1 */
NULL, /* trfun0 */
NULL, /* acfun */
NULL, /* tr_guess */
NULL, /* tr_advance */
NULL /* tr_review */
};
/*--------------------------------------------------------------------------*/
void cmd_ends(const char* cmd, int *cnt)
{
if (nestlevel == 0)
error(bWARNING, "ends not in subckt\n");
else
nestlevel--;
if (cmd[*cnt]){
if (!pmatch(cmd, cnt, namestack[nestlevel]))
error(bERROR, "ends tag [%s] does not match subckt [%s]\n",
&cmd[*cnt], namestack[nestlevel]);
}else{
nestlevel = 0;
}
insertbefore = neststack[nestlevel];
}
/*--------------------------------------------------------------------------*/
static branch_t *create_subckt(const functions_t *func)
{
branch_t *brh;
struct subckt *x;
brh = create_std(func);
x = (struct subckt*)brh->x;
brh->n = x->n;
return brh;
}
/*--------------------------------------------------------------------------*/
static branch_t *copy_subckt(const branch_t *proto)
{
branch_t *brh;
struct subckt *x;
brh = copy_std(proto);
x = (struct subckt*)brh->x;
brh->n = x->n;
return brh;
}
/*--------------------------------------------------------------------------*/
static void parse_subckt(branch_t *brh, const char *cmd, int *cnt)
{
struct subckt *x;
x = (struct subckt*)brh->x;
parselabel(brh,cmd,cnt);
(void)parsenodes(brh,cmd,cnt,PORTSPERSUBCKT);
(void)ctostr(cmd, cnt, x->modelname, LABELEN);
}
/*--------------------------------------------------------------------------*/
static void print_subckt(const branch_t *brh, int where, int detail)
{
struct subckt *x;
x = (struct subckt*)brh->x;
(void)printlabel(brh,where);
printnodes(brh,where);
mprintf(where, " %s\n", x->modelname);
}
/*--------------------------------------------------------------------------*/
static branch_t *create_model_subckt(const functions_t *func)
{
branch_t *brh;
struct smod *x;
brh = create_std(func);
x = (struct smod*)brh->x;
brh->n = x->n;
brh->stprev = &modellist;
return brh;
}
/*--------------------------------------------------------------------------*/
static branch_t *copy_model_subckt(const branch_t *proto)
{
branch_t *brh;
struct smod *x;
brh = copy_std(proto);
x = (struct smod*)brh->x;
brh->n = x->n;
brh->stprev = &modellist;
return brh;
}
/*--------------------------------------------------------------------------*/
static void parse_model_subckt(branch_t *brh, const char *cmd, int *cnt)
{
struct smod *m;
m = (struct smod*)brh->x;
if (nestlevel >= RECURSE)
error(bERROR,"%s: subckt nesting too deep\n", printlabel(brh,NO));
(void)ctostr(cmd, cnt, brh->label, LABELEN);
(void)parsenodes(brh,cmd,cnt,PORTSPERSUBCKT);
strcpy(namestack[nestlevel], brh->label);
neststack[nestlevel] = insertbefore;
nestlevel++;
brh->subckt = insertbefore = insertbranch(create_branch(&dev_comment));
m->x = (generic_t*)NULL;
}
/*--------------------------------------------------------------------------*/
static void print_model_subckt(const branch_t *brh, int where, int detail)
{
branch_t *x, *stop;
mprintf(where, ".subckt %s ", brh->label);
printnodes(brh,where);
mprintf(where, "\n");
x = stop = brh->subckt;
if (x){
do {
print_branch(x, where, NO);
} while (x = x->next, x != stop);
}
mprintf(where, "*+ends %s\n", brh->label);
}
/*--------------------------------------------------------------------------*/
static void expand_subckt(branch_t *brh)
{
struct subckt *x;
x = (struct subckt*)brh->x;
expandsubckt(brh,x->modelname);
if (!brh->subckt){
error(bERROR, "");
}
brh->tracesubckt = YES;
}
/*--------------------------------------------------------------------------*/
void expandsubckt(branch_t *brh, const char *modelname)
{
const branch_t *model;
/*struct subckt *x;*/
branch_t *scan;
branch_t *stop;
int port, i;
int map[NODESPERSUBCKT];
/*x = (struct subckt*)brh->x;*/
model = &modellist; /* search for thing to copy */
for (;;){
model = model->stnext;
if (wmatch(modelname, model->label)){
break;
}else if (model == &modellist){
error(bDANGER, "%s: can't find model: %s\n",
printlabel(brh,NO), modelname);
if (brh->subckt){
error(bERROR, e_int, "subckt exists but has no def\n");
}else{
return;
}
}
}
for (i = 0; i < NODESPERSUBCKT; i++) /* initialize: all nodes unused */
map[i] = UNUSED;
stop = scan = nextbranch_dev(model->subckt);
do { /* scan elements of subckt */
int ii; /* mark nodes used */
for (ii = 0; scan->n[ii].e != INVALIDNODE; ii++){
if (scan->n[ii].e > NODESPERSUBCKT)
error(bERROR, "%s: too many internal nodes\n", model->label);
map[scan->n[ii].e] = USED;
}
} while (scan=nextbranch_dev(scan), scan != stop);
map[0] = 0;
for (port = 0; model->n[port].e != INVALIDNODE; port++){ /* map ports */
if (model->n[port].e > NODESPERSUBCKT)
error(bERROR, "internal error: subckt node out of range: %s\n",
model->label);
map[model->n[port].e] = brh->n[port].t;
}
for (i = 0; i < NODESPERSUBCKT; i++){
if (map[i] == USED){
map[i] = newnode_subckt(); /* assign number to internal nodes */
}
}
if (!brh->subckt){
error(bTRACE, "%s: expanding\n", printlabel(brh,NO));
stop = scan = nextbranch_dev(model->subckt);
do {
branch_t *scratch; /* copy subckt */
scratch = copy_branch(scan);
scratch->parent = brh;
scratch->next = brh->subckt;
brh->subckt = insertbranch(scratch);
} while (scan=nextbranch_dev(scan), scan != stop);
}else{
error(bTRACE, "%s: re-expanding\n", printlabel(brh,NO));
}
stop = scan = nextbranch_dev(brh->subckt);
do { /* patch nodes */
int ii;
for (ii = 0; scan->n[ii].e != INVALIDNODE; ii++){
if (scan->n[ii].e < 0)
error(bERROR, e_int, "bad node");
if (map[scan->n[ii].e] < 0)
error(bERROR, e_int, "node map");
scan->n[ii].t = map[scan->n[ii].e];
}
scan->n[ii].t = INVALIDNODE;
} while (scan=nextbranch_dev(scan), scan != stop);
}
/*--------------------------------------------------------------------------*/
static double probe_subckt(const branch_t *brh, const char *what)
{
node_t ground;
int dummy = 0;
ground.e = ground.m = ground.t = 0;
if (!brh->subckt)
error(bERROR, "internal error: %s not expanded\n", printlabel(brh,NO));
setmatch(what,&dummy);
if (rematch("V")){
int nn = ctoi(what,&dummy); /* BUG: no bounds check */
return tr_volts(&(brh->n[nn+1]),&ground);
}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{ /* bad parameter */
return NOT_VALID;
}
/*NOTREACHED*/
}
/*--------------------------------------------------------------------------*/
static int tr_subckt(branch_t *brh)
{
if (!brh->subckt)
error(bERROR, "internal error: %s not expanded\n", printlabel(brh,NO));
return brh->converged = tr_fill_rl(brh->subckt);
}
/*--------------------------------------------------------------------------*/
static void un_subckt(branch_t *brh)
{
tr_unfill_rl(brh->subckt);
}
/*--------------------------------------------------------------------------*/
static void ac_subckt(branch_t *brh)
{
if (!brh->subckt)
error(bERROR, "internal error: %s not expanded\n", printlabel(brh,NO));
ac_fill_rl(brh->subckt);
}
/*--------------------------------------------------------------------------*/
static double tr_review_subckt(branch_t *brh)
{
return tr_review_rl(brh->subckt);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
SHAR_EOF
fi # end of overwriting check
if test -f 'src/d_trln.c'
then
echo shar: will not over-write existing file "'src/d_trln.c'"
else
cat << \SHAR_EOF > 'src/d_trln.c'
/* d_trln.c 93.12.22
* Copyright 1983-1992 Albert Davis
* Transmission line. (ideal lossless. for now, AC only)
*/
#include "ecah.h"
#include "ac.h"
#include "argparse.h"
#include "branch.h"
#include "d_trln.h"
#include "error.h"
#include "mode.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static void parse_trnlin(branch_t*,const char*,int*);
static void setinitcond(const char*,int*);
static void print_trnlin(const branch_t*,int,int);
static int tr_trnlin(branch_t*);
static void ac_trnlin(branch_t*);
/*--------------------------------------------------------------------------*/
#define LINLENTOL .000001
extern const ac_t ac;
static struct trnlin *x;
static struct trnlin defalt = {(generic_t*)NULL, sizeof(struct trnlin),
DEFAULT_Z0, DEFAULT_TD, DEFAULT_F, DEFAULT_NL, {0.,0.,0.,0.}, 0., NO};
/*--------------------------------------------------------------------------*/
functions_t dev_trnlin = {
(generic_t*)&defalt, /* x */
sizeof(functions_t), /* ssize */
sizeof(branch_t), /* elementsize */
(functions_t*)NULL, /* super */
4, /* numnodes */
rnTWOPORT, /* refnode */
rnTWOPORT, /* isdevice */
create_std, /* create */
copy_std, /* copy */
parse_trnlin, /* parse */
print_trnlin, /* print */
NULL, /* expand */
NULL, /* probe */
tr_trnlin, /* dotr */
NULL, /* untr */
ac_trnlin, /* doac */
NULL, /* trfun1 */
NULL, /* trfun0 */
NULL, /* acfun */
NULL, /* tr_guess */
NULL, /* tr_advance */
NULL /* tr_review */
};
/*--------------------------------------------------------------------------*/
/* parse_trnlin: parse input for transmission line, set up branch structure
*/
static void parse_trnlin(branch_t *brh, const char *cmd, int *cnt)
{
x = (struct trnlin*)brh->x;
parselabel(brh,cmd,cnt);
(void)parsenodes(brh,cmd,cnt,4);
for (;;){
if (argparse(cmd,cnt,REPEAT,
"Z", a2DOUBLE, &x->z0, &x->z0,
"Freq", aUDOUBLE, &x->f,
"Nl", aUDOUBLE, &x->nl,
"Ic", aFUNCTION, setinitcond,
""))
;
else{
syntax_check(cmd,cnt,bWARNING);
break;
}
}
if (x->nl == 0.)
x->nl = DEFAULT_NL;
x->reson = x->f * (.25 / x->nl);
}
/*--------------------------------------------------------------------------*/
/* setinitcond: set initial conditions
* called indirectly thru argparse
* reads NUM_INIT_COND args, put them in static struct x.
* passed this way because of inability of argparse to return values,
* and that only cmd and cnt are passed by argparse
*/
static void setinitcond(const char *cmd, int *cnt)
{
int i;
x->icset = YES;
for (i=0; i<NUM_INIT_COND; i++)
x->ic[i] = ctof(cmd,cnt);
}
/*--------------------------------------------------------------------------*/
/* print_trnlin: print (to "where") the transmission line data structure
*/
static void print_trnlin(const branch_t *brh, int where, int detail)
{
struct trnlin *x;
(void)printlabel(brh,where);
printnodes(brh,where);
x = (struct trnlin*)brh->x;
mprintf(where, " Z0=%s F=%s NL=%s",
ftos(x->z0, "", 7, 0),
ftos(x->f, "", 7, 0),
ftos(x->nl, "", 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));
}
mputc('\n', where);
}
/*--------------------------------------------------------------------------*/
/* tr_trnlin: transmission line for transient analysis
* stub: doesn't work
* always returns failure
*/
static int tr_trnlin(branch_t *brh)
{
error(bWARNING, "%s: no transmission line in dc or transient\n",
printlabel(brh,NO));
return brh->converged = YES;
}
/*--------------------------------------------------------------------------*/
/* ac_trnlin: transmission line procesing for AC analysis
*/
static void ac_trnlin(branch_t *brh)
{
double y11, y12; /* equivalent y parameters (y22, y21 are same) */
double lenth; /* length, first in quarter waves, then radians */
double dif; /* difference between actual length and resonance */
struct trnlin *x;
x = (struct trnlin*)brh->x;
lenth = ac.freq / x->reson;
dif = lenth - floor(lenth+.5);
if (fabs(dif) < LINLENTOL){
error(bPICKY,
"%s: transmission line too close to resonance\n", printlabel(brh,NO));
lenth = (dif<0.) ? floor(lenth+.5)-LINLENTOL : floor(lenth+.5)+LINLENTOL;
}
lenth *= (kPId2); /* now in radians */
y12 = -1 / ( x->z0 * sin(lenth) );
y11 = tan(lenth/2) / x->z0 + y12;
*im(brh->n[OUT1].m,brh->n[OUT1].m) += y11; /* BUG: bypasses load functions */
*im(brh->n[OUT2].m,brh->n[OUT2].m) += y11; /* result is flags may not be */
*im(brh->n[OUT1].m,brh->n[OUT2].m) -= y11; /* updated. No problem yet in */
*im(brh->n[OUT2].m,brh->n[OUT1].m) -= y11; /* AC but this will not work in */
/* transient. */
*im(brh->n[IN1].m,brh->n[IN1].m) += y11;
*im(brh->n[IN2].m,brh->n[IN2].m) += y11;
*im(brh->n[IN1].m,brh->n[IN2].m) -= y11;
*im(brh->n[IN2].m,brh->n[IN1].m) -= y11;
*im(brh->n[OUT1].m,brh->n[IN1].m) -= y12;
*im(brh->n[OUT2].m,brh->n[IN2].m) -= y12;
*im(brh->n[OUT1].m,brh->n[IN2].m) += y12;
*im(brh->n[OUT2].m,brh->n[IN1].m) += y12;
*im(brh->n[IN1].m,brh->n[OUT1].m) -= y12;
*im(brh->n[IN2].m,brh->n[OUT2].m) -= y12;
*im(brh->n[IN1].m,brh->n[OUT2].m) += y12;
*im(brh->n[IN2].m,brh->n[OUT1].m) += y12;
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
SHAR_EOF
fi # end of overwriting check
if test -f 'src/d_vccs.c'
then
echo shar: will not over-write existing file "'src/d_vccs.c'"
else
cat << \SHAR_EOF > 'src/d_vccs.c'
/* d_vccs.c 94.05.30
* Copyright 1983-1992 Albert Davis
* functions for vccs
*/
#include "ecah.h"
#include "branch.h"
#include "mode.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static int tr_vccs(branch_t*);
static void ac_vccs(branch_t*);
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
functions_t dev_vccs = {
(generic_t*)NULL, /* x */
sizeof(functions_t), /* ssize */
sizeof(branch_t), /* elementsize */
(functions_t*)NULL, /* super */
4, /* numnodes */
rnTWOPORT, /* refnode */
rnTWOPORT, /* isdevice */
create_std, /* create */
copy_std, /* copy */
parse_std, /* parse */
print_std, /* print */
NULL, /* expand */
probe_std, /* probe */
tr_vccs, /* dotr */
unloadactive, /* untr */
ac_vccs, /* doac */
trfix1, /* trfun1 */
trfix0, /* trfun0 */
acfix, /* acfun */
NULL, /* tr_guess */
NULL, /* tr_advance */
NULL /* tr_review */
};
/*--------------------------------------------------------------------------*/
static int tr_vccs(branch_t *brh)
{
brh->m0.x = tr_volts_limited(&(brh->n[IN1]),&(brh->n[IN2]));
brh->y0.x = brh->m0.x;
if (brh->f->trfun1){
(*brh->f->trfun1)(brh);
brh->m0.c0 = brh->y0.f0 - brh->y0.x * brh->y0.f1;
}else{
brh->y0.f1 = brh->val;
brh->y0.f0 = brh->y0.x * brh->y0.f1;
brh->m0.c0 = 0.;
}
brh->m0.x = brh->y0.x;
brh->m0.f1 = brh->y0.f1;
trloadactive(brh);
return brh->converged = conv_check(brh);
}
/*--------------------------------------------------------------------------*/
static void ac_vccs(branch_t *brh)
{
if (brh->f->acfun){
brh->acbias = dc_volts(&(brh->n[IN1]),&(brh->n[IN2]));
brh->acg = brh->ev = (*brh->f->acfun)(brh);
}else{
brh->ev.x = brh->y0.f1;
brh->ev.y = 0.;
brh->acg = brh->ev;
}
acloadactive(brh);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
SHAR_EOF
fi # end of overwriting check
if test -f 'src/d_vcvs.c'
then
echo shar: will not over-write existing file "'src/d_vcvs.c'"
else
cat << \SHAR_EOF > 'src/d_vcvs.c'
/* d_vcvs.c 94.05.30
* Copyright 1983-1992 Albert Davis
* functions for vcvs
* temporary kluge: it has resistance
* BUG: doesn't work in incmode
*/
#include "ecah.h"
#include "branch.h"
#include "mode.h"
#include "options.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static int tr_vcvs(branch_t*);
static void ac_vcvs(branch_t*);
/*--------------------------------------------------------------------------*/
extern const struct options opt;
static branch_t resistor = {(generic_t*)NULL, sizeof(branch_t),
(functions_t*)NULL, (branch_t*)NULL, (branch_t*)NULL, (branch_t*)NULL,
(branch_t*)NULL, /*more*/};
/*--------------------------------------------------------------------------*/
functions_t dev_vcvs = {
(generic_t*)NULL, /* x */
sizeof(functions_t), /* ssize */
sizeof(branch_t), /* elementsize */
(functions_t*)NULL, /* super */
4, /* numnodes */
rnTWOPORT, /* refnode */
rnTWOPORT, /* isdevice */
create_std, /* create */
copy_std, /* copy */
parse_std, /* parse */
print_std, /* print */
NULL, /* expand */
probe_std, /* probe */
tr_vcvs, /* dotr */
unloadactive, /* untr */
ac_vcvs, /* doac */
trfix1, /* trfun1 */
trfix0, /* trfun0 */
acfix, /* acfun */
NULL, /* tr_guess */
NULL, /* tr_advance */
NULL /* tr_review */
};
/*--------------------------------------------------------------------------*/
static int tr_vcvs(branch_t *brh)
{
resistor.n = brh->n;
resistor.loaditer = 0;
resistor.y0.f1 = 1./opt.shortckt; /* load the resistor */
resistor.y0.f0 = LINEAR; /* a big fudge */
resistor.m0.x = resistor.y0.x;
resistor.m0.c0 = 0.;
resistor.m0.f1 = resistor.y0.f1;
trloadpassive(&resistor);
/* then do vccs */
brh->m0.x = tr_volts_limited(&(brh->n[IN1]),&(brh->n[IN2]));
brh->y0.x = brh->m0.x;
if (brh->f->trfun1){
(*brh->f->trfun1)(brh);
brh->m0.c0 = (brh->y0.f0 - brh->y0.x * brh->y0.f1) / -opt.shortckt;
}else{
brh->y0.f1 = brh->val;
brh->y0.f0 = brh->y0.x * brh->y0.f1;
brh->m0.c0 = 0.;
}
brh->m0.f1 = brh->y0.f1 / -opt.shortckt;
trloadactive(brh);
return brh->converged = conv_check(brh);
}
/*--------------------------------------------------------------------------*/
static void ac_vcvs(branch_t *brh)
{
brh->acg.x = 1./opt.shortckt;
brh->acg.y = 0.;
acloadpassivereal(brh);
if (brh->f->acfun){
brh->acbias = dc_volts(&(brh->n[IN1]),&(brh->n[IN2]));
brh->ev = (*brh->f->acfun)(brh);
brh->acg.x = brh->ev.x / -opt.shortckt;
brh->acg.y = brh->ev.y / -opt.shortckt;
}else{
brh->ev.x = brh->y0.f1;
brh->ev.y = 0.;
brh->acg.x = brh->ev.x / -opt.shortckt;
brh->acg.y = 0.;
}
acloadactive(brh);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
SHAR_EOF
fi # end of overwriting check
if test -f 'src/d_vs.c'
then
echo shar: will not over-write existing file "'src/d_vs.c'"
else
cat << \SHAR_EOF > 'src/d_vs.c'
/* d_vs.c 94.05.30
* Copyright 1983-1992 Albert Davis
* functions for fixed voltage sources
* temporary kluge: it has resistance
*/
#include "ecah.h"
#include "branch.h"
#include "mode.h"
#include "options.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static int tr_vs(branch_t*);
static void ac_vs(branch_t*);
/*--------------------------------------------------------------------------*/
extern const struct options opt;
/*--------------------------------------------------------------------------*/
functions_t dev_vs = {
(generic_t*)NULL, /* x */
sizeof(functions_t), /* ssize */
sizeof(branch_t), /* elementsize */
(functions_t*)NULL, /* super */
2, /* numnodes */
rnONEPORT, /* refnode */
rnNISOURCE, /* isdevice */
create_std, /* create */
copy_std, /* copy */
parse_std, /* parse */
print_std, /* print */
NULL, /* expand */
probe_std, /* probe */
tr_vs, /* dotr */
unloadpassive, /* untr */
ac_vs, /* doac */
trfix1, /* trfun1 */
trfix0, /* trfun0 */
acfix, /* acfun */
NULL, /* tr_guess */
NULL, /* tr_advance */
NULL /* tr_review */
};
/*--------------------------------------------------------------------------*/
static int tr_vs(branch_t *brh)
{
brh->m0.x = 0.;
brh->y0.x = 0.;
if (brh->f->trfun1){
(*brh->f->trfun1)(brh);
}else{
brh->y0.f1 = brh->val;
brh->y0.f0 = 0.;
}
brh->m0.f1 = 1./opt.shortckt;
brh->m0.c0 = brh->y0.f1 / -opt.shortckt;
trloadpassive(brh);
return brh->converged = conv_check(brh);
}
/*--------------------------------------------------------------------------*/
static void ac_vs(branch_t *brh)
{
if (brh->f->acfun){
brh->acbias = 0.;
brh->ev = (*brh->f->acfun)(brh);
brh->acg.x = brh->ev.x / -opt.shortckt;
brh->acg.y = brh->ev.y / -opt.shortckt;
acloadsource(brh);
}else{
brh->ev.x = brh->ev.y = 0.; /* a DC only source */
}
brh->acg.x = 1./opt.shortckt;
brh->acg.y = 0.;
acloadpassivereal(brh);
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0