After ngspice 41 release, merge branch 'pre-master' into bt_dev
This commit is contained in:
commit
b0d29e7dca
|
|
@ -153,7 +153,7 @@ void NBJT2project(TWOdevice *pDevice, double delVce, double delVbe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( pElem->elemType == SEMICON
|
if ( pElem->elemType == SEMICON
|
||||||
&& (!OneCarrier | (OneCarrier == P_TYPE)) ) {
|
&& (!OneCarrier || (OneCarrier == P_TYPE)) ) {
|
||||||
delP = incVce[ pNode->pEqn ] * delVce;
|
delP = incVce[ pNode->pEqn ] * delVce;
|
||||||
newP = pNode->pConc + delP;
|
newP = pNode->pConc + delP;
|
||||||
if ( newP <= 0.0 ) {
|
if ( newP <= 0.0 ) {
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ com_stop(wordlist *wl)
|
||||||
d->db_also = TMALLOC(struct dbcomm, 1);
|
d->db_also = TMALLOC(struct dbcomm, 1);
|
||||||
d = d->db_also;
|
d = d->db_also;
|
||||||
}
|
}
|
||||||
|
d->db_also = NULL;
|
||||||
|
|
||||||
/* Figure out what the first condition is. */
|
/* Figure out what the first condition is. */
|
||||||
d->db_analysis = NULL;
|
d->db_analysis = NULL;
|
||||||
|
|
@ -127,13 +128,24 @@ com_stop(wordlist *wl)
|
||||||
/* Now get the condition */
|
/* Now get the condition */
|
||||||
if (eq(wl->wl_word, "eq") || eq(wl->wl_word, "="))
|
if (eq(wl->wl_word, "eq") || eq(wl->wl_word, "="))
|
||||||
d->db_op = DBC_EQU;
|
d->db_op = DBC_EQU;
|
||||||
else if (eq(wl->wl_word, "ne") || eq(wl->wl_word, "<>"))
|
else if (eq(wl->wl_word, "ne"))
|
||||||
d->db_op = DBC_NEQ;
|
d->db_op = DBC_NEQ;
|
||||||
else if (eq(wl->wl_word, "gt") || eq(wl->wl_word, ">"))
|
else if (eq(wl->wl_word, "gt") || eq(wl->wl_word, ">"))
|
||||||
d->db_op = DBC_GT;
|
d->db_op = DBC_GT;
|
||||||
else if (eq(wl->wl_word, "lt") || eq(wl->wl_word, "<"))
|
else if (eq(wl->wl_word, "lt"))
|
||||||
d->db_op = DBC_LT;
|
d->db_op = DBC_LT;
|
||||||
else if (eq(wl->wl_word, "ge") || eq(wl->wl_word, ">="))
|
else if (eq(wl->wl_word, "<")) {
|
||||||
|
/* "<>" is parsed as two words. */
|
||||||
|
|
||||||
|
if (eq(wl->wl_next->wl_word, ">")) {
|
||||||
|
if (!wl->wl_next->wl_next)
|
||||||
|
goto bad;
|
||||||
|
d->db_op = DBC_NEQ;
|
||||||
|
wl = wl->wl_next;
|
||||||
|
} else {
|
||||||
|
d->db_op = DBC_LT;
|
||||||
|
}
|
||||||
|
} else if (eq(wl->wl_word, "ge") || eq(wl->wl_word, ">="))
|
||||||
d->db_op = DBC_GTE;
|
d->db_op = DBC_GTE;
|
||||||
else if (eq(wl->wl_word, "le") || eq(wl->wl_word, "<="))
|
else if (eq(wl->wl_word, "le") || eq(wl->wl_word, "<="))
|
||||||
d->db_op = DBC_LTE;
|
d->db_op = DBC_LTE;
|
||||||
|
|
@ -150,15 +162,16 @@ com_stop(wordlist *wl)
|
||||||
d->db_value2 = val;
|
d->db_value2 = val;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
d->db_nodename2 = copy(wl->wl_word);
|
d->db_nodename2 = copy(wl->wl_word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wl = wl->wl_next;
|
wl = wl->wl_next;
|
||||||
}
|
} else { // Neither "after" nor "when".
|
||||||
else {
|
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
} /* end of case of word "when" */
|
} else {
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
} /* end of loop over wordlist */
|
} /* end of loop over wordlist */
|
||||||
|
|
||||||
if (thisone) {
|
if (thisone) {
|
||||||
|
|
@ -178,7 +191,12 @@ com_stop(wordlist *wl)
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
fprintf(cp_err, "Syntax error parsing breakpoint specification.\n");
|
fprintf(cp_err, "Syntax error parsing breakpoint specification.\n");
|
||||||
} /* end of funtion com_stop */
|
while (thisone) {
|
||||||
|
d = thisone->db_also;
|
||||||
|
txfree(thisone);
|
||||||
|
thisone = d;
|
||||||
|
}
|
||||||
|
} /* end of function com_stop */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2411,7 +2411,6 @@ limit(double nominal_val, double abs_variation)
|
||||||
* of agauss()
|
* of agauss()
|
||||||
* agauss in .param lines has been treated already
|
* agauss in .param lines has been treated already
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
eval_agauss(struct card *deck, char *fcn)
|
eval_agauss(struct card *deck, char *fcn)
|
||||||
{
|
{
|
||||||
|
|
@ -2448,14 +2447,30 @@ eval_agauss(struct card *deck, char *fcn)
|
||||||
begstr = copy_substring(curr_line, ap);
|
begstr = copy_substring(curr_line, ap);
|
||||||
lparen = strchr(ap, '(');
|
lparen = strchr(ap, '(');
|
||||||
tmp1str = midstr = gettok_char(&lparen, ')', FALSE, TRUE);
|
tmp1str = midstr = gettok_char(&lparen, ')', FALSE, TRUE);
|
||||||
if (lparen + 1)
|
if (!tmp1str) {
|
||||||
contstr = copy(lparen + 1);
|
fprintf(cp_err, "ERROR: Incomplete function %s in line %s\n", fcn, curr_line);
|
||||||
|
tfree(begstr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
contstr = copy(lparen + 1);
|
||||||
tmp1str++; /* skip '(' */
|
tmp1str++; /* skip '(' */
|
||||||
/* find the parameters, ignore ( ) , */
|
/* find the parameters, ignore ( ) , */
|
||||||
delstr = tmp2str = gettok_np(&tmp1str);
|
delstr = tmp2str = gettok_np(&tmp1str);
|
||||||
|
if (!tmp2str) {
|
||||||
|
fprintf(cp_err, "ERROR: Incomplete function %s in line %s\n", fcn, curr_line);
|
||||||
|
tfree(begstr);
|
||||||
|
tfree(contstr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
x = INPevaluate(&tmp2str, &nerror, 1);
|
x = INPevaluate(&tmp2str, &nerror, 1);
|
||||||
tfree(delstr);
|
tfree(delstr);
|
||||||
delstr = tmp2str = gettok_np(&tmp1str);
|
delstr = tmp2str = gettok_np(&tmp1str);
|
||||||
|
if (!tmp2str) {
|
||||||
|
fprintf(cp_err, "ERROR: Incomplete function %s in line %s\n", fcn, curr_line);
|
||||||
|
tfree(begstr);
|
||||||
|
tfree(contstr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
y = INPevaluate(&tmp2str, &nerror, 1);
|
y = INPevaluate(&tmp2str, &nerror, 1);
|
||||||
tfree(delstr);
|
tfree(delstr);
|
||||||
if (cieq(fcn, "agauss")) {
|
if (cieq(fcn, "agauss")) {
|
||||||
|
|
|
||||||
|
|
@ -2177,8 +2177,8 @@ static int inp_chk_for_multi_in_vcvs(struct card *c, int *line_number)
|
||||||
static void replace_freq(struct card *c, int *line_number)
|
static void replace_freq(struct card *c, int *line_number)
|
||||||
{
|
{
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
char *line, *e, *e_e, *n1, *n1_e, *n2, *n2_e, *freq;
|
char *line, *e, *e_e, *n1, *n1_e, *n2, *n2_e=NULL, *freq;
|
||||||
char *expr, *expr_e, *in, *in_e, *keywd, *cp, *list, *list_e;
|
char *expr, *expr_e, *in, *in_e=NULL, *keywd, *cp, *list, *list_e;
|
||||||
int db, ri, rad, got_key, diff;
|
int db, ri, rad, got_key, diff;
|
||||||
char pt, key[4];
|
char pt, key[4];
|
||||||
|
|
||||||
|
|
@ -5490,7 +5490,7 @@ static char* eval_tc(char* line, char *tline) {
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
tc1_str = tprintf("tc1=%15.8e", tc1);
|
tc1_str = tprintf("tc1=%15.8e", tc1);
|
||||||
}
|
}
|
||||||
else if (error == 1 && *tc1_ptr == '{' && tc1_ptr + 1 && *(tc1_ptr + 1) != '}') {
|
else if (error == 1 && *tc1_ptr == '{' && *(tc1_ptr + 1) != '}') {
|
||||||
char* bra = gettok_char(&tc1_ptr, '}', TRUE, TRUE);
|
char* bra = gettok_char(&tc1_ptr, '}', TRUE, TRUE);
|
||||||
if (bra) {
|
if (bra) {
|
||||||
tc1_str = tprintf("tc1=%s", bra);
|
tc1_str = tprintf("tc1=%s", bra);
|
||||||
|
|
@ -5522,7 +5522,7 @@ static char* eval_tc(char* line, char *tline) {
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
tc2_str = tprintf("tc2=%15.8e", tc2);
|
tc2_str = tprintf("tc2=%15.8e", tc2);
|
||||||
}
|
}
|
||||||
else if (error == 1 && *tc2_ptr == '{' && tc2_ptr + 1 && *(tc2_ptr + 1) != '}') {
|
else if (error == 1 && *tc2_ptr == '{' && *(tc2_ptr + 1) != '}') {
|
||||||
char* bra = gettok_char(&tc2_ptr, '}', TRUE, TRUE);
|
char* bra = gettok_char(&tc2_ptr, '}', TRUE, TRUE);
|
||||||
if (bra) {
|
if (bra) {
|
||||||
tc2_str = tprintf("tc2=%s", bra);
|
tc2_str = tprintf("tc2=%s", bra);
|
||||||
|
|
@ -5556,18 +5556,18 @@ static char* eval_m(char* line, char* tline) {
|
||||||
double m;
|
double m;
|
||||||
char* str_ptr, * m_ptr, * m_str = NULL;
|
char* str_ptr, * m_ptr, * m_str = NULL;
|
||||||
char* cut_line = line;
|
char* cut_line = line;
|
||||||
str_ptr = strstr(cut_line, "m=");
|
str_ptr = strstr(cut_line, " m=");
|
||||||
if (str_ptr) {
|
if (str_ptr) {
|
||||||
/* We need to have 'm=something */
|
/* We need to have 'm=something */
|
||||||
if (str_ptr[2]) {
|
if (str_ptr[3]) {
|
||||||
m_ptr = str_ptr + 2;
|
m_ptr = str_ptr + 3;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
m = INPevaluate(&m_ptr, &error, 1);
|
m = INPevaluate(&m_ptr, &error, 1);
|
||||||
/*We have a value and create the m string */
|
/*We have a value and create the m string */
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
m_str = tprintf("m=%15.8e", m);
|
m_str = tprintf("m=%15.8e", m);
|
||||||
}
|
}
|
||||||
else if (error == 1 && *m_ptr == '{' && m_ptr + 1 && *(m_ptr + 1) != '}') {
|
else if (error == 1 && *m_ptr == '{' && *(m_ptr + 1) != '\0' && *(m_ptr + 1) != '}') {
|
||||||
char* bra = gettok_char(&m_ptr, '}', TRUE, TRUE);
|
char* bra = gettok_char(&m_ptr, '}', TRUE, TRUE);
|
||||||
if (bra) {
|
if (bra) {
|
||||||
m_str = tprintf("m=%s", bra);
|
m_str = tprintf("m=%s", bra);
|
||||||
|
|
@ -5598,18 +5598,18 @@ static char* eval_mvalue(char* line, char* tline) {
|
||||||
double m;
|
double m;
|
||||||
char* str_ptr, * m_ptr, * m_str = NULL;
|
char* str_ptr, * m_ptr, * m_str = NULL;
|
||||||
char* cut_line = line;
|
char* cut_line = line;
|
||||||
str_ptr = strstr(cut_line, "m=");
|
str_ptr = strstr(cut_line, " m=");
|
||||||
if (str_ptr) {
|
if (str_ptr) {
|
||||||
/* We need to have 'm=something */
|
/* We need to have 'm=something */
|
||||||
if (str_ptr[2]) {
|
if (str_ptr[3]) {
|
||||||
m_ptr = str_ptr + 2;
|
m_ptr = str_ptr + 3;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
m = INPevaluate(&m_ptr, &error, 1);
|
m = INPevaluate(&m_ptr, &error, 1);
|
||||||
/*We have a value and create the m string */
|
/*We have a value and create the m string */
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
m_str = tprintf("%15.8e", m);
|
m_str = tprintf("%15.8e", m);
|
||||||
}
|
}
|
||||||
else if (error == 1 && *m_ptr == '{' && m_ptr + 1 && *(m_ptr + 1) != '}') {
|
else if (error == 1 && *m_ptr == '{' && *(m_ptr + 1) != '\0' && *(m_ptr + 1) != '}') {
|
||||||
char* bra = gettok_char(&m_ptr, '}', TRUE, TRUE);
|
char* bra = gettok_char(&m_ptr, '}', TRUE, TRUE);
|
||||||
if (bra) {
|
if (bra) {
|
||||||
m_str = tprintf("%s", bra);
|
m_str = tprintf("%s", bra);
|
||||||
|
|
@ -7963,53 +7963,55 @@ static int inp_vdmos_model(struct card *deck)
|
||||||
|
|
||||||
for (card = deck; card; card = card->nextcard) {
|
for (card = deck; card; card = card->nextcard) {
|
||||||
|
|
||||||
char* curr_line, * cut_line, * token, * new_line;
|
char* curr_line, * cut_line = NULL, * token, * new_line;
|
||||||
wordlist* wl = NULL, * wlb;
|
wordlist* wl = NULL, * wlb;
|
||||||
|
|
||||||
curr_line = cut_line = card->line;
|
curr_line = card->line;
|
||||||
|
|
||||||
if (ciprefix(".model", curr_line) && strstr(curr_line, "vdmos")) {
|
if (ciprefix(".model", curr_line)) {
|
||||||
cut_line = strstr(curr_line, "vdmos");
|
cut_line = search_plain_identifier(curr_line, "vdmos");
|
||||||
wl_append_word(&wl, &wl, copy_substring(curr_line, cut_line));
|
if (cut_line) {
|
||||||
wlb = wl;
|
wl_append_word(&wl, &wl, copy_substring(curr_line, cut_line));
|
||||||
if (strstr(cut_line, "pchan")) {
|
wlb = wl;
|
||||||
wl_append_word(NULL, &wl, copy("vdmosp ("));
|
if (strstr(cut_line, "pchan")) {
|
||||||
}
|
wl_append_word(NULL, &wl, copy("vdmosp ("));
|
||||||
else {
|
}
|
||||||
wl_append_word(NULL, &wl, copy("vdmosn ("));
|
else {
|
||||||
}
|
wl_append_word(NULL, &wl, copy("vdmosn ("));
|
||||||
cut_line = cut_line + 5;
|
}
|
||||||
|
cut_line = cut_line + 5;
|
||||||
|
|
||||||
cut_line = skip_ws(cut_line);
|
cut_line = skip_ws(cut_line);
|
||||||
if (*cut_line == '(')
|
if (*cut_line == '(')
|
||||||
cut_line = cut_line + 1;
|
cut_line = cut_line + 1;
|
||||||
new_line = NULL;
|
new_line = NULL;
|
||||||
while (cut_line && *cut_line) {
|
while (cut_line && *cut_line) {
|
||||||
token = gettok_model(&cut_line);
|
token = gettok_model(&cut_line);
|
||||||
if (!ciprefix("pchan", token) && !ciprefix("ron=", token) &&
|
if (!ciprefix("pchan", token) && !ciprefix("ron=", token) &&
|
||||||
!ciprefix("vds=", token) && !ciprefix("qg=", token) &&
|
!ciprefix("vds=", token) && !ciprefix("qg=", token) &&
|
||||||
!ciprefix("mfg=", token) && !ciprefix("nchan", token))
|
!ciprefix("mfg=", token) && !ciprefix("nchan", token))
|
||||||
wl_append_word(NULL, &wl, token);
|
wl_append_word(NULL, &wl, token);
|
||||||
else
|
else
|
||||||
tfree(token);
|
tfree(token);
|
||||||
if (*cut_line == ')') {
|
if (*cut_line == ')') {
|
||||||
wl_append_word(NULL, &wl, copy(")"));
|
wl_append_word(NULL, &wl, copy(")"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_line = wl_flatten(wlb);
|
||||||
|
tfree(card->line);
|
||||||
|
card->line = new_line;
|
||||||
|
wl_free(wlb);
|
||||||
|
|
||||||
|
/* add model card pointer to list */
|
||||||
|
vmodels[j] = card;
|
||||||
|
j++;
|
||||||
|
if (j == MODNUMBERS) {
|
||||||
|
vmodels[j - 1] = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
vmodels[j] = NULL;
|
||||||
}
|
}
|
||||||
new_line = wl_flatten(wlb);
|
|
||||||
tfree(card->line);
|
|
||||||
card->line = new_line;
|
|
||||||
wl_free(wlb);
|
|
||||||
|
|
||||||
/* add model card pointer to list */
|
|
||||||
vmodels[j] = card;
|
|
||||||
j++;
|
|
||||||
if (j == MODNUMBERS) {
|
|
||||||
vmodels[j - 1] = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
vmodels[j] = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1318,10 +1318,10 @@ static struct dvec *vec_scale(struct dvec *v)
|
||||||
* vec_scale for its scale vector (for x range of scale).
|
* vec_scale for its scale vector (for x range of scale).
|
||||||
* lims: Address of an array of 2 double values to receive the limits.
|
* lims: Address of an array of 2 double values to receive the limits.
|
||||||
**/
|
**/
|
||||||
static void find_axis_limits(double lim[2], bool oneval, bool f_real,
|
static void find_axis_limits(double *lim, bool oneval, bool f_real,
|
||||||
struct dvec *vecs,
|
struct dvec *vecs,
|
||||||
struct dvec *(*p_get_axis_dvec)(struct dvec *dvec),
|
struct dvec *(*p_get_axis_dvec)(struct dvec *dvec),
|
||||||
double lims[2])
|
double *lims)
|
||||||
{
|
{
|
||||||
if (lim != (double *) NULL) {
|
if (lim != (double *) NULL) {
|
||||||
lims[0] = lim[0];
|
lims[0] = lim[0];
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,6 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
||||||
GENinstance *gen_inst;
|
GENinstance *gen_inst;
|
||||||
|
|
||||||
bool is_init_smsig = ckt->CKTmode & MODEINITSMSIG;
|
bool is_init_smsig = ckt->CKTmode & MODEINITSMSIG;
|
||||||
bool is_sweep = ckt->CKTmode & MODEDCTRANCURVE;
|
|
||||||
bool is_dc = ckt->CKTmode & (MODEDCOP | MODEDCTRANCURVE);
|
bool is_dc = ckt->CKTmode & (MODEDCOP | MODEDCTRANCURVE);
|
||||||
bool is_ac = ckt->CKTmode & (MODEAC | MODEINITSMSIG);
|
bool is_ac = ckt->CKTmode & (MODEAC | MODEINITSMSIG);
|
||||||
bool is_tran = ckt->CKTmode & (MODETRAN);
|
bool is_tran = ckt->CKTmode & (MODETRAN);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,13 @@ CKTsetBreak(CKTcircuit *ckt, double time)
|
||||||
printf("[t:%e] \t want breakpoint for t = %e\n", ckt->CKTtime, time);
|
printf("[t:%e] \t want breakpoint for t = %e\n", ckt->CKTtime, time);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (AlmostEqualUlps(time, ckt->CKTtime, 3)) {
|
||||||
|
#ifdef TRACE_BREAKPOINT // #if (1)
|
||||||
|
fprintf(stderr, "Warning: Setting a new breakpoint at %e is ignored,\n as current time is %e\n", time, ckt->CKTtime);
|
||||||
|
#endif
|
||||||
|
return (OK);
|
||||||
|
}
|
||||||
|
|
||||||
if(ckt->CKTtime > time) {
|
if(ckt->CKTtime > time) {
|
||||||
SPfrontEnd->IFerrorf (ERR_PANIC, "breakpoint in the past - HELP!");
|
SPfrontEnd->IFerrorf (ERR_PANIC, "breakpoint in the past - HELP!");
|
||||||
return(E_INTERN);
|
return(E_INTERN);
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,13 @@ static void
|
||||||
delete_ret(void)
|
delete_ret(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
if (return_all)
|
if (return_all) {
|
||||||
for (i = 0; i < return_all->num_steps; i++) {
|
for (i = 0; i < return_all->num_steps; i++) {
|
||||||
tfree(return_all->evt_dect[i]->node_value);
|
tfree(return_all->evt_dect[i]->node_value);
|
||||||
tfree(return_all->evt_dect[i]);
|
tfree(return_all->evt_dect[i]);
|
||||||
}
|
}
|
||||||
tfree(return_all);
|
tfree(return_all);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pevt_shared_data
|
pevt_shared_data
|
||||||
|
|
|
||||||
|
|
@ -155,9 +155,6 @@ void cm_pwlts(ARGS) /* structure holding parms,
|
||||||
double test1; /* debug testing value */
|
double test1; /* debug testing value */
|
||||||
double test2; /* debug testing value */
|
double test2; /* debug testing value */
|
||||||
double *last_x_value; /* static variable for limiting */
|
double *last_x_value; /* static variable for limiting */
|
||||||
double test; /* temp storage variable for limit testing */
|
|
||||||
|
|
||||||
Mif_Complex_t ac_gain;
|
|
||||||
|
|
||||||
CALLBACK = cm_pwlts_callback;
|
CALLBACK = cm_pwlts_callback;
|
||||||
|
|
||||||
|
|
@ -283,7 +280,7 @@ void cm_pwlts(ARGS) /* structure holding parms,
|
||||||
/*** must determine position progressively & then ***/
|
/*** must determine position progressively & then ***/
|
||||||
/*** calculate required output. ***/
|
/*** calculate required output. ***/
|
||||||
|
|
||||||
for (i=1; i<size; i++) {
|
for (i = 1; i < size - 1; i++) {
|
||||||
|
|
||||||
if (x_input < (x[i] + x[i+1])/2.0) {
|
if (x_input < (x[i] + x[i+1])/2.0) {
|
||||||
/* approximate position known... */
|
/* approximate position known... */
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ struct pwl {
|
||||||
|
|
||||||
/* Called at end to free memory. */
|
/* Called at end to free memory. */
|
||||||
|
|
||||||
static void callback(ARGS, Mif_Callback_Reason_t reason)
|
static void cm_d_osc_callback(ARGS, Mif_Callback_Reason_t reason)
|
||||||
{
|
{
|
||||||
struct panel_instance *instance;
|
struct panel_instance *instance;
|
||||||
|
|
||||||
|
|
@ -70,6 +70,8 @@ void cm_d_osc(ARGS)
|
||||||
double ctl, delta, when;
|
double ctl, delta, when;
|
||||||
int csize, i;
|
int csize, i;
|
||||||
|
|
||||||
|
CALLBACK = cm_d_osc_callback;
|
||||||
|
|
||||||
csize = PARAM_SIZE(cntl_array);
|
csize = PARAM_SIZE(cntl_array);
|
||||||
if (INIT) {
|
if (INIT) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,24 +107,22 @@ NON-STANDARD FEATURES
|
||||||
* Last Modified 11/26/91 *
|
* Last Modified 11/26/91 *
|
||||||
************************************************/
|
************************************************/
|
||||||
|
|
||||||
|
#define DEBUG 0
|
||||||
|
#if DEBUG
|
||||||
|
const char * const Image[] = {"Idle", "Normal", "Same", "Revert", "Both"};
|
||||||
|
#endif
|
||||||
|
|
||||||
void cm_d_tristate(ARGS)
|
void cm_d_tristate(ARGS)
|
||||||
{
|
{
|
||||||
Digital_t *out;
|
Digital_State_t val;
|
||||||
Digital_State_t val, enable;
|
|
||||||
Digital_Strength_t str;
|
Digital_Strength_t str;
|
||||||
|
Digital_t *out;
|
||||||
struct idata *idp;
|
struct idata *idp;
|
||||||
|
|
||||||
if (INIT) { /* initial pass */
|
if (INIT) { /* initial pass */
|
||||||
/* define input loading... */
|
/* allocate storage for the outputs */
|
||||||
LOAD(in) = PARAM(input_load);
|
|
||||||
LOAD(enable) = PARAM(enable_load);
|
|
||||||
OUTPUT_DELAY(out) = PARAM(delay);
|
|
||||||
|
|
||||||
/* allocate storage for the previous output. */
|
|
||||||
|
|
||||||
cm_event_alloc(0, sizeof (Digital_t));
|
cm_event_alloc(0, sizeof (Digital_t));
|
||||||
out = (Digital_t *)cm_event_get_ptr(0, 0);
|
|
||||||
out->state = (Digital_State_t)(UNKNOWN + 1); // Force initial output.
|
|
||||||
|
|
||||||
/* Inertial delay? */
|
/* Inertial delay? */
|
||||||
|
|
||||||
|
|
@ -132,72 +130,323 @@ void cm_d_tristate(ARGS)
|
||||||
cm_is_inertial(PARAM_NULL(inertial_delay) ? Not_set :
|
cm_is_inertial(PARAM_NULL(inertial_delay) ? Not_set :
|
||||||
PARAM(inertial_delay));
|
PARAM(inertial_delay));
|
||||||
if (STATIC_VAR(is_inertial)) {
|
if (STATIC_VAR(is_inertial)) {
|
||||||
/* Allocate storage for event time. */
|
/* Allocate storage for event times. A little rude,
|
||||||
|
* as strength values will be stored in idp[1].prev.
|
||||||
|
*/
|
||||||
|
|
||||||
cm_event_alloc(1, 2 * sizeof (struct idata));
|
cm_event_alloc(1, 2 * sizeof (struct idata));
|
||||||
idp = (struct idata *)cm_event_get_ptr(1, 0);
|
idp = (struct idata *)cm_event_get_ptr(1, 0);
|
||||||
idp[1].when = idp[0].when = -1.0;
|
idp[1].when = idp[0].when = -1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare initial output. */
|
out = (Digital_t *) cm_event_get_ptr(0,0);
|
||||||
|
|
||||||
out = (Digital_t *)cm_event_get_ptr(0, 0);
|
|
||||||
out->state = (Digital_State_t)(UNKNOWN + 1); // Force initial output.
|
out->state = (Digital_State_t)(UNKNOWN + 1); // Force initial output.
|
||||||
|
|
||||||
|
/* define input loading... */
|
||||||
|
LOAD(in) = PARAM(input_load);
|
||||||
|
LOAD(enable) = PARAM(enable_load);
|
||||||
|
OUTPUT_DELAY(out) = PARAM(delay); // Never changes, unless inertial.
|
||||||
} else {
|
} else {
|
||||||
out = (Digital_t *)cm_event_get_ptr(0, 0);
|
out = (Digital_t *)cm_event_get_ptr(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve input values and static variables */
|
/* Retrieve input values. */
|
||||||
|
|
||||||
val = INPUT_STATE(in);
|
val = INPUT_STATE(in);
|
||||||
|
switch (INPUT_STATE(enable)) {
|
||||||
enable = INPUT_STATE(enable);
|
case ZERO:
|
||||||
if (ZERO == enable) {
|
|
||||||
str = HI_IMPEDANCE;
|
str = HI_IMPEDANCE;
|
||||||
} else if (UNKNOWN == enable) {
|
break;
|
||||||
str = UNDETERMINED;
|
case ONE:
|
||||||
} else {
|
|
||||||
str = STRONG;
|
str = STRONG;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = UNDETERMINED;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val == out->state && str == out->strength) {
|
/*** Check for change and output appropriate values ***/
|
||||||
|
|
||||||
|
if (val == out->state && str == out->strength) { /* output not changing */
|
||||||
OUTPUT_CHANGED(out) = FALSE;
|
OUTPUT_CHANGED(out) = FALSE;
|
||||||
} else {
|
} else {
|
||||||
if (STATIC_VAR(is_inertial) && ANALYSIS == TRANSIENT) {
|
if (STATIC_VAR(is_inertial) && ANALYSIS == TRANSIENT) {
|
||||||
int d_cancel, s_cancel;
|
/* Each channel (State, Strength) of the output has three values,
|
||||||
|
* that set by the input, the current node value and its value
|
||||||
|
* following a pending change. The channel is in one of
|
||||||
|
* five states:
|
||||||
|
* Idle - no new value and no pending output;
|
||||||
|
* Normal - there is a new value with no pending output;
|
||||||
|
* Same - no new value, there is pending output;
|
||||||
|
* Revert - new value same as current, conflicting pending output;
|
||||||
|
* Both - new value differs from both current and pending.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum {Idle, Normal, Same, Revert, Both}
|
||||||
|
d_ctl, s_ctl, ctl1, ctl2;
|
||||||
|
double first_time, second_time; /* Scheduled changes */
|
||||||
|
double delay_1; /* Delay to first output. */
|
||||||
|
double cancel_delay; /* Delay to canclling. */
|
||||||
|
int d_first;
|
||||||
|
Digital_t reversion, restoration;
|
||||||
|
|
||||||
idp = (struct idata *)cm_event_get_ptr(1, 0);
|
idp = (struct idata *)cm_event_get_ptr(1, 0);
|
||||||
d_cancel = (idp[0].when > TIME && val == idp[0].prev);
|
|
||||||
s_cancel = (idp[1].when > TIME &&
|
|
||||||
str == (Digital_Strength_t)idp[1].prev);
|
|
||||||
if ((d_cancel && s_cancel) ||
|
|
||||||
(d_cancel && str == out->strength && TIME >= idp[1].when) ||
|
|
||||||
(s_cancel && val == out->state && TIME >= idp[0].when)) {
|
|
||||||
double when;
|
|
||||||
|
|
||||||
/* Changing back: override pending change. */
|
/* Combine two independent streams (state and strength) into
|
||||||
|
* a sequence of output events. Earlier changes cancel later ones
|
||||||
|
* that may need to be restored.
|
||||||
|
*/
|
||||||
|
|
||||||
when = d_cancel ? idp[0].when : idp[1].when;
|
/* Identify earlier change. */
|
||||||
if (s_cancel && when > idp[1].when)
|
|
||||||
when = idp[1].when;
|
|
||||||
|
|
||||||
OUTPUT_DELAY(out) = (when - TIME) / 2.0; // Override
|
if (idp[0].when <= idp[1].when) {
|
||||||
idp[1].when = idp[0].when = -1.0;
|
first_time = idp[0].when;
|
||||||
|
second_time = idp[1].when;
|
||||||
|
d_first = 1;
|
||||||
} else {
|
} else {
|
||||||
/* Normal transition, or third value during delay,
|
first_time = idp[1].when;
|
||||||
* or needs cancel followed by restore of
|
second_time = idp[0].when;
|
||||||
* the other component (fudge).
|
d_first = 0;
|
||||||
*/
|
}
|
||||||
|
|
||||||
OUTPUT_DELAY(out) = PARAM(delay);
|
/* What happens to state? */
|
||||||
if (val != out->state) {
|
|
||||||
|
OUTPUT_DELAY(out) = PARAM(delay);
|
||||||
|
if (idp[0].when <= TIME) {
|
||||||
|
if (val == out->state) {
|
||||||
|
d_ctl = Idle; /* Output is stable and no change. */
|
||||||
|
idp[0].prev = val;
|
||||||
|
} else {
|
||||||
|
d_ctl = Normal; /* Output was stable, changing now. */
|
||||||
idp[0].prev = out->state;
|
idp[0].prev = out->state;
|
||||||
idp[0].when = TIME + OUTPUT_DELAY(out);
|
idp[0].when = TIME + OUTPUT_DELAY(out);
|
||||||
}
|
}
|
||||||
if (str != out->strength) {
|
} else {
|
||||||
idp[1].prev = (Digital_State_t)out->strength;
|
if (val == out->state) {
|
||||||
|
d_ctl = Same; /* Output pending, no change. */
|
||||||
|
} else if (val == idp[0].prev) {
|
||||||
|
d_ctl = Revert; /* Returning to previous state. */
|
||||||
|
idp[0].when = -1.0;
|
||||||
|
} else {
|
||||||
|
d_ctl = Both; /* Output pending, now changing. */
|
||||||
|
idp[0].when = TIME + OUTPUT_DELAY(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Strength? */
|
||||||
|
|
||||||
|
if (idp[1].when <= TIME) {
|
||||||
|
if (str == out->strength) {
|
||||||
|
s_ctl = Idle;
|
||||||
|
idp[1].prev = str;
|
||||||
|
} else {
|
||||||
|
s_ctl = Normal;
|
||||||
|
idp[1].prev = out->strength;
|
||||||
idp[1].when = TIME + OUTPUT_DELAY(out);
|
idp[1].when = TIME + OUTPUT_DELAY(out);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (str == out->strength) {
|
||||||
|
s_ctl = Same;
|
||||||
|
} else if (str == (Digital_Strength_t)idp[1].prev) {
|
||||||
|
s_ctl = Revert;
|
||||||
|
idp[1].when = -1.0;
|
||||||
|
} else {
|
||||||
|
s_ctl = Both;
|
||||||
|
idp[1].when = TIME + OUTPUT_DELAY(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d_first) {
|
||||||
|
ctl1 = d_ctl;
|
||||||
|
ctl2 = s_ctl;
|
||||||
|
} else {
|
||||||
|
ctl1 = s_ctl;
|
||||||
|
ctl2 = d_ctl;
|
||||||
|
}
|
||||||
|
#if DEBUG
|
||||||
|
cm_message_printf("%g: %s first, "
|
||||||
|
"state ctl %s %d->%d->%d @ %g, "
|
||||||
|
"strength ctl %s %d->%d->%d @ %g",
|
||||||
|
TIME, d_first ? "state" : "strength",
|
||||||
|
Image[d_ctl], idp[0].prev, out->state, val,
|
||||||
|
idp[0].when,
|
||||||
|
Image[s_ctl], idp[1].prev, out->strength, str,
|
||||||
|
idp[1].when);
|
||||||
|
#endif
|
||||||
|
switch (ctl1) {
|
||||||
|
case Idle:
|
||||||
|
switch (ctl2) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case Revert:
|
||||||
|
/* Normal output is used to revert. */
|
||||||
|
|
||||||
|
delay_1 = (second_time - TIME) / 2.0;
|
||||||
|
direct_revert:
|
||||||
|
if (d_first) {
|
||||||
|
str = (Digital_Strength_t)idp[1].prev;
|
||||||
|
} else {
|
||||||
|
val = idp[0].prev;
|
||||||
|
}
|
||||||
|
OUTPUT_DELAY(out) = delay_1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Both:
|
||||||
|
/* Push out reversion before normal output. */
|
||||||
|
|
||||||
|
cancel_delay = (second_time - TIME) / 2.0;
|
||||||
|
push_revert:
|
||||||
|
if (d_first) {
|
||||||
|
reversion.state = out->state;
|
||||||
|
reversion.strength = (Digital_Strength_t)idp[1].prev;
|
||||||
|
} else {
|
||||||
|
reversion.state = idp[0].prev;
|
||||||
|
reversion.strength = out->strength;
|
||||||
|
}
|
||||||
|
cm_schedule_output(2, 0, cancel_delay, &reversion);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Normal:
|
||||||
|
switch (ctl2) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case Revert:
|
||||||
|
/* Push out reversion before normal output. */
|
||||||
|
|
||||||
|
if (d_first) {
|
||||||
|
reversion.state = out->state;
|
||||||
|
reversion.strength = (Digital_Strength_t)idp[1].prev;
|
||||||
|
str = reversion.strength;
|
||||||
|
} else {
|
||||||
|
reversion.state = idp[0].prev;
|
||||||
|
val = reversion.state;
|
||||||
|
reversion.strength = out->strength;
|
||||||
|
}
|
||||||
|
cancel_delay = (second_time - TIME) / 2.0;
|
||||||
|
cm_schedule_output(2, 0, cancel_delay, &reversion);
|
||||||
|
break;
|
||||||
|
case Both:
|
||||||
|
/* Push out reversion before normal output. */
|
||||||
|
|
||||||
|
cancel_delay = (second_time - TIME) / 2.0;
|
||||||
|
goto push_revert;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Same:
|
||||||
|
switch (ctl2) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case Revert:
|
||||||
|
/* Normal output is used to revert. */
|
||||||
|
|
||||||
|
delay_1 = (first_time + second_time) / 2.0 - TIME;
|
||||||
|
goto direct_revert;
|
||||||
|
break;
|
||||||
|
case Both:
|
||||||
|
/* Push out reversion before normal output. */
|
||||||
|
|
||||||
|
cancel_delay = (first_time + second_time) / 2.0 - TIME;
|
||||||
|
goto push_revert;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Revert:
|
||||||
|
switch (ctl2) {
|
||||||
|
default:
|
||||||
|
/* Ordinary reversion. */
|
||||||
|
|
||||||
|
delay_1 = (first_time - TIME) / 2.0;
|
||||||
|
d_first = !d_first;
|
||||||
|
goto direct_revert;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Normal:
|
||||||
|
/* Push out state reversion before normal output. */
|
||||||
|
|
||||||
|
cancel_delay = (first_time - TIME) / 2.0;
|
||||||
|
d_first = !d_first;
|
||||||
|
goto push_revert;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Same:
|
||||||
|
/* Set normal output time to restore scheduled output
|
||||||
|
* and push out reversion.
|
||||||
|
*/
|
||||||
|
|
||||||
|
reversion.state = idp[0].prev;
|
||||||
|
reversion.strength = (Digital_Strength_t)idp[1].prev;
|
||||||
|
cancel_delay = (first_time - TIME) / 2.0;
|
||||||
|
cm_schedule_output(2, 0, cancel_delay, &reversion);
|
||||||
|
OUTPUT_DELAY(out) = second_time - TIME;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Revert:
|
||||||
|
/* Revert both together. */
|
||||||
|
|
||||||
|
val = idp[0].prev;
|
||||||
|
str = (Digital_Strength_t)idp[1].prev;
|
||||||
|
OUTPUT_DELAY(out) = (first_time - TIME) / 2.0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Both:
|
||||||
|
/* Double revert with normal output. */
|
||||||
|
|
||||||
|
reversion.state = idp[0].prev;
|
||||||
|
reversion.strength = (Digital_Strength_t)idp[1].prev;
|
||||||
|
cancel_delay = (first_time - TIME) / 2.0;
|
||||||
|
cm_schedule_output(2, 0, cancel_delay, &reversion);
|
||||||
|
|
||||||
|
if (d_first) {
|
||||||
|
val = reversion.state;
|
||||||
|
} else {
|
||||||
|
str = reversion.strength;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Both:
|
||||||
|
switch (ctl2) {
|
||||||
|
default:
|
||||||
|
/* Push out state reversion before normal output. */
|
||||||
|
|
||||||
|
cancel_delay = (first_time - TIME) / 2.0;
|
||||||
|
d_first = !d_first;
|
||||||
|
goto push_revert;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Same:
|
||||||
|
/* Push out reversion, then restore scheduled change,
|
||||||
|
* then normal output.
|
||||||
|
*/
|
||||||
|
|
||||||
|
reversion.state = idp[0].prev;
|
||||||
|
reversion.strength = (Digital_Strength_t)idp[1].prev;
|
||||||
|
cancel_delay = (first_time - TIME) / 2.0;
|
||||||
|
cm_schedule_output(2, 0, cancel_delay, &reversion);
|
||||||
|
|
||||||
|
if (d_first) {
|
||||||
|
restoration.state = reversion.state;
|
||||||
|
restoration.strength = out->strength;
|
||||||
|
} else {
|
||||||
|
restoration.state = out->state;
|
||||||
|
restoration.strength = reversion.strength;
|
||||||
|
}
|
||||||
|
cm_schedule_output(2, 0, second_time - TIME, &restoration);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Revert:
|
||||||
|
case Both:
|
||||||
|
/* Push out double reversion, then normal output. */
|
||||||
|
|
||||||
|
reversion.state = idp[0].prev;
|
||||||
|
reversion.strength = (Digital_Strength_t)idp[1].prev;
|
||||||
|
cancel_delay = (first_time - TIME) / 2.0;
|
||||||
|
cm_schedule_output(2, 0, cancel_delay, &reversion);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out->state = val;
|
out->state = val;
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,8 @@ Description: "delay"
|
||||||
Data_Type: real
|
Data_Type: real
|
||||||
Default_Value: 1.0e-9
|
Default_Value: 1.0e-9
|
||||||
Limits: [1e-12 -]
|
Limits: [1e-12 -]
|
||||||
Vector: no
|
Vector: no
|
||||||
Vector_Bounds: -
|
Vector_bounds: -
|
||||||
Null_Allowed: yes
|
Null_Allowed: yes
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -61,10 +61,8 @@ Vector: no no
|
||||||
Vector_Bounds: - -
|
Vector_Bounds: - -
|
||||||
Null_Allowed: yes yes
|
Null_Allowed: yes yes
|
||||||
|
|
||||||
|
|
||||||
PARAMETER_TABLE:
|
PARAMETER_TABLE:
|
||||||
|
|
||||||
|
|
||||||
Parameter_Name: inertial_delay family
|
Parameter_Name: inertial_delay family
|
||||||
Description: "swallow short pulses" "Logic family for bridging"
|
Description: "swallow short pulses" "Logic family for bridging"
|
||||||
Data_Type: boolean string
|
Data_Type: boolean string
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,8 @@
|
||||||
<None Include="..\..\src\xspice\icm\analog\multi_input_pwl\ifspec.ifs" />
|
<None Include="..\..\src\xspice\icm\analog\multi_input_pwl\ifspec.ifs" />
|
||||||
<None Include="..\..\src\xspice\icm\analog\oneshot\cfunc.mod" />
|
<None Include="..\..\src\xspice\icm\analog\oneshot\cfunc.mod" />
|
||||||
<None Include="..\..\src\xspice\icm\analog\oneshot\ifspec.ifs" />
|
<None Include="..\..\src\xspice\icm\analog\oneshot\ifspec.ifs" />
|
||||||
|
<None Include="..\..\src\xspice\icm\analog\pwlts\cfunc.mod" />
|
||||||
|
<None Include="..\..\src\xspice\icm\analog\pwlts\ifspec.ifs" />
|
||||||
<None Include="..\..\src\xspice\icm\analog\pwl\cfunc.mod" />
|
<None Include="..\..\src\xspice\icm\analog\pwl\cfunc.mod" />
|
||||||
<None Include="..\..\src\xspice\icm\analog\pwl\ifspec.ifs" />
|
<None Include="..\..\src\xspice\icm\analog\pwl\ifspec.ifs" />
|
||||||
<None Include="..\..\src\xspice\icm\analog\sine\cfunc.mod" />
|
<None Include="..\..\src\xspice\icm\analog\sine\cfunc.mod" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue