/* dc_setup.c  94.07.29
 * Copyright 1983-1992   Albert Davis
 * dc analysis setup
 */
#include "ecah.h"
#include "argparse.h"
#include "branch.h"
#include "dc.h"
#include "error.h"
#include "io.h"
#include "mode.h"
#include "options.h"
#include "probh.h"
#include "worst.h"
#include "declare.h"
/*--------------------------------------------------------------------------*/
	void	dc_finish(void);
	void	op_setup(const char*,int*,dc_t*);
	void	dc_setup(const char*,int*,dc_t*);
static	void	dc_options(const char*,int*,dc_t*);
static	void	dcoptby(const char*,int*);
static	void	dcoptdecade(const char*,int*);
static	void	dcopttimes(const char*,int*);
/*--------------------------------------------------------------------------*/
extern const probe_t *plotlist[];
extern       struct ioctrl io;
extern const struct options opt;
extern int sim_mode;	/* simulation type (AC, DC, ...)		    */
extern int worstcase;	/* worst case, monte carlo mode	(enum type, worst.h)*/
extern double temp;	/* actual ambient temperature, kelvin		    */
extern double genout;	/* output of signal generator (ckt input)	    */
static dc_t *par;	/* latest parameters for arg passing and "finish"   */
static branch_t stash[DCNEST];	/* store std values of elements being swept */
/*--------------------------------------------------------------------------*/
void dc_finish(void)
{
 int ii;
 if (par){
    for (ii = 0;  ii < DCNEST && exists(par->zap[ii]);  ii++){
       par->zap[ii]->subckt = stash[ii].subckt;
       par->zap[ii]->x = stash[ii].x;
       par->zap[ii]->val = stash[ii].val;
       expand_branch(par->zap[ii]);		/* BUG: why not copy the */
    }						/* whole structure, once? */
 par = (dc_t*)NULL;
 }
}
/*--------------------------------------------------------------------------*/
void op_setup(const char *cmd, int *cnt, dc_t *dc)
{
 dc->zap[0] = (branch_t*)NULL;
 dc->sweep[0] = &temp;
 dc->start[0] = (isfloat(cmd[*cnt])) ? ctof(cmd,cnt)-ABS_ZERO : opt.tempamb;
 dc->stop[0] = (isfloat(cmd[*cnt])) ? ctof(cmd,cnt)-ABS_ZERO : dc->start[0];
 dc->step[0] = 0.;
 genout = 0.;
 dc_options(cmd,cnt,dc);
 if (dc->step[0] == 0.){
    dc->step[0] = dc->stop[0] - dc->start[0];
    dc->linswp[0] = YES;
 }
}
/*--------------------------------------------------------------------------*/
void dc_setup(const char *cmd, int *cnt, dc_t *dc)
{
 branch_t *target;

 target = findbranch(cmd,cnt,firstbranch_all(),lastbranch_all());
 if (exists(target)){			/* sweep a component */
    dc->zap[0] = target;
 }else if (isfloat(cmd[*cnt])){		/* sweep the generator */
    dc->zap[0] = (branch_t*)NULL;
 }					/* else leave it alone */
 
 if (isfloat(cmd[*cnt])){		/* set up parameters */
    dc->start[0] = ctof(cmd,cnt);
    dc->stop[0] = (isfloat(cmd[*cnt])) ? ctof(cmd,cnt) : dc->start[0];
    dc->step[0] = 0.;
 }					/* else leave it alone */

 if (exists(dc->zap[0])){
    stash[0] = *(dc->zap[0]);		/* stash the std value */
    dc->zap[0]->x = (generic_t*)NULL;	/* zap out the extensions */
    dc->zap[0]->subckt = (branch_t*)NULL;
    dc->sweep[0] = &(dc->zap[0]->val);	/* point to value to patch */
 }else{
    dc->sweep[0] = &genout;		/* point to value to patch */
 }

 genout = 0.;
 temp = opt.tempamb;
 dc_options(cmd,cnt,dc);
 if (dc->step[0] == 0.){
    dc->step[0] = dc->stop[0] - dc->start[0];
    dc->linswp[0] = YES;
 }
}
/*--------------------------------------------------------------------------*/
static void dc_options(const char *cmd, int *cnt, dc_t *dc)
{
 par = dc;
 io.where |= io.mstdout;
 io.ploton = io.plotset && count_probes(plotlist[sDC]) > 0;
 dc->loop = dc->reverse = dc->cont = dc->trace = worstcase = NO;
 for (;;){
    if (argparse(cmd,cnt,REPEAT,
	"*",		aFUNCTION,  dcopttimes,
    	"ACMAx",	aENUM,	    &worstcase,	  wMAXAC,
	"ACMIn",	aENUM,	    &worstcase,	  wMINAC,
	"Ambient",	aODOUBLE,   &temp,	  opt.tempamb,
	"By",		aFUNCTION,  dcoptby,
	"Continue",	aENUM,	    &dc->cont,	  YES,
    	"DCMAx",	aENUM,	    &worstcase,	  wMAXDC,
	"DCMIn",	aENUM,	    &worstcase,	  wMINDC,
	"Decade",	aFUNCTION,  dcoptdecade,
	"LAg",		aENUM,	    &worstcase,   wLAG,
	"LEad",		aENUM,	    &worstcase,   wLEAD,
	"LOop",		aENUM,	    &dc->loop,	  YES,
	"MAx",		aENUM,	    &worstcase,   wMAXDC,
	"MIn",		aENUM,	    &worstcase,   wMINDC,
	"NOPlot",	aENUM,	    &io.ploton,   NO,
	"PLot",		aENUM,	    &io.ploton,   YES,
	"Reftemp",	aODOUBLE,   &temp,	  opt.tnom,
	"REverse",	aENUM,	    &dc->reverse, YES,
	"SEnsitivity",	aENUM,	    &worstcase,   wSENS,
	"Temperature",	aODOUBLE,   &temp,	  -ABS_ZERO,
	"TRace",	aFINT,	    &dc->trace,
	"TImes",	aFUNCTION,  dcopttimes,
	"WAtch",	aENUM,	    &dc->trace,	  tITERATION,
	""))
	;	
    else if (isfloat(cmd[*cnt]))
    	dcoptby(cmd,cnt);
    else if (outset(cmd,cnt,"",""))
	;
    else{
       syntax_check(cmd,cnt,bWARNING);
       break;
    }
 }
 initio(io.where,(FILE*)NULL);
 if (worstcase == wRAND   ||   worstcase == wWORST)
    io.ploton = NO;
}
/*--------------------------------------------------------------------------*/
static void dcoptby(const char *cmd, int *cnt)
{
 par->step[0] = ctof(cmd,cnt);
 par->linswp[0] = YES;
 if (par->step[0] == 0.)
     par->step[0] = par->stop[0] - par->start[0];
}
/*--------------------------------------------------------------------------*/
static void dcoptdecade(const char *cmd, int *cnt)
{
 double junk;
 junk = fabs(ctof(cmd,cnt));
 if (junk == 0.)
    junk = 1.;
 junk = pow(10., 1./junk);
 par->step[0] = junk;
 par->linswp[0] = NO;
}
/*--------------------------------------------------------------------------*/
static void dcopttimes(const char *cmd, int *cnt)
{
 par->step[0] = fabs(ctof(cmd,cnt));
 par->linswp[0] = NO;
 if (par->step[0] == 0.  &&  par->start[0] != 0.)
    par->step[0] = par->stop[0] / par->start[0];
}
/*--------------------------------------------------------------------------*/
/*--------------------------------------------------------------------------*/
