/* d_bjt.c  94.12.09
 * Copyright 1983-1992   Albert Davis
 * bjt model.
 * this is not really a bjt, but a diode
 * It exists only as a frame.  Don't use it!!!!
 * netlist syntax:
 * device:  qxxxx n+ n- mname <area> <off> <ic=vd> <model-card-args>
 * model:   .model mname D <args>
 */
#include "ecah.h"
#include "argparse.h"
#include "branch.h"
#include "d_bjt.h"
#include "d_diode.h"
#include "error.h"
#include "mode.h"
#include "types.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
static 	void    parse_bjt(branch_t*,const char*,int*);
static 	void    print_bjt(const branch_t*,int,int);
static	branch_t	*create_model_bjt(const functions_t*);
static	branch_t	*copy_model_bjt(const branch_t*);
static 	void	parse_model_bjt(branch_t*,const char*,int*);
static 	void	print_model_bjt(const branch_t*,int,int);
static 	void	expand_bjt(branch_t*);
static 	int	tr_bjt(branch_t*);
static 	void	ac_bjt(branch_t*);
static	void	evalbjt(branch_t*);
static	void	bjtcap(branch_t*);
/*--------------------------------------------------------------------------*/
static struct bjt *x;
static struct bjt defalt = {(generic_t*)NULL, sizeof(struct bjt),
    (struct qmod*)NULL, qDEFDEV_modelname, qDEFDEV_is, qDEFDEV_rs,
    qDEFDEV_cj, qDEFDEV_cjsw, qDEFDEV_area, qDEFDEV_perim,
    qDEFDEV_ic, qDEFDEV_off};
static struct qmod defaltmodel = {(generic_t*)NULL, sizeof(struct qmod),
    qDEFMOD_js, qDEFMOD_rs, qDEFMOD_n, qDEFMOD_tt, qDEFMOD_cj,
    qDEFMOD_pb, qDEFMOD_mj, qDEFMOD_eg, qDEFMOD_xti, qDEFMOD_kf,
    qDEFMOD_af, qDEFMOD_fc, qDEFMOD_bv, qDEFMOD_ibv, qDEFMOD_cjsw,
    qDEFMOD_mjsw, qDEFMOD_fcpb};
static branch_t modellist = {(generic_t*)&defaltmodel, sizeof(branch_t),
    &model_bjt, &modellist, &modellist, &modellist, &modellist,
    (branch_t*)NULL, (branch_t*)NULL, qDEFMOD_modelname, /* more */};
/*--------------------------------------------------------------------------*/
functions_t dev_bjt = {
   (generic_t*)&defalt,
   sizeof(functions_t),
   sizeof(branch_t),
   (functions_t*)NULL,	/* super */
   2, 			/* numnodes */
   1, 			/* refnode */
   YES,			/* isdevice */
   create_std,
   copy_std,
   parse_bjt,
   print_bjt,
   expand_bjt,
   NULL,		/* probe */
   NULL,		/* tr_probe */
   NULL,		/* ac_probe */
   NULL,		/* xprobe */
   tr_bjt,
   NULL,	
   ac_bjt,
   NULL,	
   NULL,	
   NULL,	
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
functions_t model_bjt = {
   (generic_t*)&defaltmodel,
   sizeof(functions_t),
   sizeof(branch_t),
   (functions_t*)NULL,	/* super */
   0, 			/* numnodes */
   rnMODEL,		/* refnode */
   NO,			/* isdevice */
   create_model_bjt,
   copy_model_bjt,
   parse_model_bjt,
   print_model_bjt,
   NULL,	
   NULL,		/* probe */
   NULL,		/* tr_probe */
   NULL,		/* ac_probe */
   NULL,		/* xprobe */
   NULL,	
   NULL,	
   NULL,	
   NULL,	
   NULL,	
   NULL,	
   NULL,		/* tr_guess */
   NULL,		/* tr_advance */
   NULL			/* tr_review */
};
/*--------------------------------------------------------------------------*/
static void parse_bjt(branch_t *brh, const char *cmd, int *cnt)
{
 struct bjt *x;

 x = (struct bjt*)brh->x;

 parselabel(brh,cmd,cnt);
 (void)parsenodes(brh,cmd,cnt);
 (void)ctostr(cmd, cnt, x->modelname, LABELEN, TOKENTERM);
 x->m = (struct qmod*)NULL;
 if (isdigit(cmd[*cnt])  ||  cmd[*cnt] == '.')
    x->area = fabs(ctof(cmd,cnt));
 for (;;){
    if (argparse(cmd,cnt,REPEAT,
	"Area",	aUDOUBLE,	&x->area,
	"Perim",aUDOUBLE,	&x->perim,
	"IC",	aDOUBLE,	&x->ic,
	"OFF",	aENUM,		&x->off,	YES,
	"IS",	aUDOUBLE,	&x->is,
	"Rs",	aUDOUBLE,	&x->rs,
	"Cjo",	aUDOUBLE,	&x->cj,
	"CJSW",	aUDOUBLE,	&x->cjsw,
	""))
	;
    else{
       syntax_check(cmd,cnt,bWARNING);
       break;
    }
 }
}
/*--------------------------------------------------------------------------*/
static void print_bjt(const branch_t *brh, int where, int detail)
{
 struct bjt *x;

 x = (struct bjt*)brh->x;

 (void)printlabel(brh,where);
 printnodes(brh,where);
 mprintf(where, " %s ", x->modelname);

    mprintf(where,    " %s ", ftos(x->area,"", 7, 0));
 if (x->perim != 0.)
    mprintf(where,"perim=%s ",ftos(x->perim,"", 7, 0));
 if (x->off)
    mprintf(where, " off ");
 if (x->ic != NOT_INPUT)
    mprintf(where, " ic=%s ", ftos(x->ic,  "", 7, 0));
 if (!x->calc.is  &&  x->is != NOT_INPUT)
    mprintf(where, " is=%s ", ftos(x->is,  "", 7, 0));
 if (!x->calc.rs  &&  x->rs != NOT_INPUT)
    mprintf(where, " rs=%s ", ftos(x->rs,  "", 7, 0));
 if (!x->calc.cj  &&  x->cj != NOT_INPUT)
    mprintf(where, " cj=%s ", ftos(x->cj,  "", 7, 0));
 if (!x->calc.cjsw  &&  x->cjsw != NOT_INPUT)
    mprintf(where, " cjsw=%s ",ftos(x->cjsw,"", 7, 0));
 if (x->calc.is  &&  x->calc.rs  &&  x->calc.cj  &&  x->calc.cjsw)
    mprintf(where, "\n*+");
 if (x->calc.is  &&  x->is != NOT_INPUT)
    mprintf(where, " is=%s ", ftos(x->is,  "", 7, 0));
 if (x->calc.rs  &&  x->rs != NOT_INPUT)
    mprintf(where, " rs=%s ", ftos(x->rs,  "", 7, 0));
 if (x->calc.cj  &&  x->cj != NOT_INPUT)
    mprintf(where, " cj=%s ", ftos(x->cj,  "", 7, 0));
 if (x->calc.cjsw  &&  x->cjsw != NOT_INPUT)
    mprintf(where, " cjsw=%s ",ftos(x->cjsw,"", 7, 0));
 mprintf(where, "\n");
}
/*--------------------------------------------------------------------------*/
static branch_t *create_model_bjt(const functions_t *func)
{
 branch_t *brh;

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

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

 m = (struct qmod*)brh->x;

 (void)ctostr(cmd, cnt, brh->label, LABELEN, TOKENTERM);
 skiparg(cmd,cnt);	/* skip known "d" */

 for (;;){
    if (argparse(cmd,cnt,REPEAT,
	"IS",	aUDOUBLE,	&m->js,
	"RS",	aUDOUBLE,	&m->rs,
	"N",	aUDOUBLE,	&m->n,
	"TT",	aUDOUBLE,	&m->tt,
	"CJo",	aUDOUBLE,	&m->cj,
	"VJ",	aUDOUBLE,	&m->pb,
	"PB",	aUDOUBLE,	&m->pb,
	"Mj",	aUDOUBLE,	&m->mj,
	"EGap",	aUDOUBLE,	&m->eg,
 	""))
       ;
    else if (argparse(cmd,cnt,REPEAT,
	"XTI",	aUDOUBLE,	&m->xti,
	"KF",	aUDOUBLE,	&m->kf,
	"AF",	aUDOUBLE,	&m->af,
	"FC",	aUDOUBLE,	&m->fc,
	"BV",	aUDOUBLE,	&m->bv,
	"IBV",	aUDOUBLE,	&m->ibv,
	"CJSw",	aUDOUBLE,	&m->cjsw,
	"MJSw",	aUDOUBLE,	&m->mjsw,
	""))
	;
    else{
       syntax_check(cmd,cnt,bWARNING);
       break;
    }
 }
 m->fcpb = m->fc * m->pb;
 if (m->tt != 0.)
    error(bWARNING, "%s: tt not implemented\n", printlabel(brh,NO));
}
/*--------------------------------------------------------------------------*/
static void print_model_bjt(const branch_t *brh, int where, int detail)
{
 struct qmod *m;
 m = (struct qmod*)brh->x;

 mprintf(where, ".model  %s  d  (", brh->label);
 mprintf(where, " is=%s ",  ftos(m->js,  "", 7, 0));
 mprintf(where, " rs=%s ",  ftos(m->rs,  "", 7, 0));
 mprintf(where, " n=%s ",   ftos(m->n,   "", 7, 0));
 mprintf(where, " tt=%s ",  ftos(m->tt,  "", 7, 0));
 mprintf(where, " cjo=%s ", ftos(m->cj, "", 7, 0));
 mprintf(where, " vj=%s ",  ftos(m->pb,  "", 7, 0));
 mprintf(where, " m=%s ",   ftos(m->mj,   "", 7, 0));
 mprintf(where, " eg=%s ",  ftos(m->eg,  "", 7, 0));
 mprintf(where, " xti=%s ", ftos(m->xti, "", 7, 0));
 mprintf(where, " kf=%s ",  ftos(m->kf,  "", 7, 0));
 mprintf(where, " af=%s ",  ftos(m->af,  "", 7, 0));
 mprintf(where, " fc=%s ",  ftos(m->fc,  "", 7, 0));
 mprintf(where, " bv=%s ",  ftos(m->bv,  "", 7, 0));
 mprintf(where, " ibv=%s ", ftos(m->ibv, "", 7, 0));
 if (m->cjsw != 0.){
    mprintf(where, " cjsw=%s ", ftos(m->cjsw,"", 7, 0));
    mprintf(where, " mjsw=%s ", ftos(m->mjsw,"", 7, 0));
 }
 mprintf(where, ")\n");
}
/*--------------------------------------------------------------------------*/
static void expand_bjt(branch_t *brh)
{
 const struct qmod *m;
 struct bjt *x;
 branch_t *scratch;

 expandgeneric(brh,&modellist);
 x = (struct bjt*)brh->x;
 m = x->m;

 if (x->calc.is  ||  x->is == NOT_INPUT){	    /* calculate parameters */
    x->is = m->js * x->area;
    x->calc.is = YES;
 }
 if (x->calc.rs  ||  x->rs == NOT_INPUT){
    x->rs = m->rs * x->area;
    x->calc.rs = YES;
 }
 if (x->calc.cj  ||  x->cj == NOT_INPUT){
    x->cj = m->cj * x->area;
    x->calc.cj = YES;
 }
 if (x->calc.cjsw  ||  x->cjsw == NOT_INPUT){
    x->cjsw = m->cjsw * x->perim;
    x->calc.cjsw = YES;
 }

							    /* build subckt */
 if (x->cj != 0.  ||  x->cjsw != 0.){
    scratch = create_branch(&dev_cap);
    scratch->parent = brh;
    {functions_t *ff;
     ff = (functions_t*)calloc(1, sizeof(functions_t));
     *ff = *(scratch->f);
     ff->expand = NULL;
     ff->trfun1 = bjtcap;
     ff->acfun = NULL;
     scratch->f = ff;}
    strcpy(scratch->label,"Cj");
    scratch->n[OUT1].t = brh->n[OUT1].t;
    scratch->n[OUT2].t = brh->n[OUT2].t;
    scratch->next = brh->subckt;
    brh->subckt = insertbranch(scratch);
 }

 scratch = create_branch(&dev_admittance);
 scratch->parent = brh;
 {functions_t *ff;
  ff = (functions_t*)calloc(1, sizeof(functions_t));
  *ff = *(scratch->f);
  ff->expand = NULL;
  ff->trfun1 = evalbjt;
  ff->acfun = NULL;
  scratch->f = ff;}
 strcpy(scratch->label,"Yj");
 scratch->n[OUT1].t = brh->n[OUT1].t;
 scratch->n[OUT2].t = brh->n[OUT2].t;
 scratch->next = brh->subckt;
 brh->subckt = insertbranch(scratch);
}
/*--------------------------------------------------------------------------*/
static int tr_bjt(branch_t *brh)
{
 x = (struct bjt*)brh->x;
 if (!x->m)
    error(bERROR, "internal error: %s not expanded\n", printlabel(brh,NO));
 return brh->converged = tr_fill_rl(brh->subckt);
}
/*--------------------------------------------------------------------------*/
static void ac_bjt(branch_t *brh)
{
 x = (struct bjt*)brh->x;
 if (!x->m)
    error(bERROR, "internal error: %s not expanded\n", printlabel(brh,NO));
 ac_fill_rl(brh->subckt);
}
/*--------------------------------------------------------------------------*/
static void evalbjt(branch_t *brh)
{;}
/*--------------------------------------------------------------------------*/
static void bjtcap(branch_t *brh)
{;}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
