From 752c4936c0f5f7c25fc868aaf0c820e6f62637ee Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Fri, 21 Jul 2023 16:33:03 -0700 Subject: [PATCH 01/22] Prevent crashes in udevices.c when malformed U* instances are present. This would happen with incorrectly written U* gates, ff, latches which do not conform to the PSpice specs. Instead, ERROR messages are output which, hopefully, will help a user to debug their subckt. --- src/frontend/udevices.c | 248 ++++++++++++++++++++++++++++++---------- 1 file changed, 189 insertions(+), 59 deletions(-) diff --git a/src/frontend/udevices.c b/src/frontend/udevices.c index cfe27e84d..49822946e 100644 --- a/src/frontend/udevices.c +++ b/src/frontend/udevices.c @@ -438,9 +438,13 @@ static void add_all_port_names(char *subckt_line) } /* skip past .subckt and its name */ tok = strtok(copy_line, " \t"); - tok = strtok(NULL, " \t"); - while ((tok = strtok(NULL, " \t")) != NULL) { - add_port_name(tok); + if (tok) { + tok = strtok(NULL, " \t"); + if (tok) { + while ((tok = strtok(NULL, " \t")) != NULL) { + add_port_name(tok); + } + } } tfree(copy_line); } @@ -1555,13 +1559,17 @@ static struct instance_hdr *create_instance_header(char *line) hdr = TMALLOC(struct instance_hdr, 1); hdr->num1 = -1; hdr->num2 = -1; + hdr->instance_name = NULL; + hdr->instance_type = NULL; /* instance name */ tok = strtok(newline, " \t"); + if (!tok) { delete_instance_hdr(hdr); tfree(newline); return NULL; } tmp = TMALLOC(char, strlen(tok) + 1); (void) memcpy(tmp, tok, strlen(tok) + 1); hdr->instance_name = tmp; /* instance type */ tok = strtok(NULL, " \t"); + if (!tok) { delete_instance_hdr(hdr); tfree(newline); return NULL; } p1 = strchr(tok, '('); if (p1) { /* ...(n1,n2) or ...(n1) */ @@ -1679,7 +1687,7 @@ static Xlatorp gen_dff_instance(struct dff_instance *ip, int withinv) clrb = ip->clrbar; xxp = create_xlator(); - if (eq(preb, "$d_hi")) { + if (eq(preb, "$d_hi") || eq(preb, "$d_nc")) { preb = "NULL"; } else { add_input_pin(preb); @@ -1689,7 +1697,7 @@ static Xlatorp gen_dff_instance(struct dff_instance *ip, int withinv) } } - if (eq(clrb, "$d_hi")) { + if (eq(clrb, "$d_hi") || eq(clrb, "$d_nc")) { clrb = "NULL"; } else { add_input_pin(clrb); @@ -1792,7 +1800,7 @@ static Xlatorp gen_jkff_instance(struct jkff_instance *ip, int withinv) clrb = ip->clrbar; xxp = create_xlator(); - if (eq(preb, "$d_hi")) { + if (eq(preb, "$d_hi") || eq(preb, "$d_nc")) { preb = "NULL"; } else { add_input_pin(preb); @@ -1802,7 +1810,7 @@ static Xlatorp gen_jkff_instance(struct jkff_instance *ip, int withinv) } } - if (eq(clrb, "$d_hi")) { + if (eq(clrb, "$d_hi") || eq(clrb, "$d_nc")) { clrb = "NULL"; } else { add_input_pin(clrb); @@ -1906,7 +1914,7 @@ static Xlatorp gen_dltch_instance(struct dltch_instance *ip, int withinv) clrb = ip->clrbar; xxp = create_xlator(); - if (eq(preb, "$d_hi")) { + if (eq(preb, "$d_hi") || eq(preb, "$d_nc")) { preb = "NULL"; } else { add_input_pin(preb); @@ -1916,7 +1924,7 @@ static Xlatorp gen_dltch_instance(struct dltch_instance *ip, int withinv) } } - if (eq(clrb, "$d_hi")) { + if (eq(clrb, "$d_hi") || eq(clrb, "$d_nc")) { clrb = "NULL"; } else { add_input_pin(clrb); @@ -2022,7 +2030,7 @@ static Xlatorp gen_srff_instance(struct srff_instance *srffp, int withinv) clrb = srffp->clrbar; xxp = create_xlator(); - if (eq(preb, "$d_hi")) { + if (eq(preb, "$d_hi") || eq(preb, "$d_nc")) { preb = "NULL"; } else { add_input_pin(preb); @@ -2032,7 +2040,7 @@ static Xlatorp gen_srff_instance(struct srff_instance *srffp, int withinv) } } - if (eq(clrb, "$d_hi")) { + if (eq(clrb, "$d_hi") || eq(clrb, "$d_nc")) { clrb = "NULL"; } else { add_input_pin(clrb); @@ -3088,12 +3096,15 @@ static BOOL u_process_model(char *nline, char *original) /* .model */ tok = strtok(nline, " \t"); + if (!tok) { return FALSE; } /* model name */ tok = strtok(NULL, " \t"); + if (!tok) { return FALSE; } tmodel = TMALLOC(char, strlen(tok) + 1); memcpy(tmodel, tok, strlen(tok) + 1); /* model utype */ tok = strtok(NULL, " \t("); + if (!tok) { tfree(tmodel); return FALSE; } utype = TMALLOC(char, strlen(tok) + 1); memcpy(utype, tok, strlen(tok) + 1); @@ -3166,19 +3177,24 @@ static struct dff_instance *add_dff_inout_timing_model( char *name, **arrp; int i, num_gates = hdr->num1; struct dff_instance *dffip = NULL; + BOOL compat = TRUE; + if (num_gates < 1) { return NULL; } dffip = create_dff_instance(hdr); dffip->num_gates = num_gates; copyline = TMALLOC(char, strlen(start) + 1); (void) memcpy(copyline, start, strlen(start) + 1); /* prebar, clrbar, clk */ tok = strtok(copyline, " \t"); + if (!tok) { goto bail_out; } dffip->prebar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dffip->prebar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } dffip->clrbar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dffip->clrbar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } dffip->clk = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dffip->clk, tok, strlen(tok) + 1); /* d inputs */ @@ -3186,6 +3202,7 @@ static struct dff_instance *add_dff_inout_timing_model( arrp = dffip->d_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } arrp[i] = get_name_hilo(tok); } /* q_out outputs */ @@ -3193,6 +3210,7 @@ static struct dff_instance *add_dff_inout_timing_model( arrp = dffip->q_out; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); arrp[i] = name; @@ -3202,12 +3220,14 @@ static struct dff_instance *add_dff_inout_timing_model( arrp = dffip->qb_out; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); arrp[i] = name; } /* timing model */ tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } dffip->tmodel = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dffip->tmodel, tok, strlen(tok) + 1); tfree(copyline); @@ -3216,20 +3236,27 @@ static struct dff_instance *add_dff_inout_timing_model( arrp = dffip->d_in; for (i = 0; i < num_gates; i++) { if (eq(arrp[i], "$d_nc")) { - delete_dff_instance(dffip); - return NULL; + fprintf(stderr, "ERROR incompatible dff d input $d_nc\n"); + compat = FALSE; + break; } } - if (eq(dffip->prebar, "$d_lo") || eq(dffip->prebar, "$d_nc")) { - delete_dff_instance(dffip); - return NULL; + if (eq(dffip->clk, "$d_nc")) { + fprintf(stderr, "ERROR incompatible dff clk $d_nc\n"); + compat = FALSE; } - if (eq(dffip->clrbar, "$d_lo") || eq(dffip->clrbar, "$d_nc")) { + if (compat) { + return dffip; + } else { delete_dff_instance(dffip); return NULL; } - return dffip; +bail_out: + fprintf(stderr, "ERROR parsing dff\n"); + delete_dff_instance(dffip); + tfree(copyline); + return NULL; } static struct dltch_instance *add_dltch_inout_timing_model( @@ -3239,19 +3266,24 @@ static struct dltch_instance *add_dltch_inout_timing_model( char *name, **arrp; int i, num_gates = hdr->num1; struct dltch_instance *dlp = NULL; + BOOL compat = TRUE; + if (num_gates < 1) { return NULL; } dlp = create_dltch_instance(hdr); dlp->num_gates = num_gates; copyline = TMALLOC(char, strlen(start) + 1); (void) memcpy(copyline, start, strlen(start) + 1); /* prebar, clrbar, clk(gate) */ tok = strtok(copyline, " \t"); + if (!tok) { goto bail_out; } dlp->prebar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dlp->prebar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } dlp->clrbar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dlp->clrbar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } dlp->gate = get_name_hilo(tok); /* d inputs */ @@ -3259,6 +3291,7 @@ static struct dltch_instance *add_dltch_inout_timing_model( arrp = dlp->d_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } arrp[i] = get_name_hilo(tok); } /* q_out outputs */ @@ -3266,6 +3299,7 @@ static struct dltch_instance *add_dltch_inout_timing_model( arrp = dlp->q_out; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); arrp[i] = name; @@ -3275,12 +3309,14 @@ static struct dltch_instance *add_dltch_inout_timing_model( arrp = dlp->qb_out; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); arrp[i] = name; } /* timing model */ tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } dlp->tmodel = TMALLOC(char, strlen(tok) + 1); (void) memcpy(dlp->tmodel, tok, strlen(tok) + 1); tfree(copyline); @@ -3289,23 +3325,27 @@ static struct dltch_instance *add_dltch_inout_timing_model( arrp = dlp->d_in; for (i = 0; i < num_gates; i++) { if (eq(arrp[i], "$d_nc")) { - delete_dltch_instance(dlp); - return NULL; + fprintf(stderr, "ERROR incompatible dltch d input $d_nc\n"); + compat = FALSE; + break; } } if (eq(dlp->gate, "$d_nc")) { + fprintf(stderr, "ERROR incompatible dltch gate $d_nc\n"); + compat = FALSE; + } + if (compat) { + return dlp; + } else { delete_dltch_instance(dlp); return NULL; } - if (eq(dlp->prebar, "$d_lo") || eq(dlp->prebar, "$d_nc")) { - delete_dltch_instance(dlp); - return NULL; - } - if (eq(dlp->clrbar, "$d_lo") || eq(dlp->clrbar, "$d_nc")) { - delete_dltch_instance(dlp); - return NULL; - } - return dlp; + +bail_out: + fprintf(stderr, "ERROR parsing dltch\n"); + delete_dltch_instance(dlp); + tfree(copyline); + return NULL; } static struct jkff_instance *add_jkff_inout_timing_model( @@ -3315,19 +3355,24 @@ static struct jkff_instance *add_jkff_inout_timing_model( char *name, **arrp, **arrpk; int i, num_gates = hdr->num1; struct jkff_instance *jkffip = NULL; + BOOL compat = TRUE; + if (num_gates < 1) { return NULL; } jkffip = create_jkff_instance(hdr); jkffip->num_gates = num_gates; copyline = TMALLOC(char, strlen(start) + 1); (void) memcpy(copyline, start, strlen(start) + 1); /* prebar, clrbar, clkbar */ tok = strtok(copyline, " \t"); + if (!tok) { goto bail_out; } jkffip->prebar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(jkffip->prebar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } jkffip->clrbar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(jkffip->clrbar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } jkffip->clkbar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(jkffip->clkbar, tok, strlen(tok) + 1); /* j inputs */ @@ -3335,6 +3380,7 @@ static struct jkff_instance *add_jkff_inout_timing_model( arrp = jkffip->j_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } arrp[i] = get_name_hilo(tok); } /* k inputs */ @@ -3342,6 +3388,7 @@ static struct jkff_instance *add_jkff_inout_timing_model( arrp = jkffip->k_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } arrp[i] = get_name_hilo(tok); } /* q_out outputs */ @@ -3349,6 +3396,7 @@ static struct jkff_instance *add_jkff_inout_timing_model( arrp = jkffip->q_out; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); arrp[i] = name; @@ -3358,12 +3406,14 @@ static struct jkff_instance *add_jkff_inout_timing_model( arrp = jkffip->qb_out; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); arrp[i] = name; } /* timing model */ tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } jkffip->tmodel = TMALLOC(char, strlen(tok) + 1); (void) memcpy(jkffip->tmodel, tok, strlen(tok) + 1); tfree(copyline); @@ -3373,19 +3423,27 @@ static struct jkff_instance *add_jkff_inout_timing_model( arrpk = jkffip->k_in; for (i = 0; i < num_gates; i++) { if (eq(arrp[i], "$d_nc") || eq(arrpk[i], "$d_nc")) { - delete_jkff_instance(jkffip); - return NULL; + fprintf(stderr, "ERROR incompatible jkff j/k input $d_nc\n"); + compat = FALSE; + break; } } - if (eq(jkffip->prebar, "$d_lo") || eq(jkffip->prebar, "$d_nc")) { + if (eq(jkffip->clkbar, "$d_nc")) { + fprintf(stderr, "ERROR incompatible jkff clkbar $d_nc\n"); + compat = FALSE; + } + if (compat) { + return jkffip; + } else { delete_jkff_instance(jkffip); return NULL; } - if (eq(jkffip->clrbar, "$d_lo") || eq(jkffip->clrbar, "$d_nc")) { - delete_jkff_instance(jkffip); - return NULL; - } - return jkffip; + +bail_out: + fprintf(stderr, "ERROR parsing jkff\n"); + delete_jkff_instance(jkffip); + tfree(copyline); + return NULL; } static struct srff_instance *add_srff_inout_timing_model( @@ -3395,7 +3453,9 @@ static struct srff_instance *add_srff_inout_timing_model( char *name, **arrp, **arrpr; int i, num_gates = hdr->num1; struct srff_instance *srffp = NULL; + BOOL compat = TRUE; + if (num_gates < 1) { return NULL; } srffp = create_srff_instance(hdr); srffp->num_gates = num_gates; copyline = TMALLOC(char, strlen(start) + 1); @@ -3403,14 +3463,17 @@ static struct srff_instance *add_srff_inout_timing_model( /* prebar, clrbar, gate */ tok = strtok(copyline, " \t"); + if (!tok) { goto bail_out; } srffp->prebar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(srffp->prebar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } srffp->clrbar = TMALLOC(char, strlen(tok) + 1); (void) memcpy(srffp->clrbar, tok, strlen(tok) + 1); tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } srffp->gate = get_name_hilo(tok); /* s inputs */ @@ -3418,6 +3481,7 @@ static struct srff_instance *add_srff_inout_timing_model( arrp = srffp->s_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } arrp[i] = get_name_hilo(tok); } /* r inputs */ @@ -3425,6 +3489,7 @@ static struct srff_instance *add_srff_inout_timing_model( arrp = srffp->r_in; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } arrp[i] = get_name_hilo(tok); } /* q_out outputs */ @@ -3432,6 +3497,7 @@ static struct srff_instance *add_srff_inout_timing_model( arrp = srffp->q_out; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); arrp[i] = name; @@ -3441,12 +3507,14 @@ static struct srff_instance *add_srff_inout_timing_model( arrp = srffp->qb_out; for (i = 0; i < num_gates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); arrp[i] = name; } /* timing model */ tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } srffp->tmodel = TMALLOC(char, strlen(tok) + 1); (void) memcpy(srffp->tmodel, tok, strlen(tok) + 1); tfree(copyline); @@ -3456,23 +3524,27 @@ static struct srff_instance *add_srff_inout_timing_model( arrpr = srffp->r_in; for (i = 0; i < num_gates; i++) { if (eq(arrp[i], "$d_nc") || eq(arrpr[i], "$d_nc")) { - delete_srff_instance(srffp); - return NULL; + fprintf(stderr, "ERROR incompatible srff s/r input $d_nc\n"); + compat = FALSE; + break; } } - if (eq(srffp->gate, "$d_nc")) { + if (eq(srffp->gate, "$d_nc")) { /* d_srff clk cannot be null */ + fprintf(stderr, "ERROR incompatible srff gate $d_nc\n"); + compat = FALSE; + } + if (compat) { + return srffp; + } else { delete_srff_instance(srffp); return NULL; } - if (eq(srffp->prebar, "$d_lo") || eq(srffp->prebar, "$d_nc")) { - delete_srff_instance(srffp); - return NULL; - } - if (eq(srffp->clrbar, "$d_lo") || eq(srffp->clrbar, "$d_nc")) { - delete_srff_instance(srffp); - return NULL; - } - return srffp; + +bail_out: + fprintf(stderr, "ERROR parsing srff\n"); + delete_srff_instance(srffp); + tfree(copyline); + return NULL; } static struct compound_instance *add_compound_inout_timing_model( @@ -3485,8 +3557,9 @@ static struct compound_instance *add_compound_inout_timing_model( BOOL first = TRUE; if (is_compound_gate(itype)) { - inwidth = n1; - numgates = n2; + inwidth = n1; + numgates = n2; + if (inwidth < 2 || numgates < 1) { return NULL; } } else { return NULL; } @@ -3504,9 +3577,11 @@ static struct compound_instance *add_compound_inout_timing_model( for (j = 0; j < inwidth; j++) { if (first) { tok = strtok(copyline, " \t"); + if (!tok) { goto bail_out; } first = FALSE; } else { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); @@ -3516,16 +3591,24 @@ static struct compound_instance *add_compound_inout_timing_model( } /* one output */ tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); compi->output = name; /* timing model */ tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); compi->tmodel = name; tfree(copyline); return compi; + +bail_out: + fprintf(stderr, "ERROR parsing compound instance\n"); + delete_compound_instance(compi); + tfree(copyline); + return NULL; } static struct gate_instance *add_array_inout_timing_model( @@ -3540,23 +3623,29 @@ static struct gate_instance *add_array_inout_timing_model( if (is_tristate_buf_array(itype)) { inwidth = 1; numgates = n1; + if (numgates < 1) { return NULL; } tristate = TRUE; } else if (is_buf_gate_array(itype)) { inwidth = 1; numgates = n1; + if (numgates < 1) { return NULL; } } else if (is_vector_gate_array(itype)) { inwidth = n1; numgates = n2; + if (inwidth < 2 || numgates < 1) { return NULL; } } else if (is_tristate_vector_array(itype)) { inwidth = n1; numgates = n2; + if (inwidth < 2 || numgates < 1) { return NULL; } tristate = TRUE; } else if (is_xor_gate_array(itype)) { inwidth = 2; numgates = n1; + if (numgates < 1) { return NULL; } } else if (is_tristate_xor_array(itype)) { inwidth = 2; numgates = n1; + if (numgates < 1) { return NULL; } tristate = TRUE; } else { return NULL; @@ -3579,9 +3668,11 @@ static struct gate_instance *add_array_inout_timing_model( for (j = 0; j < inwidth; j++) { if (first) { tok = strtok(copyline, " \t"); + if (!tok) { goto bail_out; } first = FALSE; } else { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); @@ -3592,6 +3683,7 @@ static struct gate_instance *add_array_inout_timing_model( /* enable for tristate */ if (tristate) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); gip->enable = name; @@ -3601,17 +3693,25 @@ static struct gate_instance *add_array_inout_timing_model( gip->outputs = outarr; for (i = 0; i < numgates; i++) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); outarr[i] = name; } /* timing model last */ tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); gip->tmodel = name; tfree(copyline); return gip; + +bail_out: + fprintf(stderr, "ERROR parsing array of gates\n"); + delete_gate_instance(gip); + tfree(copyline); + return NULL; } static struct gate_instance *add_gate_inout_timing_model( @@ -3625,8 +3725,10 @@ static struct gate_instance *add_gate_inout_timing_model( if (is_vector_gate(itype)) { inwidth = n1; + if (inwidth < 2) { return NULL; } } else if (is_vector_tristate(itype)) { inwidth = n1; + if (inwidth < 2) { return NULL; } tristate = TRUE; } else if (is_buf_gate(itype)) { inwidth = 1; @@ -3654,9 +3756,11 @@ static struct gate_instance *add_gate_inout_timing_model( for (i = 0; i < inwidth; i++) { if (first) { tok = strtok(copyline, " \t"); + if (!tok) { goto bail_out; } first = FALSE; } else { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); @@ -3665,6 +3769,7 @@ static struct gate_instance *add_gate_inout_timing_model( /* enable for tristate */ if (tristate) { tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); gip->enable = name; @@ -3673,16 +3778,24 @@ static struct gate_instance *add_gate_inout_timing_model( outarr = TMALLOC(char *, gip->num_outs); gip->outputs = outarr; tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); outarr[0] = name; /* timing model last */ tok = strtok(NULL, " \t"); + if (!tok) { goto bail_out; } name = TMALLOC(char, strlen(tok) + 1); (void) memcpy(name, tok, strlen(tok) + 1); gip->tmodel = name; tfree(copyline); return gip; + +bail_out: + fprintf(stderr, "ERROR parsing gate\n"); + delete_gate_instance(gip); + tfree(copyline); + return NULL; } static char *skip_past_words(char *start, int count) @@ -3703,7 +3816,7 @@ static char *skip_past_words(char *start, int count) static Xlatorp translate_pull(struct instance_hdr *hdr, char *start) { char *itype, *xspice, *iname, *newline = NULL, *tok; - char *model_name, *inst_stmt, *model_stmt; + char *model_name = NULL, *inst_stmt = NULL, *model_stmt = NULL; int i, numpulls; Xlatorp xp = NULL; Xlatep xdata = NULL; @@ -3723,6 +3836,11 @@ static Xlatorp translate_pull(struct instance_hdr *hdr, char *start) } else { tok = strtok(NULL, " \t"); } + if (!tok) { + delete_xlator(xp); + xp = NULL; + goto end_of_function; + } inst_stmt = tprintf("a%s_%d %s %s", iname, i, tok, model_name); xdata = create_xlate_translated(inst_stmt); xp = add_xlator(xp, xdata); @@ -3731,9 +3849,10 @@ static Xlatorp translate_pull(struct instance_hdr *hdr, char *start) model_stmt = tprintf(".model %s %s(load = 1pf)", model_name, xspice); xdata = create_xlate_translated(model_stmt); xp = add_xlator(xp, xdata); - tfree(model_stmt); - tfree(model_name); - tfree(newline); +end_of_function: + if (model_stmt) { tfree(model_stmt); } + if (model_name) { tfree(model_name); } + if (newline) { tfree(newline); } delete_instance_hdr(hdr); return xp; } @@ -3829,6 +3948,9 @@ BOOL u_check_instance(char *line) char *xspice, *itype; struct instance_hdr *hdr = create_instance_header(line); + if (!hdr) { + return FALSE; + } itype = hdr->instance_type; xspice = find_xspice_for_delay(itype); if (!xspice) { @@ -3870,6 +3992,9 @@ BOOL u_process_instance(char *nline) Xlatorp xp = NULL; BOOL behav_ret = TRUE; + if (!hdr) { + return FALSE; + } itype = hdr->instance_type; xspice = find_xspice_for_delay(itype); if (!xspice) { @@ -3916,6 +4041,10 @@ BOOL u_process_instance(char *nline) } /* Skip past instance name, type, pwr, gnd */ p1 = skip_past_words(nline, 4); + if (!p1 || strlen(p1) == 0) { + delete_instance_hdr(hdr); + return FALSE; + } if (is_gate(itype) || is_gate_array(itype)) { xp = translate_gate(hdr, p1); } else if (is_tristate(itype) || is_tristate_array(itype)) { @@ -3944,11 +4073,12 @@ BOOL u_process_instance(char *nline) delete_xlator(xp); return TRUE; } else { + if (current_subckt) { + fprintf(stderr, "ERROR in %s\n", current_subckt); + } + fprintf(stderr, "ERROR U* device syntax error\n"); + fprintf(stderr, "ERROR at line \"%s\"\n", nline); if (ps_udevice_exit) { - if (current_subckt) { - fprintf(stderr, "ERROR in %s\n", current_subckt); - } - fprintf(stderr, "ERROR U* device syntax error\n"); fflush(stdout); controlled_exit(EXIT_FAILURE); } From f46f481942564bc696ad995412eb5cac639030b8 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 22 Jul 2023 10:30:37 +0200 Subject: [PATCH 02/22] Remove compiler warnings (VS2022) --- src/frontend/numparam/xpressn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/numparam/xpressn.c b/src/frontend/numparam/xpressn.c index 346cbfc14..f4185c15b 100644 --- a/src/frontend/numparam/xpressn.c +++ b/src/frontend/numparam/xpressn.c @@ -1207,7 +1207,7 @@ insertnumber(dico_t *dico, char **lp, DSTRINGPTR ustr_p) { const char *u = ds_get_buf(ustr_p); char *s = *lp; // Point to line contents - long id; + long id = 0; int n; char *p = strstr(s, "numparm__________"); @@ -1218,7 +1218,7 @@ insertnumber(dico_t *dico, char **lp, DSTRINGPTR ustr_p) (id > 0) && (id < dynsubst + 1)) { /* Found a target for substitution. */ - n = ds_get_length(ustr_p); + n = (int)ds_get_length(ustr_p); if (n <= ACT_CHARACTS) { char buf[ACT_CHARACTS + 1]; From 7027a49663745b4364a32f39b5935001e96a3fcd Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 22 Jul 2023 16:03:34 +0200 Subject: [PATCH 03/22] Add an option nginfo to enable a status report during simulation (currently available only with MS Windows GUI version). --- src/frontend/options.c | 4 +++- src/include/ngspice/fteext.h | 1 + src/winmain.c | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/frontend/options.c b/src/frontend/options.c index 0a17714a5..d246ad318 100644 --- a/src/frontend/options.c +++ b/src/frontend/options.c @@ -24,7 +24,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group bool ft_acctprint = FALSE, ft_noacctprint = FALSE, ft_listprint = FALSE; bool ft_nodesprint = FALSE, ft_optsprint = FALSE, ft_noinitprint = FALSE; bool ft_norefprint = FALSE; -bool ft_ngdebug = FALSE, ft_stricterror = FALSE; +bool ft_ngdebug = FALSE, ft_nginfo = FALSE, ft_stricterror = FALSE; static void setdb(char *str); static struct variable *cp_enqvec_as_var(const char *vec_name, @@ -305,6 +305,8 @@ cp_usrset(struct variable *var, bool isset) ft_noacctprint = isset; } else if (eq(var->va_name, "ngdebug")) { ft_ngdebug = isset; + } else if (eq(var->va_name, "nginfo")) { + ft_nginfo = isset; } else if (eq(var->va_name, "noinit")) { ft_noinitprint = isset; } else if (eq(var->va_name, "norefvalue")) { diff --git a/src/include/ngspice/fteext.h b/src/include/ngspice/fteext.h index 4f2ce0c35..9f6848503 100644 --- a/src/include/ngspice/fteext.h +++ b/src/include/ngspice/fteext.h @@ -266,6 +266,7 @@ extern char *ft_setkwords[]; extern struct card *inp_getopts(struct card *deck); extern struct card *inp_getoptsc(char *line, struct card *options); extern bool ft_ngdebug; +extern bool ft_nginfo; extern bool ft_stricterror; /* parse.c */ diff --git a/src/winmain.c b/src/winmain.c index 8bc92a97e..2fb22aa0c 100644 --- a/src/winmain.c +++ b/src/winmain.c @@ -131,6 +131,7 @@ static HFONT efont; /* Font for element windows */ static HFONT tfont; /* Font for text window */ static HFONT sfont; /* Font for string window */ +extern bool ft_nginfo; /* some additional info printed */ extern bool ft_ngdebug; /* some additional debug info printed */ extern bool ft_batchmode; extern FILE *flogp; /* definition see xmain.c, stdout redirected to file */ @@ -260,7 +261,7 @@ SetAnalyse(char *Analyse, /* in: analysis type */ timebefore.timezone = timenow.timezone; /* info when previous analysis period has finished */ if (strcmp(OldAn, Analyse)) { - if (ft_ngdebug && (strcmp(OldAn, ""))) + if ((ft_nginfo || ft_ngdebug) && (strcmp(OldAn, ""))) win_x_printf("%s finished after %4.2f seconds.\n", OldAn, seconds()); strncpy(OldAn, Analyse, 127); } From 9a6d9501594915f8273b0e63a5ac51253f0e7fd4 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 22 Jul 2023 17:10:30 +0200 Subject: [PATCH 04/22] Make status report (MS Windows only) a little smarter. --- src/spicelib/analysis/cktop.c | 3 ++- src/spicelib/analysis/optran.c | 11 +++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/spicelib/analysis/cktop.c b/src/spicelib/analysis/cktop.c index 50f2dd374..d46cf1024 100644 --- a/src/spicelib/analysis/cktop.c +++ b/src/spicelib/analysis/cktop.c @@ -30,7 +30,8 @@ CKTop (CKTcircuit *ckt, long int firstmode, long int continuemode, int converged; #ifdef HAS_PROGREP - SetAnalyse("op", 0); + if (!ckt->CKTnoOpIter || ckt->CKTnumGminSteps >= 1 || ckt->CKTnumSrcSteps >= 1) + SetAnalyse("op", 0); #endif ckt->CKTmode = firstmode; diff --git a/src/spicelib/analysis/optran.c b/src/spicelib/analysis/optran.c index 8aba4e1a9..f0c7dd76e 100644 --- a/src/spicelib/analysis/optran.c +++ b/src/spicelib/analysis/optran.c @@ -319,9 +319,9 @@ OPtran(CKTcircuit *ckt, int oldconverged) NOISEAN *nojob = (NOISEAN *) ckt->CKTcurJob; */ if(optime == 0) { - -// int type = ckt->CKTcurJob->JOBtype; - +#ifdef HAS_PROGREP + SetAnalyse("optran init", 0); +#endif SPfrontEnd->IFerrorf(ERR_INFO, "Transient op started"); if (opramptime > 0) { CKTnode* n; @@ -483,11 +483,10 @@ OPtran(CKTcircuit *ckt, int oldconverged) resume: #ifdef HAS_PROGREP - if (optime == 0.) - SetAnalyse( "optran init", 0); - else + if (optime > 0) SetAnalyse( "optran", (int)((optime * 1000.) / opfinaltime + 0.5)); #endif + ckt->CKTdelta = MIN(ckt->CKTdelta,ckt->CKTmaxStep); #ifdef XSPICE From d1187e9a34896927531436f37d2663ca9c28b393 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Mon, 24 Jul 2023 14:18:05 +0200 Subject: [PATCH 05/22] Add variable "csnumprec" to allow setting the precision of vectors and variables as arguments to functions listet in manual chapter 17.5. Default is 6, as has been standard up to now. --- src/frontend/variable.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/frontend/variable.c b/src/frontend/variable.c index 9410d4db2..ef28cffed 100644 --- a/src/frontend/variable.c +++ b/src/frontend/variable.c @@ -39,6 +39,7 @@ wordlist *cp_varwl(struct variable *var) wordlist *wl = NULL, *w, *wx = NULL; char *buf; struct variable *vt; + int csnump = 0; switch (var->va_type) { case CP_BOOL: @@ -49,8 +50,10 @@ wordlist *cp_varwl(struct variable *var) buf = tprintf("%d", var->va_num); break; case CP_REAL: - /* This is a case where printnum isn't too good... */ - buf = tprintf("%G", var->va_real); + if (cp_getvar("csnumprec", CP_NUM, &csnump, 0) && csnump > 0) + buf = tprintf("%.*g",csnump, var->va_real); /* csnumprec is set */ + else + buf = tprintf("%G", var->va_real); /* standard behavior */ break; case CP_STRING: buf = copy(var->va_string); From a5535d18d009327a6121374eb1d2cc5820d48779 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 25 Jul 2023 15:16:33 +0200 Subject: [PATCH 06/22] re-enable rcheck debug output with WINGUI --- src/include/ngspice/complex.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/include/ngspice/complex.h b/src/include/ngspice/complex.h index f13c83f1e..27caafa32 100644 --- a/src/include/ngspice/complex.h +++ b/src/include/ngspice/complex.h @@ -5,7 +5,6 @@ #ifndef ngspice_COMPLEX_H #define ngspice_COMPLEX_H - /* Complex numbers. */ struct ngcomplex { double cx_real; @@ -73,6 +72,15 @@ typedef struct { #define cmag(c) (hypot(realpart(c), imagpart(c))) #define radtodeg(c) (cx_degrees ? ((c) * (180 / M_PI)) : (c)) #define degtorad(c) (cx_degrees ? ((c) * (M_PI / 180)) : (c)) +#ifdef HAS_WINGUI +#define rcheck(cond, name)\ + if (!(cond)) {\ + (void) win_x_fprintf(cp_err, "Error: argument out of range for %s\n",\ + name);\ + xrc = -1;\ + goto EXITPOINT;\ + } +#else #define rcheck(cond, name)\ if (!(cond)) {\ (void) fprintf(cp_err, "Error: argument out of range for %s\n",\ @@ -80,6 +88,7 @@ typedef struct { xrc = -1;\ goto EXITPOINT;\ } +#endif #define cdiv(r1, i1, r2, i2, r3, i3) \ { \ From c9548c10c9525c6d4bf38614a858f3bca56ea7b3 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Tue, 25 Jul 2023 15:18:02 +0200 Subject: [PATCH 07/22] Prevent crash when number of parameter dependencies increases beyond limit. Raise the limit from 100 to 200. --- src/frontend/inpcom.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index a4b157de3..1726feed6 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -66,6 +66,8 @@ Author: 1985 Wayne A. Christopher #define NPARAMS 10000 #define FCN_PARAMS 1000 +#define DEPENDSON 200 + #define VALIDCHARS "!$%_#?@.[]&" static struct library { @@ -4745,7 +4747,7 @@ struct dependency { int skip; char *param_name; char *param_str; - char *depends_on[100]; + char *depends_on[DEPENDSON]; struct card *card; }; @@ -5055,6 +5057,11 @@ static void inp_sort_params(struct card *param_cards, for (ind = 0; deps[j].depends_on[ind]; ind++) ; deps[j].depends_on[ind++] = param; + if (ind == DEPENDSON) { + fprintf(stderr, "Error in netlist: Too many parameter dependencies (> %d)\n", ind); + fprintf(stderr, " Please check your netlist.\n"); + controlled_exit(EXIT_BAD); + } deps[j].depends_on[ind] = NULL; } } From 8f3c83f77642182f5a74887856c3fa465603ba4f Mon Sep 17 00:00:00 2001 From: Brian Taylor Date: Mon, 24 Jul 2023 11:00:32 -0700 Subject: [PATCH 08/22] Example for 7490a Pspice subckt. This exercises jkff, logicexp, and pindly conversions to XSPICE. --- examples/digital/digital_devices/7490a.cir | 199 ++++++++++++++++++ .../digital/digital_devices/7490a.clk.stim | 49 +++++ .../digital_devices/7490a.control.stim | 9 + 3 files changed, 257 insertions(+) create mode 100644 examples/digital/digital_devices/7490a.cir create mode 100644 examples/digital/digital_devices/7490a.clk.stim create mode 100644 examples/digital/digital_devices/7490a.control.stim diff --git a/examples/digital/digital_devices/7490a.cir b/examples/digital/digital_devices/7490a.cir new file mode 100644 index 000000000..967a2fe1e --- /dev/null +++ b/examples/digital/digital_devices/7490a.cir @@ -0,0 +1,199 @@ +Conversion of Pspice 7490a decade counters + +* ----------------------------------------------------------- 7490A ------ +* Decade Counters +* +* The TTL Logic Data Book, 1988, TI Pages 2-277 to 2-287 +* bss 2/25/94 +* +.SUBCKT 7490A R01 R02 R91 R92 CKA CKB QA QB QC QD ++ optional: DPWR=$G_DPWR DGND=$G_DGND ++ params: MNTYMXDLY=0 IO_LEVEL=0 + +U1 JKFF(1) DPWR DGND ++ NAND9 NAND0 CKA $D_HI $D_HI QA_O $D_NC ++ D0_EFF IO_STD MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} + +U2 JKFF(1) DPWR DGND ++ $D_HI NANDC CKB QDBAR $D_HI QB_O $D_NC ++ D0_EFF IO_STD MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} + +U3 JKFF(1) DPWR DGND ++ $D_HI NANDC QB_O $D_HI $D_HI QC_O $D_NC ++ D0_EFF IO_STD MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} + +U4 JKFF(1) DPWR DGND ++ NAND9 NAND0 CKB ANDQ QD_O QD_O QDBAR ++ D0_EFF IO_STD MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} + +U5LOG LOGICEXP(6,4) DPWR DGND ++ R01 R02 R91 R92 QB_O QC_O ++ NAND9 NAND0 NANDC ANDQ ++ D0_GATE IO_STD MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} ++ ++ LOGIC: ++ NAND0 = {~(R01 & R02)} ++ NAND9 = {~(R91 & R92)} ++ NANDC = {NAND0 & NAND9} ++ ANDQ = {QB_O & QC_O} + +U6DLY PINDLY(4,0,4) DPWR DGND ++ QA_O QB_O QC_O QD_O ++ CKA CKB NAND9 NAND0 ++ QA QB QC QD ++ IO_STD MNTYMXDLY={MNTYMXDLY} IO_LEVEL={IO_LEVEL} ++ ++ BOOLEAN: ++ CHA = {CHANGED_HL(CKA,0)} ++ CHB = {CHANGED_HL(CKB,0)} ++ SETTO9 = {CHANGED_HL(NAND9,0)} ++ SETTO0 = {CHANGED_HL(NAND0,0)} ++ SET = {SETTO0 | SETTO9} ++ ++ PINDLY: ++ QA = { ++ CASE( ++ SETTO0 & TRN_HL, DELAY(-1,26ns,40ns), ++ SETTO9 & TRN_LH, DELAY(-1,20ns,30ns), ++ CHA & TRN_LH, DELAY(-1,10ns,16ns), ++ CHA & TRN_HL, DELAY(-1,12ns,18ns), ++ DELAY(-1,27ns,41ns))} ++ ++ QB = { ++ CASE( ++ SET & TRN_HL, DELAY(-1,26ns,40ns), ++ CHB & TRN_LH, DELAY(-1,10ns,16ns), ++ CHB & TRN_HL, DELAY(-1,14ns,21ns), ++ DELAY(-1,27ns,41ns))} ++ ++ QC = { ++ CASE( ++ SET & TRN_HL, DELAY(-1,26ns,40ns), ++ CHB & TRN_LH, DELAY(-1,21ns,32ns), ++ CHB & TRN_HL, DELAY(-1,23ns,35ns), ++ DELAY(-1,27ns,41ns))} ++ ++ QD = { ++ CASE( ++ SETTO0 & TRN_HL, DELAY(-1,26ns,40ns), ++ SETTO9 & TRN_LH, DELAY(-1,20ns,30ns), ++ CHB & TRN_LH, DELAY(-1,21ns,32ns), ++ CHB & TRN_HL, DELAY(-1,23ns,35ns), ++ CHA & TRN_LH, DELAY(-1,32ns,48ns), ++ CHA & TRN_HL, DELAY(-1,34ns,50ns), ++ DELAY(-1,35ns,51ns))} + +U7CON CONSTRAINT(8) DPWR DGND ++ R01 R02 R91 R92 CKA CKB NAND9 NAND0 ++ IO_STD IO_LEVEL={IO_LEVEL} ++ ++ FREQ: ++ NODE=CKA ++ MAXFREQ=32MEG ++ ++ FREQ: ++ NODE=CKB ++ MAXFREQ=16MEG ++ ++ WIDTH: ++ NODE=CKA ++ MIN_HI=15ns ++ MIN_LO=15ns ++ ++ WIDTH: ++ NODE=CKB ++ MIN_HI=30ns ++ MIN_LO=30ns ++ ++ WIDTH: ++ NODE=R01 ++ MIN_HI=15ns ++ WHEN = {NAND9!='0} ++ ++ WIDTH: ++ NODE=R02 ++ MIN_HI=15ns ++ WHEN = {NAND9!='0} ++ ++ WIDTH: ++ NODE=R91 ++ MIN_HI=15ns ++ WHEN = {NAND0!='0} ++ ++ WIDTH: ++ NODE=R92 ++ MIN_HI=15ns ++ WHEN = {NAND0!='0} ++ ++ SETUP_HOLD: ++ CLOCK HL = CKA ++ DATA(1) = NAND9 ++ SETUPTIME_HI = 25ns ++ MESSAGE = "SETUP ERROR - R91 R92 SETUP < 25ns" ++ ++ SETUP_HOLD: ++ CLOCK HL = CKB ++ DATA(1) = NAND9 ++ SETUPTIME_HI = 25ns ++ MESSAGE = "SETUP ERROR - R91 R92 SETUP < 25ns" ++ ++ SETUP_HOLD: ++ CLOCK HL = CKA ++ DATA(1) = NAND0 ++ SETUPTIME_HI = 25ns ++ WHEN = {NAND9!='0} ++ MESSAGE = "SETUP ERROR - R01 R02 SETUP < 25ns" ++ ++ SETUP_HOLD: ++ CLOCK HL = CKB ++ DATA(1) = NAND0 ++ SETUPTIME_HI = 25ns ++ WHEN = {NAND9!='0} ++ MESSAGE = "SETUP ERROR - R01 R02 SETUP < 25ns" + +.ENDS 7490A + +* .SUBCKT 7490A R01 R02 R91 R92 CKA CKB QA QB QC QD +* output qa is connected to ckb and clock is applied to cka +* triggered on falling edge of clka +x1 r01 r02 r91 r92 clka qa1 qa1 qb1 qc1 qd1 7490a + +* output qd is connected to cka and clock is applied to ckb +* triggered on falling edge of clkb +***x2 r01 r02 r91 r92 od2 clkb oa2 ob2 oc2 od2 7490a +* the outputs are ordered to match the datasheet for the BCD mode +x2 r01 r02 r91 r92 o2 clkb o1 o4 o3 o2 7490a + +a1 [clka] input_vec1 +.model input_vec1 d_source(input_file = "7490a.clk.stim") +a2 [clkb] input_vec1 +a3 [r01 r02 r91 r92] input_vec2 +.model input_vec2 d_source(input_file = "7490a.control.stim") + +.save all +.control +tran 1ns 6us +run +listing r +eprint r01 r02 r91 r92 clka clkb +eprint qd1 qc1 qb1 qa1 +eprint o1 o2 o3 o4 +* save data to input directory +cd $inputdir +eprvcd r01 r02 r91 r92 clka clkb qd1 qc1 qb1 qa1 o1 o2 o3 o4 > 7490a.vcd +* plotting the vcd file with GTKWave +if $oscompiled = 1 | $oscompiled = 8 ; MS Windows + shell start gtkwave 7490a.vcd --script nggtk.tcl +else + if $oscompiled = 7 ; macOS, manual tweaking required (mark, insert, Zoom Fit) + shell open -a gtkwave 7490a.vcd + else ; Linux and others + shell gtkwave 7490a.vcd --script nggtk.tcl & + end +end + +*plot qd1 qc1 qb1 qa1 digitop +*plot o1 o2 o3 o4 digitop +quit +.endc +.end diff --git a/examples/digital/digital_devices/7490a.clk.stim b/examples/digital/digital_devices/7490a.clk.stim new file mode 100644 index 000000000..65fb27237 --- /dev/null +++ b/examples/digital/digital_devices/7490a.clk.stim @@ -0,0 +1,49 @@ +* T c +* i l +* m k +* e +0ns 1s +100ns 0s +200ns 1s + +300ns 0s +400ns 1s + +500ns 0s +600ns 1s + +700ns 0s +800ns 1s + +1000ns 0s +1200ns 1s + +1400ns 0s +1600ns 1s + +1800ns 0s +2000ns 1s + +2200ns 0s +2400ns 1s + +2600ns 0s +2800ns 1s + +3000ns 0s +3200ns 1s + +3400ns 0s +3600ns 1s + +3800ns 0s +4000ns 1s + +4200ns 0s +4400ns 1s + +4600ns 0s +4800ns 1s + +5000ns 0s +5200ns 1s diff --git a/examples/digital/digital_devices/7490a.control.stim b/examples/digital/digital_devices/7490a.control.stim new file mode 100644 index 000000000..6bff982fb --- /dev/null +++ b/examples/digital/digital_devices/7490a.control.stim @@ -0,0 +1,9 @@ +* T r r r r +* i 0 0 9 9 +* m 1 2 1 2 +* e +0ns 0s 0s 0s 0s +50ns 0s 0s 1s 1s +250ns 1s 1s 0s 0s +450ns 1s 1s 0s 0s +650ns 0s 0s 0s 0s From e9386155a63c17ce4d7b8f814f6f18d98927c40b Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sat, 29 Jul 2023 09:16:01 +0100 Subject: [PATCH 09/22] Add support for including analog node changes in VCD file output, and an option to explicitly set the VCD timestep. Correct the output value for high-impedance nodes. --- src/frontend/commands.c | 2 +- src/xspice/evt/evtprint.c | 348 +++++++++++++++++++++++++++++++------- 2 files changed, 287 insertions(+), 63 deletions(-) diff --git a/src/frontend/commands.c b/src/frontend/commands.c index a72560cba..8e2988c56 100644 --- a/src/frontend/commands.c +++ b/src/frontend/commands.c @@ -259,7 +259,7 @@ struct comm spcp_coms[] = { { "eprvcd", EVTprintvcd, FALSE, TRUE, { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, arg_enodes, - "node node ... : Print event values into vcd file." }, + "[-a] [-t timescale] node node ... : Print event values into VCD file." }, { "edisplay", EVTdisplay, FALSE, TRUE, { 040000, 040000, 040000, 040000 }, E_BEGINNING, 0, 0, NULL, diff --git a/src/xspice/evt/evtprint.c b/src/xspice/evt/evtprint.c index 624866257..9d9ccb721 100644 --- a/src/xspice/evt/evtprint.c +++ b/src/xspice/evt/evtprint.c @@ -53,6 +53,8 @@ NON-STANDARD FEATURES #include "ngspice/evtproto.h" +#include "ngspice/fteext.h" + #include #include @@ -466,10 +468,11 @@ get_vcdval(char *xspiceval, char **newval) "0z", "1z", "Uz", "0u", "1u", "Uu" }; + static char *returnmap[] = { "0", "1", "x", "0", "1", "x", - "0", "1", "z", + "z", "z", "z", "0", "1", "x" }; @@ -482,7 +485,7 @@ get_vcdval(char *xspiceval, char **newval) /* is it a real number ? */ retval = INPevaluate(&xspiceval, &err, 1); if (err) { - *newval = copy("unknown"); + *newval = copy(xspiceval); // Assume the node type is coded for this. return 2; } *newval = tprintf("%.16g", retval); @@ -495,6 +498,73 @@ get_vcdval(char *xspiceval, char **newval) #define localtime _localtime64 #endif +/* Function to return a real value to be written to a VCD file. */ + +struct reals { + struct dvec *time; // Scale vector + int v_index, last_i; + double factor; + struct dvec *node_vector[EPRINT_MAXARGS]; // For analog nodes +}; + +static double get_real(int index, double when, struct reals *ctx) +{ + struct dvec *dv; + + if (index < ctx->last_i) { + /* Starting a new pass. */ + + if (!ctx->time) { + ctx->v_index = 0; + ctx->time = vec_get("time"); + if (!ctx->time) { + if (ctx->last_i == EPRINT_MAXARGS) { // First time + fprintf(cp_err, + "ERROR - No vector 'time' in current plot\n"); + } + ctx->node_vector[index] = NULL; // No more calls + return NAN; + } + } + + /* Advance the vector index. */ + + while (ctx->v_index < ctx->time->v_length && + ctx->time->v_realdata[ctx->v_index++] < when) ; + ctx->v_index--; + + /* Calculate interpolation factor. */ + + if (ctx->v_index + 1 < ctx->time->v_length) { + ctx->factor = (when - ctx->time->v_realdata[ctx->v_index]); + ctx->factor /= (ctx->time->v_realdata[ctx->v_index + 1] - + ctx->time->v_realdata[ctx->v_index]); + if (ctx->factor < 0.0 || ctx->factor >= 1.0) + ctx->factor = 0.0; // Rounding + } else { + ctx->factor = 0.0; + } + } + + /* Return interpolated value. */ + + ctx->last_i = index; + dv = ctx->node_vector[index]; + if (ctx->v_index < dv->v_length) { + if (ctx->factor == 0.0) { + return dv->v_realdata[ctx->v_index]; + } else { + return dv->v_realdata[ctx->v_index] + + ctx->factor * + (dv->v_realdata[ctx->v_index + 1] - + dv->v_realdata[ctx->v_index]); + } + } else { + ctx->node_vector[index] = NULL; // No more calls + return dv->v_realdata[dv->v_length - 1]; + } +} + /* * A simple vcd file printer. * command 'eprvcd a0 a1 a2 b0 b1 b2 clk > myvcd.vcd' @@ -510,16 +580,23 @@ EVTprintvcd(wordlist *wl) { int i; int nargs; + int timesteps = 0, tspower = -1; wordlist *w; + struct reals ctx; + + double out_time, last_out_time; + + char *node_name[EPRINT_MAXARGS]; - int node_index[EPRINT_MAXARGS]; - int udn_index[EPRINT_MAXARGS]; + int node_index[EPRINT_MAXARGS]; + int udn_index[EPRINT_MAXARGS]; Evt_Node_t *node_data[EPRINT_MAXARGS]; char *node_value[EPRINT_MAXARGS]; char *old_node_value[EPRINT_MAXARGS]; - char node_ident[EPRINT_MAXARGS + 1]; + char node_ident[EPRINT_MAXARGS + 1]; + char vbuf[24][2][EPRINT_MAXARGS]; // Analog value strings CKTcircuit *ckt; @@ -527,19 +604,37 @@ EVTprintvcd(wordlist *wl) Mif_Boolean_t more; - double step = 0.0; double next_step; double this_step; char *value; + /* Check for the "-a" option (output analog values at timesteps) + * and "-t nn": specifies the VCD timestep as a power of ten. + */ + + while (wl && wl->wl_word[0] == '-') { + if (wl->wl_word[1] == 'a' && !wl->wl_word[2]) { + timesteps = 1; + } else if (wl->wl_word[1] == 't' && !wl->wl_word[2]) { + wl = wl->wl_next; + if (wl) + tspower = atoi(wl->wl_word); + else + break; + } else { + break; + } + wl = wl->wl_next; + } + /* Count the number of arguments to the command */ nargs = 0; for (w = wl; w; w = w->wl_next) nargs++; if (nargs < 1) { - printf("Usage: eprvcd ...\n"); + printf("Usage: eprvcd [-a] ...\n"); return; } if (nargs > EPRINT_MAXARGS) { @@ -560,17 +655,41 @@ EVTprintvcd(wordlist *wl) node_table = ckt->evt->info.node_table; /* Get data for each argument */ + w = wl; for (i = 0; i < nargs; i++) { node_name[i] = w->wl_word; node_index[i] = get_index(node_name[i]); - if (node_index[i] < 0) { - fprintf(cp_err, "ERROR - Node %s is not an event node.\n", node_name[i]); - return; - } - udn_index[i] = node_table[node_index[i]]->udn_index; - node_data[i] = ckt->evt->data.node->head[node_index[i]]; + if (node_index[i] >= 0) { + udn_index[i] = node_table[node_index[i]]->udn_index; + node_data[i] = ckt->evt->data.node->head[node_index[i]]; + ctx.node_vector[i] = NULL; + } else { + struct pnode *pn; + struct dvec *dv; + wordlist *save; + + /* Is it an analog parameter/node expression? + * The whole expression must be a single word (no spaces). + */ + + save = w->wl_next; + w->wl_next = NULL; + pn = ft_getpnames_quotes(w, TRUE); + w->wl_next = save; + if (pn) { + dv = ft_evaluate(pn); + free_pnode(pn); + } else { + dv = NULL; + } + if (!dv) { + fprintf(cp_err, "ERROR - Node %s not parsed.\n", node_name[i]); + return; + } + ctx.node_vector[i] = dv; + } node_value[i] = ""; w = w->wl_next; } @@ -606,43 +725,95 @@ EVTprintvcd(wordlist *wl) /* get the sim time resolution based on tstep */ char *unit; - double scale; - double tstep = ckt->CKTstep; + double scale, tick; - /* if selected time step is down to [ms] then report time at [us] etc., always with one level higher resolution */ - if (tstep >= 1e-3) { - unit = "us"; - scale = 1e6; + if (tspower >= 0) { + /* VCD timestep set by "-t" option. */ + + if (tspower == 0) { + unit = "s"; + scale = 1.0; + } else if (tspower < 4) { + unit = "ms"; + tspower = 3 - tspower; + scale = 1e3 * exp10((double)-tspower); + } else if (tspower < 7) { + unit = "us"; + tspower = 6 - tspower; + scale = 1e6 * exp10((double)-tspower); + } else if (tspower < 10) { + unit = "ns"; + tspower = 9 - tspower; + scale = 1e9 * exp10((double)-tspower); + } else if (tspower < 13) { + unit = "ps"; + tspower = 12 - tspower; + scale = 1e12 * exp10((double)-tspower); + } else if (tspower < 16) { + unit = "fs"; + tspower = 15 - tspower; + scale = 1e15 * exp10((double)-tspower); + } else { // 1 fS is the bottom. + unit = "fs"; + tspower = 0; + scale = 1e15; + } + out_printf("$timescale %g %s $end\n", exp10((double)tspower), unit); + } else { + double tstep = ckt->CKTstep; + + /* Use the simulation time step. If the selected time step + * is down to [ms] then report time at [us] etc., + * always with one level higher resolution. + */ + + if (tstep >= 1e-3) { + unit = "us"; + scale = 1e6; + } + else if (tstep >= 1e-6) { + unit = "ns"; + scale = 1e9; + } + else if (tstep >= 1e-9) { + unit = "ps"; + scale = 1e12; + } else { + unit = "fs"; + scale = 1e15; + } + out_printf("$timescale 1 %s $end\n", unit); } - else if (tstep >= 1e-6) { - unit = "ns"; - scale = 1e9; - } - else if (tstep >= 1e-9) { - unit = "ps"; - scale = 1e12; - } - else { - unit = "fs"; - scale = 1e15; - } - out_printf("$timescale 1 %s $end\n", unit); + tick = 1.0 / scale; /* Scan the node data. Go for printing using $dumpvars for the initial values. Also, determine if there is more data following it and if so, what the next step is. */ + + ctx.time = NULL; + ctx.last_i = EPRINT_MAXARGS; // Indicate restart more = MIF_FALSE; next_step = 1e30; for (i = 0; i < nargs; i++) { - step = node_data[i]->step; - g_evt_udn_info[udn_index[i]]->print_val - (node_data[i]->node_value, "all", &value); - old_node_value[i] = node_value[i] = value; - node_data[i] = node_data[i]->next; - if (node_data[i]) { - more = MIF_TRUE; - if (next_step > node_data[i]->step) - next_step = node_data[i]->step; + if (ctx.node_vector[i]) { + /* Analog node or expression. */ + + sprintf(vbuf[0][i], "%.16g", get_real(i, 0.0, &ctx)); + node_value[i] = vbuf[0][i]; + old_node_value[i] = vbuf[1][i]; + strcpy(vbuf[1][i], vbuf[0][i]); + } else { + /* This must return a pointer to a statically-allocated string. */ + + g_evt_udn_info[udn_index[i]]->print_val + (node_data[i]->node_value, "all", &value); + node_data[i] = node_data[i]->next; + old_node_value[i] = node_value[i] = value; + if (node_data[i]) { + more = MIF_TRUE; + if (next_step > node_data[i]->step) + next_step = node_data[i]->step; + } } } @@ -658,7 +829,6 @@ EVTprintvcd(wordlist *wl) } out_printf("$enddefinitions $end\n"); - out_printf("#%lld\n", (unsigned long long)(step * scale)); /* first set of data for initialization or if only op has been calculated */ @@ -676,38 +846,92 @@ EVTprintvcd(wordlist *wl) out_printf("$end\n"); /* While there is more data, get the next values and print */ - while (more) { - more = MIF_FALSE; + last_out_time = 0.0; + while (more || + (timesteps && ctx.time && ctx.v_index + 1 < ctx.time->v_length)) { + int got_one; + this_step = next_step; - next_step = 1e30; - for (i = 0; i < nargs; i++) - if (node_data[i]) { - if (node_data[i]->step == this_step) { - g_evt_udn_info[udn_index[i]]->print_val - (node_data[i]->node_value, "all", &value); - node_value[i] = value; - node_data[i] = node_data[i]->next; - } - if (node_data[i]) { - more = MIF_TRUE; - if (next_step > node_data[i]->step) - next_step = node_data[i]->step; - } + if (timesteps && ctx.time && ctx.v_index + 1 < ctx.time->v_length && + (ctx.time->v_realdata[ctx.v_index + 1] < this_step || + (timesteps && !more))) { + + /* Analogue output at each time step, skipping if they would + * appear simulataneous in the output. + */ + + out_time = ctx.time->v_realdata[ctx.v_index + 1]; + if (out_time - last_out_time < tick) { + ++ctx.v_index; + continue; } - /* timestamp */ - out_printf("#%lld\n", (unsigned long long)(this_step * scale)); + for (i = 0; i < nargs; i++) { + if (ctx.node_vector[i]) + sprintf(node_value[i], "%.16g", + get_real(i, out_time, &ctx)); + } + } else { + /* Process next event. */ + + out_time = this_step; + more = MIF_FALSE; + next_step = 1e30; + for (i = 0; i < nargs; i++) { + if (ctx.node_vector[i]) { + /* Analog node or expression. */ + + sprintf(node_value[i], "%.16g", + get_real(i, this_step, &ctx)); + } else if (node_data[i]) { + if (node_data[i]->step == this_step) { + g_evt_udn_info[udn_index[i]]->print_val + (node_data[i]->node_value, "all", &value); + node_value[i] = value; + node_data[i] = node_data[i]->next; + } + if (node_data[i]) { + more = MIF_TRUE; + if (next_step > node_data[i]->step) + next_step = node_data[i]->step; + } + } + } + } + /* print only values that have changed */ - for (i = 0; i < nargs; i++) { + + for (i = 0, got_one = 0; i < nargs; i++) { if (!eq(old_node_value[i], node_value[i])) { char *buf; + + if (!got_one) { + /* timestamp */ + + out_printf("#%lld\n", + (unsigned long long)(out_time * scale)); + last_out_time = out_time;; + got_one = 1; + } + if (get_vcdval(node_value[i], &buf) == 1) out_printf("r%s %c\n", buf, node_ident[i]); else out_printf("%s%c\n", buf, node_ident[i]); - old_node_value[i] = node_value[i]; + + if (ctx.node_vector[i]) { + char *t; + + /* Swap buffers. */ + + t = old_node_value[i]; + old_node_value[i] = node_value[i]; + node_value[i] = t; + } else {; + old_node_value[i] = node_value[i]; + } tfree(buf); } } From d3a8634afe172bbe34ffeed6e05d4fe5091189c5 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sat, 29 Jul 2023 09:30:51 +0100 Subject: [PATCH 10/22] Marcel Hendrix's fix for Bug #324 - Difference between file and line input for '];' --- src/frontend/inpcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 1726feed6..ddbd0670f 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -3199,7 +3199,7 @@ static void inp_stripcomments_line(char *s, bool cs) /* look for comments */ while ((c = *d) != '\0') { d++; - if (*d == ';') { + if (!cs && *d == ';') { break; } /* outside of .control section, and not in PS mode */ From bead3e3249017b09d31a2820045dfc81c0d3f2c8 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Mon, 3 Jul 2023 19:19:03 +0100 Subject: [PATCH 11/22] Add an option for parameters to the xfer code model to be provided in a Touchstone-format file instead of as a model parameter. The change to mif_inp2.c allows the "table" parameter to be omitted. --- src/xspice/icm/analog/xfer/cfunc.mod | 314 +++++++++++++++++++++----- src/xspice/icm/analog/xfer/ifspec.ifs | 15 +- src/xspice/mif/mif_inp2.c | 4 - 3 files changed, 272 insertions(+), 61 deletions(-) diff --git a/src/xspice/icm/analog/xfer/cfunc.mod b/src/xspice/icm/analog/xfer/cfunc.mod index e57cbeaa8..6da543975 100644 --- a/src/xspice/icm/analog/xfer/cfunc.mod +++ b/src/xspice/icm/analog/xfer/cfunc.mod @@ -1,24 +1,32 @@ /* Transfer function block for AC simulation, based on s_xfer code model. */ #include +#include +#include +#include +#include #define PI 3.141592653589793238462643383279502884197 +#define ALLOC 1024 /* How the table information is stored internally. */ -struct data_pt { - double f; /* Frequency, radians/sec. */ - Mif_Complex_t s; /* The S-parameter. */ +struct data { + int size; /* Table size. */ + double *f; /* Frequency table, radians/sec. */ + Mif_Complex_t *s; /* The S-parameter table. */ }; static void cleanup(ARGS, Mif_Callback_Reason_t reason) { - struct data_pt *table; + struct data *table; switch (reason) { case MIF_CB_DESTROY: - table = (struct data_pt *)STATIC_VAR(table); + table = (struct data *)STATIC_VAR(table); if (table) { + free(table->f); + free(table->s); free(table); STATIC_VAR(table) = NULL; } @@ -26,94 +34,291 @@ static void cleanup(ARGS, Mif_Callback_Reason_t reason) } } +static double *read_file(const char *fn, int span, int offset, + int *size_p, Mif_Boolean_t *ri, Mif_Boolean_t *db) +{ + FILE *fp; + double *file_data; + double mult; + int i, j, line, size, count, skip, want; + char *cp, *word; + double vals[9]; + char buff[1024]; + + fp = fopen(fn, "r"); + if (fp == NULL) { + cm_message_printf("Can not open file %s: %s", fn, strerror(errno)); + return NULL; + } + + /* Find and examine the option line. */ + + line = 0; + while (fgets(buff, sizeof buff, fp)) { + ++line; + if (buff[0] == '#') + break; + } + if (buff[0] != '#') { + cm_message_printf("No option line found in file %s", fn); + fclose(fp); + return NULL; + } + mult = 1.0e9; // Default to GHz + for (cp = buff + 1; *cp; ++cp) { + while (isspace(*cp)) + ++cp; + if (*cp) { + word = cp; + while (*cp && !isspace(*cp)) + ++cp; + *cp++ = '\0'; + + if (!strcmp(word, "MHz")) + mult = 1.0e6; + else if (!strcmp(word, "KHz")) + mult = 1.0e3; + else if (!strcmp(word, "Hz")) + mult = 1.0; + else if (!strcmp(word, "DB")) + *db = MIF_TRUE; + else if (!strcmp(word, "RI")) + *ri = MIF_TRUE; + } + } + + /* Read the data: at most 9 values per line. */ + + size = ALLOC; + file_data = malloc(size * sizeof(double)); + if (!file_data) + goto bad; + want = skip = i = 0; + + while (fgets(buff, sizeof buff, fp)) { + ++line; + count = sscanf(buff, "%lg%lg%lg%lg%lg%lg%lg%lg%lg", + vals, vals + 1, vals + 2, vals + 3, vals + 4, + vals + 5, vals + 6, vals + 7, vals + 8); + if (!count) + continue; + if (span == 9 && count == 5) { + /* Special case: noise data in 2-port file. */ + + cm_message_printf("Ignoring noise parameters in file %s", fn); + break; + } + if (skip) { + if (count > skip) { + j = skip; + skip = 0; + } else { + skip -= count; + continue; + } + } else { + j = 0; + } + + /* Check allocation. */ + + if (i + 3 > size) { + size += ALLOC; + file_data = realloc(file_data, size * sizeof(double)); + if (!file_data) + goto bad; + } + + while (j < count) { + /* Store value. */ + + file_data[i++] = vals[j]; + switch (want) { + case 0: + /* Stored a frequency value. */ + + if (j != 0) + cm_message_printf("Warning: frequency not at start " + "of line %d", + line); + want = 2; + j += offset; + if (j >= count) + skip = j - count; + break; + case 1: + want = 0; + j += span - offset - 1; + if (j >= count) + skip = j - count; + break; + case 2: + j++; + want = 1; + skip = 0; + break; + } + } + } + + if (want || skip) + cm_message_send("Warning: unexpected end of file data."); + *size_p = i / 3; + bad: + fclose(fp); + return file_data; +} + void cm_xfer(ARGS) /* structure holding parms, inputs, outputs, etc. */ { - struct data_pt *table; + struct data *table; Mif_Complex_t ac_gain; double factor; int span, size, i; - span = PARAM(span); if (INIT) { - Mif_Boolean_t ri, db, rad; - int offset, bad = 0, j; - - /* Validate table. */ + Mif_Boolean_t ri, db, rad; + double *file_data; + int offset, bad = 0, j; offset = PARAM(offset); - size = PARAM_SIZE(table); - bad = size % span; - if (!bad) { - for (i = 0; i < size - span; i += span) { - if (PARAM(table[i]) < 0 || - PARAM(table[i + span]) < PARAM(table[i])) { - bad = 1; - break; + span = PARAM(span); + if (offset < 1 || span < offset + 2) { + cm_message_send("Error: impossible span/offset."); + return; + } + + /* Table or File? */ + + if (PARAM(file) == NULL) { + /* Data given by "table" parameter. */ + + file_data = NULL; + size = PARAM_SIZE(table); + bad = size % span || size == 0; + + /* Validate table. */ + + if (!bad) { + for (i = 0; i < size - span; i += span) { + if (PARAM(table[i]) < 0 || + PARAM(table[i + span]) < PARAM(table[i])) { + bad = 1; + break; + } } } - } - if (bad) { - cm_message_send("Warning: badly formed table."); - return; + if (bad) { + cm_message_send("Error: badly formed table."); + return; + } + size /= span; /* Size now in entries. */ + ri = PARAM(r_i); + db = PARAM(db); + rad = PARAM(rad); + } else { + /* Get data from a Touchstone file. */ + + if (!PARAM_NULL(table)) { + cm_message_send("Error: both file and table " + "parameters given."); + return; + } else { + db = MIF_FALSE; + ri = MIF_FALSE; + file_data = read_file(PARAM(file), span, offset, + &size, &ri, &db); + if (file_data == NULL) + return; + span = 3; + rad = MIF_FALSE; + + /* Explicit parameters override file. */ + + if (!PARAM_NULL(r_i)) + ri = PARAM(r_i); + if (!PARAM_NULL(db)) + db = PARAM(db); + if (!PARAM_NULL(rad)) + rad = PARAM(rad); + } } /* Allocate the internal table. */ - size /= span; - table = (struct data_pt *)calloc(size, sizeof(struct data_pt)); + table = (struct data *)malloc(sizeof(struct data)); + if (!table) + return; + table->size = size; + table->f = (double*)malloc(size * sizeof (double)); + if (!table->f) { + free(table); + return; + } + table->s = ( Mif_Complex_t *)malloc(size * sizeof (Mif_Complex_t)); + if (!table->s) { + free(table->f); + free(table); + return; + } STATIC_VAR(table) = table; CALLBACK = cleanup; /* Fill it. */ - ri = PARAM(r_i); - db = PARAM(db); - rad = PARAM(rad); for (i = 0, j = 0; i < size; i++, j += span) { - table[i].f = PARAM(table[j]) * 2.0 * PI; - if (ri) { - table[i].s.real = PARAM(table[j + offset]); - table[i].s.imag = PARAM(table[j + offset + 1]); - } else { - double phase, mag; + double f, a, b; - mag = PARAM(table[j + offset]); + if (file_data) { + f = file_data[j]; + a = file_data[j + 1]; + b = file_data[j + 2]; + } else { + f = PARAM(table[j]); + a = PARAM(table[j + offset]); + b = PARAM(table[j + offset + 1]); + } + table->f[i] = f * 2.0 * PI; + if (ri) { + table->s[i].real = a; + table->s[i].imag = b; + } else { if (db) - mag = pow(10, mag / 20); - phase = PARAM(table[j + offset + 1]); + a = pow(10, a / 20); if (!rad) - phase *= 2 * PI / 360; - table[i].s.real = mag * cos(phase); - table[i].s.imag = mag * sin(phase); + b *= 2 * PI / 360; + table->s[i].real = a * cos(b); + table->s[i].imag = a * sin(b); } } + if (file_data) + free(file_data); } - - table = (struct data_pt *)STATIC_VAR(table); + table = (struct data *)STATIC_VAR(table); if (!table) return; if (ANALYSIS == MIF_AC) { double rv; - size = PARAM_SIZE(table) / span; + size = table->size; rv = RAD_FREQ; - if (rv <= table[0].f) { - ac_gain = table[0].s; - } else if (rv >= table[size - 1].f) { - ac_gain = table[size - 1].s; + if (rv <= table->f[0]) { + ac_gain = table->s[0]; + } else if (rv >= table->f[size - 1]) { + ac_gain = table->s[size - 1]; } else { for (i = 0; i < size; i++) { - if (table[i].f > rv) + if (table->f[i] > rv) break; } /* Linear interpolation. */ - factor = (rv - table[i - 1].f) / (table[i].f - table[i - 1].f); - ac_gain.real = table[i - 1].s.real + - factor * (table[i].s.real - table[i - 1].s.real); - ac_gain.imag = table[i - 1].s.imag + - factor * (table[i].s.imag - table[i - 1].s.imag); + factor = (rv - table->f[i - 1]) / (table->f[i] - table->f[i - 1]); + ac_gain.real = table->s[i - 1].real + + factor * (table->s[i].real - table->s[i - 1].real); + ac_gain.imag = table->s[i - 1].imag + + factor * (table->s[i].imag - table->s[i - 1].imag); } AC_GAIN(out, in) = ac_gain; } else { /* DC, transient ... */ @@ -124,7 +329,6 @@ void cm_xfer(ARGS) /* structure holding parms, inputs, outputs, etc. */ "transient analysis."); } } - OUTPUT(out) = table[0].s.real * INPUT(in); + OUTPUT(out) = table->s[0].real * INPUT(in); } } - diff --git a/src/xspice/icm/analog/xfer/ifspec.ifs b/src/xspice/icm/analog/xfer/ifspec.ifs index 41f2ac177..1caf58711 100644 --- a/src/xspice/icm/analog/xfer/ifspec.ifs +++ b/src/xspice/icm/analog/xfer/ifspec.ifs @@ -23,11 +23,22 @@ PARAMETER_TABLE: Parameter_Name: table Description: "PWL table: frequency/magnitude/phase" Data_Type: real -Default_Value: - +Default_Value: 0 Limits: - Vector: yes Vector_Bounds: [3 -] -Null_Allowed: no +Null_Allowed: yes + +PARAMETER_TABLE: + +Parameter_Name: file +Description: "File in Touchstone format" +Data_Type: string +Default_Value: - +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes PARAMETER_TABLE: diff --git a/src/xspice/mif/mif_inp2.c b/src/xspice/mif/mif_inp2.c index 41f606b9a..e09d8c378 100644 --- a/src/xspice/mif/mif_inp2.c +++ b/src/xspice/mif/mif_inp2.c @@ -579,10 +579,6 @@ MIF_INP2A ( tfree(emessage); gc_end(); return; - } else if((param_info->is_array) && (! param_info->has_conn_ref)) { - LITERR("Defaulted array parameter must have associated array connection"); - gc_end(); - return; } } if((! mdfast->param[i]->is_null) && (param_info->is_array)) { From 54b8171c5371ef34627a03a229f9ff884be38180 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sat, 29 Jul 2023 09:37:57 +0100 Subject: [PATCH 12/22] Add code in ivars.c to look for a SPICE_ROOT environment variable that gives the location of the ngspice installation. That allows binaries to be installed in a different directory to the one compiled in. The spinit startup file is made location-independent by passing a variable giving the location of loadable modules, so this fixes Bug #615 - "spinit contains arch dependent paths, but is installed as noarch DATA". --- src/frontend/cpitf.c | 10 ++++++++++ src/include/ngspice/ngspice.h | 1 + src/misc/ivars.c | 37 +++++++++++++++++++++++++++-------- src/spinit.in | 30 +++++++++++++++------------- 4 files changed, 56 insertions(+), 22 deletions(-) diff --git a/src/frontend/cpitf.c b/src/frontend/cpitf.c index 484b2ff49..b04900ced 100644 --- a/src/frontend/cpitf.c +++ b/src/frontend/cpitf.c @@ -293,10 +293,20 @@ ft_cpinit(void) if ((fp = fopen(buf, "r")) != NULL) { + /* Set a variable to identify the loadable module directory. + * The standard spinit uses it to load XSPICE and OSDI files. + */ + +#define VARNAME "_module_path_" + cp_vset(VARNAME, CP_STRING, Module_Path); + + /* Run spinit */ + cp_interactive = FALSE; inp_spsource(fp, TRUE, buf, FALSE); cp_interactive = TRUE; found = TRUE; + cp_remvar(VARNAME); break; #if defined(HAS_WINGUI) || defined(__MINGW32__) || defined(_MSC_VER) diff --git a/src/include/ngspice/ngspice.h b/src/include/ngspice/ngspice.h index 0937f597d..8d852e9ba 100644 --- a/src/include/ngspice/ngspice.h +++ b/src/include/ngspice/ngspice.h @@ -277,6 +277,7 @@ extern char *News_File; extern char *Spice_Path; extern char *Help_Path; extern char *Lib_Path; +extern char *Module_Path; extern char *Inp_Path; extern char *Infile_Path; extern char *Spice_Exec_Path; diff --git a/src/misc/ivars.c b/src/misc/ivars.c index ce5446982..b26c66d80 100644 --- a/src/misc/ivars.c +++ b/src/misc/ivars.c @@ -10,6 +10,7 @@ char *Spice_Path; char *News_File; char *Help_Path; char *Lib_Path; +char *Module_Path; char *Inp_Path; char *Spice_Exec_Path; @@ -49,23 +50,39 @@ mkvar(char **p, char *path_prefix, char *var_dir, char *env_var) is given, to ../lib, set by src/makefile.am. With Visual C, it is set manually by an entry to ngspice\visualc\src\include\ngspice\config.h. For Windows GUI and Console the path is set relative to the executable.*/ + void ivars(char *argv0) { - char *temp=NULL; + char *root, *temp=NULL; #if defined (HAS_WINGUI) || defined (__MINGW32__) || defined (_MSC_VER) char *ngpath; #endif + root = getenv("SPICE_ROOT"); + if (root) { + temp = tprintf("%s/share/ngspice", root); + mkvar(&Spice_Lib_Dir, root, "share/ngspice", "SPICE_LIB_DIR"); + mkvar(&Module_Path, root, "lib/ngspice", "SPICE_MODULE_DIR"); + } else { #ifdef HAS_RELPATH - Spice_Lib_Dir = temp = copy("../share/ngspice"); -#elif !defined SHARED_MODULE && (defined (HAS_WINGUI) || defined (__MINGW32__) || defined (_MSC_VER)) - ngpath = ngdirname(argv0); - mkvar(&Spice_Lib_Dir, ngpath, "../share/ngspice", "SPICE_LIB_DIR"); - tfree(ngpath); + Spice_Lib_Dir = temp = copy("../share/ngspice"); +#elif !defined SHARED_MODULE && \ + (defined (HAS_WINGUI) || defined (__MINGW32__) || defined (_MSC_VER)) + + ngpath = ngdirname(argv0); + mkvar(&Spice_Lib_Dir, ngpath, "../share/ngspice", "SPICE_LIB_DIR"); + mkvar(&Module_Path, ngpath, "../lib/ngspice", "SPICE_MODULE_DIR"); + tfree(ngpath); #else - env_overr(&Spice_Lib_Dir, "SPICE_LIB_DIR"); + /* Trim "/share/ngspice" from configured Spice_Lib_Dir. */ + + temp = tprintf("%.*s", strlen(Spice_Lib_Dir) - 14, Spice_Lib_Dir); + mkvar(&Module_Path, temp, "lib/ngspice", "SPICE_MODULE_DIR"); + env_overr(&Spice_Lib_Dir, "SPICE_LIB_DIR"); #endif + } + tfree(temp); /* for printing a news file */ mkvar(&News_File, Spice_Lib_Dir, "news", "SPICE_NEWS"); @@ -75,14 +92,16 @@ ivars(char *argv0) mkvar(&Lib_Path, Spice_Lib_Dir, "scripts", "SPICE_SCRIPTS"); /* used to call ngspice with aspice command, not used in Windows mode */ mkvar(&Spice_Path, Spice_Exec_Dir, "ngspice", "SPICE_PATH"); - tfree(temp); + /* may be used to store input files (*.lib, *.include, ...) */ /* get directory where ngspice resides */ #if defined (HAS_WINGUI) || defined (__MINGW32__) || defined (_MSC_VER) { ngpath = ngdirname(argv0); + /* set path either to /input or, if set, to environment variable NGSPICE_INPUT_DIR */ + mkvar(&Inp_Path, ngpath, "input", "NGSPICE_INPUT_DIR"); tfree(ngpath); } @@ -90,6 +109,7 @@ ivars(char *argv0) NG_IGNORE(argv0); /* set path either to environment variable NGSPICE_INPUT_DIR (if given) or to NULL */ + env_overr(&Inp_Path, "NGSPICE_INPUT_DIR"); Inp_Path = copy(Inp_Path); /* allow tfree */ #endif @@ -100,6 +120,7 @@ ivars(char *argv0) /* Set raw file mode, 0 by default (binary) set in conf.c, may be overridden by environmental variable, not sure if acknowledged everywhere in ngspice */ + env_overr(&temp, "SPICE_ASCIIRAWFILE"); if(temp) AsciiRawFile = atoi(temp); diff --git a/src/spinit.in b/src/spinit.in index f1ca1c285..ed1b4b78f 100644 --- a/src/spinit.in +++ b/src/spinit.in @@ -16,29 +16,31 @@ set x11lineararcs * comment out if central osdi management is set up unset osdi_enabled +* XSPICE and OSDI are loaded from a path provided in a variable. + * Load the codemodels if $?xspice_enabled -@XSPICEINIT@ codemodel @pkglibdir@/spice2poly.cm -@XSPICEINIT@ codemodel @pkglibdir@/analog.cm -@XSPICEINIT@ codemodel @pkglibdir@/digital.cm -@XSPICEINIT@ codemodel @pkglibdir@/xtradev.cm -@XSPICEINIT@ codemodel @pkglibdir@/xtraevt.cm -@XSPICEINIT@ codemodel @pkglibdir@/table.cm +@XSPICEINIT@ codemodel $_module_path_/spice2poly.cm +@XSPICEINIT@ codemodel $_module_path_/analog.cm +@XSPICEINIT@ codemodel $_module_path_/digital.cm +@XSPICEINIT@ codemodel $_module_path_/xtradev.cm +@XSPICEINIT@ codemodel $_module_path_/xtraevt.cm +@XSPICEINIT@ codemodel $_module_path_/table.cm end * Load the OpenVAF/OSDI models if $?osdi_enabled - osdi @pkglibdir@/asmhemt.osdi - osdi @pkglibdir@/bjt504t.osdi - osdi @pkglibdir@/BSIMBULK107.osdi - osdi @pkglibdir@/BSIMCMG.osdi - osdi @pkglibdir@/HICUMl0-2.0.osdi - osdi @pkglibdir@/psp103.osdi - osdi @pkglibdir@/r2_cmc.osdi - osdi @pkglibdir@/vbic_4T_et_cf.osdi + osdi $_module_path_/asmhemt.osdi + osdi $_module_path_/bjt504t.osdi + osdi $_module_path_/BSIMBULK107.osdi + osdi $_module_path_/BSIMCMG.osdi + osdi $_module_path_/HICUMl0-2.0.osdi + osdi $_module_path_/psp103.osdi + osdi $_module_path_/r2_cmc.osdi + osdi $_module_path_/vbic_4T_et_cf.osdi end From c61543a4f348d8605a5ab7bbc1e28caac855d417 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sat, 29 Jul 2023 07:44:22 +0100 Subject: [PATCH 13/22] Fix Bug #629 - "XSPICE d_osc failures". The old code has been completely replaced by a new design that is faster, more reliable and does not usually insert analog breakpoints. --- src/xspice/icm/digital/d_osc/cfunc.mod | 641 +++++++----------------- src/xspice/icm/digital/d_osc/ifspec.ifs | 4 + 2 files changed, 185 insertions(+), 460 deletions(-) diff --git a/src/xspice/icm/digital/d_osc/cfunc.mod b/src/xspice/icm/digital/d_osc/cfunc.mod index 6f16a93e4..01e268f74 100644 --- a/src/xspice/icm/digital/d_osc/cfunc.mod +++ b/src/xspice/icm/digital/d_osc/cfunc.mod @@ -1,479 +1,200 @@ -/*.......1.........2.........3.........4.........5.........6.........7.........8 -================================================================================ +/* XSPICE code model for the Controlled Digital Oscillator. + * This is a complete redesign of the original version by the + * Georgia Tech team, as a fix for ngspice Bug #629 - "XSPICE d_osc failures". + */ -FILE d_osc/cfunc.mod - -Public Domain - -Georgia Tech Research Corporation -Atlanta, Georgia 30332 -PROJECT A-8503-405 - - -AUTHORS - - 24 Jul 1991 Jeffrey P. Murray - - -MODIFICATIONS - - 23 Aug 1991 Jeffrey P. Murray - 30 Sep 1991 Jeffrey P. Murray - 09 Nov 2022 Holger Vogt - 05 Jan 2023 Robert Turnbull - -SUMMARY - - This file contains the model-specific routines used to - functionally describe the d_osc code model. - - -INTERFACES - - FILE ROUTINE CALLED - - CMmacros.h cm_message_send(); - - CM.c void *cm_analog_alloc() - void *cm_analog_get_ptr() - - CMevt.c void cm_event_queue() - - -REFERENCED FILES - - Inputs from and outputs to ARGS structure. - - -NON-STANDARD FEATURES - - NONE - -===============================================================================*/ - -/*=== INCLUDE FILES ====================*/ - -#include "d_osc.h" /* ...contains macros & type defns. - for this model. 7/24/91 - JPM */ #include +#define FACTOR 0.75 // Controls timing of next scheduled call. */ -/*=== CONSTANTS ========================*/ +/* PWL table entry. */ +struct pwl { + double ctl, freq; +}; +/* Called at end to free memory. */ - -/*=== MACROS ===========================*/ - - - - -/*=== LOCAL VARIABLES & TYPEDEFS =======*/ - - -typedef struct { - double *x; - double *y; -} Local_Data_t; - - -/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ - - - - - -/*============================================================================== - -FUNCTION cm_d_osc() - -AUTHORS - - 24 Jul 1991 Jeffrey P. Murray - -MODIFICATIONS - - 30 Sep 1991 Jeffrey P. Murray - -SUMMARY - - This function implements the d_osc code model. - -INTERFACES - - FILE ROUTINE CALLED - - CMmacros.h cm_message_send(); - - CM.c void *cm_analog_alloc() - void *cm_analog_get_ptr() - - CMevt.c void cm_event_queue() - -RETURNED VALUE - - Returns inputs and outputs via ARGS structure. - -GLOBAL VARIABLES - - NONE - -NON-STANDARD FEATURES - - NONE - -==============================================================================*/ - -static void cm_d_osc_callback(ARGS, - Mif_Callback_Reason_t reason) +static void callback(ARGS, Mif_Callback_Reason_t reason) { - switch (reason) { - case MIF_CB_DESTROY: { - Local_Data_t *loc = STATIC_VAR(locdata); - if (loc) { - if (loc->x) - free(loc->x); - if(loc->y) - free(loc->y); - free(loc); - STATIC_VAR(locdata) = loc = NULL; - } - break; - } /* end of case MIF_CB_DESTROY */ - } /* end of switch over reason being called */ -} /* end of function cm_d_osc_callback */ + struct panel_instance *instance; + if (reason == MIF_CB_DESTROY) { + struct pwl *table = STATIC_VAR(locdata); -/*=== CM_D_OSC ROUTINE ===*/ - -/************************************************************* -* The following is the model for the controlled digital * -* oscillator for the ATESSE Version 2.0 system. * -* * -* Created 7/24/91 J.P.Murray * -*************************************************************/ - -/************************************************************* -* * -* * -* <-----duty_cycle-----> * -* I * -* I t2 t3 * -* I \______________/_____ * -* I | | * -* I | | | | * -* I | | * -* I | | | | * -* I | | * -* I | | | | * -* I-----------------*-----* - - - - - - - - - -*--------- * -* t1 t4 * -* * -* * -* t2 = t1 + rise_delay * -* t4 = t3 + fall_delay * -* * -* Note that for the digital model, unlike for the * -* analog "square" model, t1 and t3 are stored and * -* adjusted values, but t2 & t4 are implied by the * -* rise and fall delays of the model, but are otherwise * -* not stored values. JPM * -* * -*************************************************************/ - - -void cm_d_osc(ARGS) -{ - - double *x, /* analog input value control array */ - *y, /* frequency array */ - cntl_input, /* control input value */ - *phase, /* instantaneous phase of the model */ - *phase_old, /* previous phase of the model */ - *t1, /* pointer to t1 value */ - *t3, /* pointer to t3 value */ - /*time1,*/ /* variable for calculating new time1 value */ - /*time3,*/ /* variable for calculating new time3 value */ - freq = 0.0, /* instantaneous frequency value */ - dphase, /* fractional part into cycle */ - duty_cycle, /* duty_cycle value */ - test_double, /* testing variable */ - slope; /* slope value...used to extrapolate - freq values past endpoints. */ - - - int i, /* generic loop counter index */ - cntl_size, /* control array size */ - freq_size; /* frequency array size */ - - Local_Data_t *loc; /* Pointer to local static data, not to be included - in the state vector (save memory!) */ - - - - - /**** Retrieve frequently used parameters... ****/ - - cntl_size = PARAM_SIZE(cntl_array); - freq_size = PARAM_SIZE(freq_array); - duty_cycle = PARAM(duty_cycle); - - - /* check and make sure that the control array is the - same size as the frequency array */ - - if(cntl_size != freq_size){ - cm_message_send(d_osc_array_error); - return; - } - - - if (INIT) { /*** Test for INIT == TRUE. If so, allocate storage, etc. ***/ - - /* Allocate storage for internal variables */ - cm_analog_alloc(0, sizeof(double)); - cm_analog_alloc(1, sizeof(double)); - cm_analog_alloc(2, sizeof(double)); - - /* assign internal variables */ - phase = phase_old = (double *) cm_analog_get_ptr(0,0); - - t1 = (double *) cm_analog_get_ptr(1,0); - - t3 = (double *) cm_analog_get_ptr(2,0); - - /*** allocate static storage for *loc ***/ - STATIC_VAR (locdata) = calloc (1 , sizeof ( Local_Data_t )); - loc = STATIC_VAR (locdata); - CALLBACK = cm_d_osc_callback; - - x = loc->x = (double *) calloc((size_t) cntl_size, sizeof(double)); - if (!x) { - cm_message_send(d_osc_allocation_error); - return; - } - y = loc->y = (double *) calloc((size_t) cntl_size, sizeof(double)); - if (!y) { - cm_message_send(d_osc_allocation_error); - if(x) - free(x); - return; - } - /* Retrieve x and y values. */ - for (i=0; i *phase ) { - *phase = *phase + 360.0; - } - *phase = *phase / 360.0; - - - /* set phase value to init_phase */ - *phase_old = *phase; - - /* preset time values to harmless values... */ - *t1 = -1; - *t3 = -1; - - } - - loc = STATIC_VAR (locdata); - x = loc->x; - y = loc->y; - - /* Retrieve cntl_input value. */ - cntl_input = INPUT(cntl_in); - - /* Determine segment boundaries within which cntl_input resides */ - /*** cntl_input below lowest cntl_voltage ***/ - if (cntl_input <= x[0]) { - - slope = (y[1] - y[0])/(x[1] - x[0]); - freq = y[0] + (cntl_input - x[0]) * slope; - - } - else - /*** cntl_input above highest cntl_voltage ***/ - - if (cntl_input >= x[cntl_size-1]) { - - slope = (y[cntl_size-1] - y[cntl_size-2]) / - (x[cntl_size-1] - x[cntl_size-2]); - freq = y[cntl_size-1] + (cntl_input - x[cntl_size-1]) * slope; - - } - else { /*** cntl_input within bounds of end midpoints... - must determine position progressively & then - calculate required output. ***/ - - for (i=0; i= x[i]) ) { - - /* Interpolate to the correct frequency value */ - - freq = ( (cntl_input - x[i]) / (x[i+1] - x[i]) ) * - ( y[i+1]-y[i] ) + y[i]; - } - } - } - - /*** If freq < 0.0, clamp to 1e-16 & issue a warning ***/ - if ( 0.0 > freq ) { - freq = 1.0e-16; - cm_message_send(d_osc_negative_freq_error); - } - - - /* calculate the instantaneous phase */ - *phase = *phase_old + freq * (TIME - T(1)); - - /* dphase is the percent into the cycle for - the period */ - dphase = *phase_old - floor(*phase_old); - - - /* Calculate the time variables and the output value - for this iteration */ - - if((*t1 <= TIME) && (TIME <= *t3)) { /* output high */ - - *t3 = T(1) + (1 - dphase)/freq; - - if(TIME < *t3) { - cm_event_queue(*t3); - } - } - else - - if((*t3 <= TIME) && (TIME <= *t1)) { /* output low */ - - if(dphase > (1.0 - duty_cycle) ) { - dphase = dphase - 1.0; - } - *t1 = T(1) + ( (1.0 - duty_cycle) - dphase)/freq; - - if(TIME < *t1) { - - cm_event_queue(*t1); - } - } - else { - - if(dphase > (1.0 - duty_cycle) ) { - dphase = dphase - 1.0; - } - *t1 = T(1) + ( (1.0 - duty_cycle) - dphase )/freq; - - if((TIME < *t1) || (T(1) == 0)) { - cm_event_queue(*t1); - } - - *t3 = T(1) + (1 - dphase)/freq; - } - } - break; - - - case EVENT: /** discrete call...lots to do **/ - - test_double = TIME; - - if ( 0.0 == TIME ) { /* DC analysis...preset values, - as appropriate.... */ - - /* retrieve & normalize phase value */ - *phase = PARAM(init_phase); - if ( 0 > *phase ) { - *phase = *phase + 360.0; - } - *phase = *phase / 360.0; - - - /* set phase value to init_phase */ - *phase_old = *phase; - - /* preset time values to harmless values... */ - *t1 = -1; - *t3 = -1; - } - - /* Calculate the time variables and the output value - for this iteration */ - - /* Output is always set to STRONG */ - OUTPUT_STRENGTH(out) = STRONG; - - if( *t1 == TIME ) { /* rising edge */ - - OUTPUT_STATE(out) = ONE; - OUTPUT_DELAY(out) = PARAM(rise_delay); - } - else { - - if ( *t3 == TIME ) { /* falling edge */ - - OUTPUT_STATE(out) = ZERO; - OUTPUT_DELAY(out) = PARAM(fall_delay); - } - - else { /* no change in output */ - - if ( TIME != 0.0 ) { - OUTPUT_CHANGED(out) = FALSE; - } - - if ( (*t1 < TIME) && (TIME < *t3) ) { - OUTPUT_STATE(out) = ONE; - } - else { - OUTPUT_STATE(out) = ZERO; - } - } - } - - break; + if (table) + free(table); + STATIC_VAR(locdata) = NULL; } } +/* Get the current period. */ +static double get_period(double ctl, struct pwl *table, int csize) +{ + double f; + int i; + for (i = 0; i < csize; ++i) { + if (table[i].ctl > ctl) + break; + } + /* Interpolation outside input range continues slope. */ + if (i > 0) { + if (i == csize) + i -= 2; + else + i--; + } + f = table[i].freq + + (ctl - table[i].ctl) * ((table[i + 1].freq - table[i].freq) / + (table[i + 1].ctl - table[i].ctl)); + return 1.0 / f; +} +/* The state data. */ +struct state { + double last_time; // Time of last output change. + Digital_State_t last; // Last value output. +}; + +/* The code-model function. */ + +void cm_d_osc(ARGS) +{ + struct pwl *table; + struct state *state; + double ctl, delta, when; + int csize, i; + + csize = PARAM_SIZE(cntl_array); + if (INIT) { + + /* Validate PWL table. */ + + for (i = 0; i < csize - 1; ++i) { + if (PARAM(cntl_array[i]) >= PARAM(cntl_array[i + 1])) + break; + } + + if (i < csize - 1 || csize != PARAM_SIZE(freq_array)) { + cm_message_send("Badly-formed control table"); + STATIC_VAR(locdata) = NULL; + return; + } + + /* Allocate PWL table. */ + + table = malloc(csize * sizeof (struct pwl)); + STATIC_VAR(locdata) = table; + if (!table) + return; + + for (i = 0; i < csize; ++i) { + table[i].ctl = PARAM(cntl_array[i]); + table[i].freq = PARAM(freq_array[i]); + if (table[i].freq <= 0) { + cm_message_printf("Error: frequency %g is not positve, " + "value replaced by 1e-16.", + table[i].freq); + table[i].freq = 1.0e-16; + } + } + + /* Allocate state data. */ + + cm_event_alloc(0, sizeof (struct state)); + return; + } + + table = STATIC_VAR(locdata); + if (!table) + return; + state = (struct state *)cm_event_get_ptr(0, 0); + + if (CALL_TYPE != EVENT) { + if (TIME == 0.0) { + double phase; + + /* Set initial output and state data. */ + + ctl = INPUT(cntl_in); + delta = get_period(ctl, table, csize); + + phase = PARAM(init_phase); + phase /= 360.0; + if (phase < 0.0) + phase += 1.0; + + /* When would a hypothetical previous transition have been? */ + + state->last_time = delta * (1.0 - PARAM(duty_cycle) - phase); + if (state->last_time < 0.0) { + state->last = ONE; + } else { + state->last = ZERO; + state->last_time = -delta * phase; + } + } + return; + } + + /* Event call; either one requested previously or just before + * a time-step is accepted. + */ + + if (TIME == 0.0) { + OUTPUT_STATE(out) = state->last; + OUTPUT_STRENGTH(out) = STRONG; + return; + } + + /* When is the next transition due? */ + + ctl = INPUT(cntl_in); + delta = get_period(ctl, table, csize); + if (state->last) + delta *= PARAM(duty_cycle); + else + delta *= (1.0 - PARAM(duty_cycle)); + when = state->last_time + delta; + + if (TIME >= when) { + /* If the frequency rose rapidly, the transition has been missed. + * Force a shorter time-step and schedule then. + */ + + cm_analog_set_temp_bkpt(state->last_time + FACTOR * delta); + OUTPUT_CHANGED(out) = FALSE; + return; + } + + if (TIME >= state->last_time + FACTOR * delta) { + /* TIME is reasonably close to transition time. Request output. */ + + state->last_time = when; + state->last ^= ONE; + OUTPUT_STATE(out) = state->last; + OUTPUT_STRENGTH(out) = STRONG; + OUTPUT_DELAY(out) = when - TIME; + + /* Request a call in the next half-cycle. */ + + cm_event_queue(when + FACTOR * delta); + } else { + OUTPUT_CHANGED(out) = FALSE; + + if (TIME < state->last_time) { + /* Output transition pending, nothing to do. */ + + return; + } else { + /* Request a call nearer to transition time. */ + + cm_event_queue(state->last_time + FACTOR * delta); + } + } +} diff --git a/src/xspice/icm/digital/d_osc/ifspec.ifs b/src/xspice/icm/digital/d_osc/ifspec.ifs index d28b93014..b70c86058 100644 --- a/src/xspice/icm/digital/d_osc/ifspec.ifs +++ b/src/xspice/icm/digital/d_osc/ifspec.ifs @@ -62,6 +62,10 @@ Vector_Bounds: - - Null_Allowed: yes yes +/* Rise and fall delay parameter are unused, but retained, + * to be compatible with an earlier version. + */ + PARAMETER_TABLE: Parameter_Name: rise_delay fall_delay From e0f618b5dbf3f8c1ecdc626f199c4088a1d1a707 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sat, 29 Jul 2023 09:42:06 +0100 Subject: [PATCH 14/22] Add a comment to say that LT/PSPICE compatability is needed. --- examples/soa/bjt-soa.cir | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/soa/bjt-soa.cir b/examples/soa/bjt-soa.cir index a2a155389..f5da0072a 100644 --- a/examples/soa/bjt-soa.cir +++ b/examples/soa/bjt-soa.cir @@ -1,4 +1,6 @@ SOA check for bipolar +* LTSPICE or PSPICE compatability must be enabled to correctly parse the +* model below, for example with "set ngbehavior=psa" in .spiceinit. Vce c 0 -1 Ib b 0 -1u From 22af06585ed4b43031a0e0c383fed91bd6f76443 Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Sat, 29 Jul 2023 10:35:16 +0100 Subject: [PATCH 15/22] Add example of reading S-parameters from a Touchstone file. --- examples/sp/137mhz_bpf.s2p | 102 +++++++++++++++++++++++++++++++++++++ examples/sp/file.cir | 80 +++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) create mode 100644 examples/sp/137mhz_bpf.s2p create mode 100644 examples/sp/file.cir diff --git a/examples/sp/137mhz_bpf.s2p b/examples/sp/137mhz_bpf.s2p new file mode 100644 index 000000000..26590f41e --- /dev/null +++ b/examples/sp/137mhz_bpf.s2p @@ -0,0 +1,102 @@ +# HZ S RI R 50 +1.07000000000000000000e+08 +9.10612811414344691663e-01 -4.13169361932556822303e-01 +3.58748396996190531752e-03 +7.90670646175397305588e-03 +3.58748396996190531752e-03 +7.90670646175397305588e-03 +9.10612811414344691663e-01 -4.13169361932556822303e-01 +1.07600000000000000000e+08 +9.08235089938359885231e-01 -4.18357965192380332198e-01 +3.87160175700515963443e-03 +8.40506184306095451009e-03 +3.87160175700515963443e-03 +8.40506184306095451009e-03 +9.08235089938359885231e-01 -4.18357965192380332198e-01 +1.08200000000000000000e+08 +9.05749587403653522166e-01 -4.23698325415379828396e-01 +4.18204303082422238630e-03 +8.94004890380398729854e-03 +4.18204303082422238630e-03 +8.94004890380398729854e-03 +9.05749587403653522166e-01 -4.23698325415379883907e-01 +1.08800000000000000000e+08 +9.03148132734517106179e-01 -4.29199802742280811518e-01 +4.52173719143059496539e-03 +9.51491234400438264107e-03 +4.52173719143059496539e-03 +9.51491234400438264107e-03 +9.03148132734517106179e-01 -4.29199802742280811518e-01 +1.09400000000000000000e+08 +9.00421705997276333733e-01 -4.34872530176818039571e-01 +4.89400500260515122081e-03 +1.01332414163138578161e-02 +4.89400500260515122081e-03 +1.01332414163138578161e-02 +9.00421705997276222710e-01 -4.34872530176818039571e-01 +1.10000000000000000000e+08 +8.97560326671087205241e-01 -4.40727493499846412206e-01 +5.30262050968193648925e-03 +1.07990126939620512125e-02 +5.30262050968193648925e-03 +1.07990126939620512125e-02 +8.97560326671087205241e-01 -4.40727493499846467717e-01 +1.10600000000000000000e+08 +8.94552923981059566749e-01 -4.46776620978363570025e-01 +5.75188437592742858595e-03 +1.15166388420669847659e-02 +5.75188437592742858595e-03 +1.15166388420669847659e-02 +8.94552923981059566749e-01 -4.46776620978363570025e-01 +1.11200000000000000000e+08 +8.91387185874491061455e-01 -4.53032884216226061636e-01 +6.24671105749824082110e-03 +1.22910243042241851263e-02 +6.24671105749824082110e-03 +1.22910243042241851263e-02 +8.91387185874491061455e-01 -4.53032884216226061636e-01 +1.11800000000000000000e+08 +8.88049382462717695752e-01 -4.59510411684503461416e-01 +6.79273281927252579881e-03 +1.31276289546426536831e-02 +6.79273281927252579881e-03 +1.31276289546426536831e-02 +8.88049382462717584730e-01 -4.59510411684503461416e-01 +1.12400000000000000000e+08 +8.84524158800256921076e-01 -4.66224616682866299655e-01 +7.39642433361215653059e-03 +1.40325409206529441025e-02 +7.39642433361215653059e-03 +1.40325409206529441025e-02 +8.84524158800256921076e-01 -4.66224616682866299655e-01 +1.13000000000000000000e+08 +8.80794290674400959240e-01 -4.73192341717892483999e-01 +8.06525254871107676047e-03 +1.50125599496431123836e-02 +8.06525254871107676047e-03 +1.50125599496431123836e-02 +8.80794290674400959240e-01 -4.73192341717892483999e-01 +1.13600000000000000000e+08 +8.76840395559183138907e-01 -4.80432021535730224837e-01 +8.80785772578509228159e-03 +1.60752928741492231990e-02 +8.80785772578509228159e-03 +1.60752928741492231990e-02 +8.76840395559183138907e-01 -4.80432021535730169326e-01 +1.14200000000000000000e+08 +8.72640588950992834860e-01 -4.87963867306267284896e-01 +9.63427310957915526701e-03 +1.72292629101185625073e-02 +9.63427310957915526701e-03 +1.72292629101185625073e-02 +8.72640588950992834860e-01 -4.87963867306267395918e-01 +1.14800000000000000000e+08 +8.68170073819481191713e-01 -4.95810074706974301950e-01 +1.05561927286469178083e-02 +1.84840346898929169805e-02 +1.05561927286469178083e-02 +1.84840346898929169805e-02 +8.68170073819481191713e-01 -4.95810074706974246439e-01 +1.15400000000000000000e+08 +8.63400647702665446914e-01 -5.03995058866944289910e-01 +1.15872994754173033044e-02 +1.98503570544751144211e-02 +1.15872994754173033044e-02 +1.98503570544751144211e-02 +8.63400647702665446914e-01 -5.03995058866944289910e-01 +1.16000000000000000000e+08 +8.58300107813398716061e-01 -5.12545719254411613619e-01 +1.27436691026065560678e-02 +2.13403256603461738417e-02 +1.27436691026065560678e-02 +2.13403256603461738417e-02 +8.58300107813398716061e-01 -5.12545719254411613619e-01 +1.16600000000000000000e+08 +8.52831529083974415606e-01 -5.21491737538981703359e-01 +1.40442703825286278885e-02 +2.29675673131932087112e-02 +1.40442703825286278885e-02 +2.29675673131932087112e-02 +8.52831529083974415606e-01 -5.21491737538981703359e-01 +1.17200000000000000000e+08 +8.46952382915109547312e-01 -5.30865911093095221851e-01 +1.55115878109843285948e-02 +2.47474474905705343897e-02 +1.55115878109843285948e-02 +2.47474474905705343897e-02 +8.46952382915109658335e-01 -5.30865911093095221851e-01 +1.17800000000000000000e+08 +8.40613454904811319146e-01 -5.40704523886904042662e-01 +1.71724014566747885946e-02 +2.66973015386259178439e-02 +1.71724014566747885946e-02 +2.66973015386259178439e-02 +8.40613454904811319146e-01 -5.40704523886904042662e-01 +1.18400000000000000000e+08 +8.33757507163127353778e-01 -5.51047754704064529641e-01 +1.90587696432502860799e-02 +2.88366881666843703769e-02 +1.90587696432502860799e-02 +2.88366881666843703769e-02 +8.33757507163127242755e-01 -5.51047754704064529641e-01 +1.19000000000000000000e+08 +8.26317613782773907616e-01 -5.61940119254769165913e-01 +2.12092752066929506050e-02 +3.11876605324044979539e-02 +2.12092752066929506050e-02 +3.11876605324044979539e-02 +8.26317613782773907616e-01 -5.61940119254769165913e-01 +1.19600000000000000000e+08 +8.18215074961415989030e-01 -5.73430936892501019742e-01 +2.36706166567796187639e-02 +3.37750444494076887403e-02 +2.36706166567796187639e-02 +3.37750444494076887403e-02 +8.18215074961415989030e-01 -5.73430936892501019742e-01 +1.20200000000000000000e+08 +8.09356783794367262708e-01 -5.85574802618157308487e-01 +2.64996539077710438481e-02 +3.66267034759058598969e-02 +2.64996539077710438481e-02 +3.66267034759058598969e-02 +8.09356783794367151685e-01 -5.85574802618157308487e-01 +1.20800000000000000000e+08 +7.99631876521557427573e-01 -5.98432028175489127975e-01 +2.97660574957424005349e-02 +3.97737542299275784186e-02 +2.97660574957424005349e-02 +3.97737542299275784186e-02 +7.99631876521557538595e-01 -5.98432028175489127975e-01 +1.21400000000000000000e+08 +7.88907437254089627388e-01 -6.12068987795145957875e-01 +3.35557648838942790270e-02 +4.32506678291533358527e-02 +3.35557648838942790270e-02 +4.32506678291533358527e-02 +7.88907437254089738410e-01 -6.12068987795145957875e-01 +1.22000000000000000000e+08 +7.77022945174120960310e-01 -6.26558256937955193600e-01 +3.79755239917851997178e-02 +4.70951474501905345549e-02 +3.79755239917851997178e-02 +4.70951474501905345549e-02 +7.77022945174120960310e-01 -6.26558256937955304622e-01 +1.22600000000000000000e+08 +7.63783036426104788852e-01 -6.41978353306991378346e-01 +4.31589115020280175705e-02 +5.13475949867441897045e-02 +4.31589115020280175705e-02 +5.13475949867441897045e-02 +7.63783036426104899874e-01 -6.41978353306991267324e-01 +1.23200000000000000000e+08 +7.48947991379154576208e-01 -6.58412756234040386083e-01 +4.92743642326537167886e-02 +5.60498498382881113478e-02 +4.92743642326537167886e-02 +5.60498498382881113478e-02 +7.48947991379154465186e-01 -6.58412756234040386083e-01 +1.23800000000000000000e+08 +7.32221133494524778484e-01 -6.75947654675000730862e-01 +5.65359722796431041214e-02 +6.12426619420981047104e-02 +5.65359722796431041214e-02 +6.12426619420981047104e-02 +7.32221133494524667462e-01 -6.75947654675000730862e-01 +1.24400000000000000000e+08 +7.13232018117048838235e-01 -6.94667487538792149948e-01 +6.52180722502373466654e-02 +6.69609822298508489125e-02 +6.52180722502373466654e-02 +6.69609822298508489125e-02 +7.13232018117048838235e-01 -6.94667487538792149948e-01 +1.25000000000000000000e+08 +6.91513879029558520273e-01 -7.14646672219031442452e-01 +7.56750654227188457313e-02 +7.32254973969026640157e-02 +7.56750654227188457313e-02 +7.32254973969026640157e-02 +6.91513879029558742317e-01 -7.14646672219031664497e-01 +1.25600000000000000000e+08 +6.66473286596086511580e-01 -7.35934751791925023667e-01 +8.83683681884297467235e-02 +8.00276880990771627422e-02 +8.83683681884297467235e-02 +8.00276880990771627422e-02 +6.66473286596086400557e-01 -7.35934751791925023667e-01 +1.26200000000000000000e+08 +6.37349418889811336619e-01 -7.58530139785663415353e-01 +1.03902913067786747958e-01 +8.73036650638884248465e-02 +1.03902913067786747958e-01 +8.73036650638884248465e-02 +6.37349418889811336619e-01 -7.58530139785663415353e-01 +1.26800000000000000000e+08 +6.03160016271287791056e-01 -7.82334008994332363862e-01 +1.23075894784645631375e-01 +9.48884464275511901876e-02 +1.23075894784645631375e-01 +9.48884464275511901876e-02 +6.03160016271287791056e-01 -7.82334008994332252840e-01 +1.27400000000000000000e+08 +5.62631768181749869484e-01 -8.07069443849200984786e-01 +1.46939705431997608143e-01 +1.02435976127424777093e-01 +1.46939705431997608143e-01 +1.02435976127424777093e-01 +5.62631768181750091529e-01 -8.07069443849201206831e-01 +1.28000000000000000000e+08 +5.14116722910564871718e-01 -8.32139762338305111200e-01 +1.76877066035562968693e-01 +1.09279067848783703609e-01 +1.76877066035562968693e-01 +1.09279067848783703609e-01 +5.14116722910564760696e-01 -8.32139762338305111200e-01 +1.28600000000000000000e+08 +4.55508881725662506668e-01 -8.56381160970645760599e-01 +2.14673667923626160237e-01 +1.14184859345813238818e-01 +2.14673667923626160237e-01 +1.14184859345813238818e-01 +4.55508881725662451156e-01 -8.56381160970645538555e-01 +1.29200000000000000000e+08 +3.84210082447127954097e-01 -8.77636826483634058249e-01 +2.62538535983115273176e-01 +1.14933591562888362536e-01 +2.62538535983115273176e-01 +1.14933591562888362536e-01 +3.84210082447127676541e-01 -8.77636826483634058249e-01 +1.29800000000000000000e+08 +2.97282439804261167104e-01 -8.92050849400025880342e-01 +3.22933968491662837241e-01 +1.07620095999508322282e-01 +3.22933968491662837241e-01 +1.07620095999508322282e-01 +2.97282439804260945060e-01 -8.92050849400025658298e-01 +1.30400000000000000000e+08 +1.92124026112849011216e-01 -8.93003103562596822762e-01 +3.97877265327953033580e-01 +8.56008022912990995668e-02 +3.97877265327953033580e-01 +8.56008022912990995668e-02 +1.92124026112848844683e-01 -8.93003103562597155829e-01 +1.31000000000000000000e+08 +6.83696830944386380047e-02 -8.69873938402882518339e-01 +4.87011020451681930776e-01 +3.82777177954215439004e-02 +4.87011020451681930776e-01 +3.82777177954215439004e-02 +6.83696830944385824935e-02 -8.69873938402882740384e-01 +1.31600000000000000000e+08 -6.79609918130797963087e-02 -8.07833653901424253441e-01 +5.83418457384371480501e-01 -4.90815117870006464851e-02 +5.83418457384371480501e-01 -4.90815117870006464851e-02 -6.79609918130799073310e-02 -8.07833653901424364463e-01 +1.32200000000000000000e+08 -1.98153839635750228521e-01 -6.92090925495786102317e-01 +6.67267837493468296550e-01 -1.91046695157952195476e-01 +6.67267837493468296550e-01 -1.91046695157952195476e-01 -1.98153839635750284032e-01 -6.92090925495785880273e-01 +1.32800000000000000000e+08 -2.88122535752197594938e-01 -5.21098980196032735002e-01 +7.03079580788580793538e-01 -3.88742022822993749109e-01 +7.03079580788580793538e-01 -3.88742022822993749109e-01 -2.88122535752197039827e-01 -5.21098980196032179890e-01 +1.33400000000000000000e+08 -3.02899090104842838578e-01 -3.23184234498291922399e-01 +6.54154450530631925709e-01 -6.13095462906359078836e-01 +6.54154450530631925709e-01 -6.13095462906359078836e-01 -3.02899090104841950399e-01 -3.23184234498290756665e-01 +1.34000000000000000000e+08 -2.37828639780715223040e-01 -1.50750676934625182923e-01 +5.13708511510395426924e-01 -8.10441445574923924333e-01 +5.13708511510395426924e-01 -8.10441445574923924333e-01 -2.37828639780715112018e-01 -1.50750676934625460479e-01 +1.34600000000000000000e+08 -1.28778381340762526630e-01 -4.31933080860871232431e-02 +3.15050440267938713923e-01 -9.39304895506694381702e-01 +3.15050440267938713923e-01 -9.39304895506694381702e-01 -1.28778381340763359297e-01 -4.31933080860877338658e-02 +1.35200000000000000000e+08 -2.26687593006301701948e-02 -2.32886210872496057789e-03 +1.02169999172554967770e-01 -9.94505904970966247980e-01 +1.02169999172554967770e-01 -9.94505904970966247980e-01 -2.26687593006293930387e-02 -2.32886210872484955559e-03 +1.35800000000000000000e+08 +5.12317245896800610439e-02 -5.08765253339041323422e-03 -9.86895486310297442856e-02 -9.93785590144210084773e-01 -9.86895486310297442856e-02 -9.93785590144210084773e-01 +5.12317245896809492223e-02 -5.08765253339038547864e-03 +1.36400000000000000000e+08 +8.40418978386497927957e-02 -2.47111790981879020368e-02 -2.81008072924272656046e-01 -9.55699105360378831087e-01 -2.81008072924272656046e-01 -9.55699105360378831087e-01 +8.40418978386494597288e-02 -2.47111790981878742812e-02 +1.37000000000000000000e+08 +7.85557334917619254355e-02 -3.95099779062877409785e-02 -4.47583614504772686615e-01 -8.89908347195507376526e-01 -4.47583614504772686615e-01 -8.89908347195507376526e-01 +7.85557334917602601010e-02 -3.95099779062870748447e-02 +1.37600000000000000000e+08 +4.33521236669899279192e-02 -3.27109643899355928554e-02 -6.01428618147698434981e-01 -7.97078542839531056785e-01 -6.01428618147698434981e-01 -7.97078542839531056785e-01 +4.33521236669892617854e-02 -3.27109643899353708107e-02 +1.38200000000000000000e+08 -8.04940534568654442182e-03 +8.85863432498479319577e-03 -7.40049151858467535448e-01 -6.72446268860972695691e-01 -7.40049151858467535448e-01 -6.72446268860972695691e-01 -8.04940534568665544413e-03 +8.85863432498462666231e-03 +1.38800000000000000000e+08 -5.58391713551985857666e-02 +9.30142688617066060175e-02 -8.52308017760986635913e-01 -5.11665296449570261572e-01 -8.52308017760986635913e-01 -5.11665296449570261572e-01 -5.58391713551986690334e-02 +9.30142688617063284617e-02 +1.39400000000000000000e+08 -7.51065097618354160502e-02 +2.16574628409290537157e-01 -9.19641887566338023241e-01 -3.18925134089829143136e-01 -9.19641887566338023241e-01 -3.18925134089829143136e-01 -7.51065097618356380949e-02 +2.16574628409290093067e-01 +1.40000000000000000000e+08 -4.41585566854835187556e-02 +3.60278820495524731982e-01 -9.24877650887353075504e-01 -1.13360152888461893084e-01 -9.24877650887353075504e-01 -1.13360152888461893084e-01 -4.41585566854836297779e-02 +3.60278820495526064249e-01 +1.40600000000000000000e+08 +4.25841585503898278908e-02 +4.93237478947128604734e-01 -8.65631579526607741748e-01 +7.47351813318648527940e-02 -8.65631579526607741748e-01 +7.47351813318648527940e-02 +4.25841585503898834020e-02 +4.93237478947128660245e-01 +1.41200000000000000000e+08 +1.69816611909315795526e-01 +5.88499794210738835787e-01 -7.59475009375782605936e-01 +2.19152961803428608656e-01 -7.59475009375782605936e-01 +2.19152961803428608656e-01 +1.69816611909315740014e-01 +5.88499794210738613742e-01 +1.41800000000000000000e+08 +3.11691537919532690726e-01 +6.36052617943876796858e-01 -6.33875259743318597572e-01 +3.10624544235383104329e-01 -6.33875259743318597572e-01 +3.10624544235383104329e-01 +3.11691537919532857259e-01 +6.36052617943877018902e-01 +1.42400000000000000000e+08 +4.46363884348691120074e-01 +6.41957335175016075013e-01 -5.11847516613783248829e-01 +3.55896308354627821657e-01 -5.11847516613783248829e-01 +3.55896308354627821657e-01 +4.46363884348690953541e-01 +6.41957335175016075013e-01 +1.43000000000000000000e+08 +5.62328031516411086521e-01 +6.19153247397310035893e-01 -4.05752187949748654994e-01 +3.68512690666458253563e-01 -4.05752187949748654994e-01 +3.68512690666458253563e-01 +5.62328031516411086521e-01 +6.19153247397310257938e-01 +1.43600000000000000000e+08 +6.56703034170113220114e-01 +5.79966141570946946970e-01 -3.19101877505562903092e-01 +3.61323112069375451672e-01 -3.19101877505562903092e-01 +3.61323112069375451672e-01 +6.56703034170113664203e-01 +5.79966141570947391060e-01 +1.44200000000000000000e+08 +7.31225299542947571041e-01 +5.33281885204806793688e-01 -2.50632247696477128418e-01 +3.43661852167726378227e-01 -2.50632247696477128418e-01 +3.43661852167726378227e-01 +7.31225299542947126952e-01 +5.33281885204806571643e-01 +1.44800000000000000000e+08 +7.89253603441596229828e-01 +4.84595814808915670291e-01 -1.97341163269705077710e-01 +3.21406457625694363944e-01 -1.97341163269705077710e-01 +3.21406457625694363944e-01 +7.89253603441595785739e-01 +4.84595814808915281713e-01 +1.45400000000000000000e+08 +8.34238858661892845880e-01 +4.36956610777625931163e-01 -1.56049924295309616618e-01 +2.97930978791497547142e-01 -1.56049924295309616618e-01 +2.97930978791497547142e-01 +8.34238858661892956903e-01 +4.36956610777625931163e-01 +1.46000000000000000000e+08 +8.69145732343485355464e-01 +3.91878699879104397397e-01 -1.24003647625265986387e-01 +2.75027045771496170268e-01 -1.24003647625265986387e-01 +2.75027045771496170268e-01 +8.69145732343485466487e-01 +3.91878699879104508419e-01 +1.46600000000000000000e+08 +8.96333661820903238038e-01 +3.49988747700131330731e-01 -9.90060323794834662436e-02 +2.53557979015644252563e-01 -9.90060323794834662436e-02 +2.53557979015644252563e-01 +8.96333661820903238038e-01 +3.49988747700131330731e-01 +1.47200000000000000000e+08 +9.17614949219226927468e-01 +3.11429199085059171814e-01 -7.93727086503074746870e-02 +2.33868835136589070522e-01 -7.93727086503074746870e-02 +2.33868835136589070522e-01 +9.17614949219226927468e-01 +3.11429199085059060792e-01 +1.47800000000000000000e+08 +9.34360276091864228043e-01 +2.76094265020993989701e-01 -6.38341075139270547334e-02 +2.16027863948048792775e-01 -6.38341075139270547334e-02 +2.16027863948048792775e-01 +9.34360276091864339065e-01 +2.76094265020993934190e-01 +1.48400000000000000000e+08 +9.47601398965509655881e-01 +2.43762504731008078362e-01 -5.14389708525672395556e-02 +1.99963652305866934622e-01 -5.14389708525672395556e-02 +1.99963652305866934622e-01 +9.47601398965509877925e-01 +2.43762504731008078362e-01 +1.49000000000000000000e+08 +9.58115897463989729665e-01 +2.14168948404499598359e-01 -4.14742398544802881588e-02 +1.85541035877714699520e-01 -4.14742398544802881588e-02 +1.85541035877714699520e-01 +9.58115897463989951710e-01 +2.14168948404499737137e-01 +1.49600000000000000000e+08 +9.66492476705455239028e-01 +1.87042904238775814507e-01 -3.34032487122101762189e-02 +1.72602049295914855565e-01 -3.34032487122101762189e-02 +1.72602049295914855565e-01 +9.66492476705455016983e-01 +1.87042904238775786752e-01 +1.50200000000000000000e+08 +9.73179715504686182470e-01 +1.62126666826780146957e-01 -2.68196353517203348038e-02 +1.60987242952528530893e-01 -2.68196353517203348038e-02 +1.60987242952528530893e-01 +9.73179715504686071448e-01 +1.62126666826780230224e-01 +1.50800000000000000000e+08 +9.78521947841751504882e-01 +1.39183784557022988126e-01 -2.14134987589714859135e-02 +1.50546118446372279021e-01 -2.14134987589714859135e-02 +1.50546118446372279021e-01 +9.78521947841751504882e-01 +1.39183784557023071393e-01 +1.51400000000000000000e+08 +9.82785550685771336354e-01 +1.18001749656824000967e-01 -1.69466865545634358392e-02 +1.41141624817103600309e-01 -1.69466865545634358392e-02 +1.41141624817103600309e-01 +9.82785550685771447377e-01 +1.18001749656824028722e-01 +1.52000000000000000000e+08 +9.86178216288868814132e-01 +9.83918184497583336867e-02 -1.32347489362253222661e-02 +1.32651487741551277200e-01 -1.32347489362253222661e-02 +1.32651487741551277200e-01 +9.86178216288868814132e-01 +9.83918184497583614423e-02 +1.52600000000000000000e+08 +9.88863134958873568614e-01 +8.01874542817054003496e-02 -1.01337169681433910545e-02 +1.24967916984866367347e-01 -1.01337169681433910545e-02 +1.24967916984866367347e-01 +9.88863134958873679636e-01 +8.01874542817053725940e-02 +1.53200000000000000000e+08 +9.90969491202608132596e-01 +6.32422036209547150376e-02 -7.53036459310523452471e-03 +1.17996545694793272818e-01 -7.53036459310523452471e-03 +1.17996545694793272818e-01 +9.90969491202608132596e-01 +6.32422036209546178931e-02 +1.53800000000000000000e+08 +9.92600283416096629274e-01 +4.74274344189095364843e-02 -5.33499072627072364050e-03 +1.11655065718824664245e-01 -5.33499072627072364050e-03 +1.11655065718824664245e-01 +9.92600283416096740297e-01 +4.74274344189094532176e-02 +1.54400000000000000000e+08 +9.93838191714249141739e-01 +3.26301535992100377737e-02 -3.47603188170799012532e-03 +1.05871804407971059625e-01 -3.47603188170799012532e-03 +1.05871804407971059625e-01 +9.93838191714249252762e-01 +3.26301535992100655292e-02 +1.55000000000000000000e+08 +9.94750013965809976035e-01 +1.87510036058552952143e-02 -1.89601184847547994325e-03 +1.00584366170223482584e-01 -1.89601184847547994325e-03 +1.00584366170223482584e-01 +9.94750013965810087058e-01 +1.87510036058553541949e-02 +1.55600000000000000000e+08 +9.95390044545548469124e-01 +5.70247464609406271019e-03 -5.48474208879234188460e-04 +9.57383944849925644371e-02 -5.48474208879234188460e-04 +9.57383944849925644371e-02 +9.95390044545548358101e-01 +5.70247464609402454627e-03 +1.56200000000000000000e+08 +9.95802666844078254726e-01 -6.59266390241927680016e-03 +6.04357729233382908254e-04 +9.12864734811606737264e-02 +6.04357729233382908254e-04 +9.12864734811606737264e-02 +9.95802666844078476771e-01 -6.59266390241941557804e-03 +1.56800000000000000000e+08 +9.96024356866451077153e-01 -1.82027258011077906763e-02 +1.59337883713245374688e-03 +8.71871690449039227211e-02 +1.59337883713245374688e-03 +8.71871690449039227211e-02 +9.96024356866451077153e-01 -1.82027258011078219013e-02 +1.57400000000000000000e+08 +9.96085242530484138435e-01 -2.91882839409680835963e-02 +2.44399311414590343985e-03 +8.34042000814511491624e-02 +2.44399311414590343985e-03 +8.34042000814511491624e-02 +9.96085242530484249457e-01 -2.91882839409682293130e-02 +1.58000000000000000000e+08 +9.96010325368780979893e-01 -3.96031820734600165101e-02 +3.17719702261206552590e-03 +7.99057266252640729931e-02 +3.17719702261206552590e-03 +7.99057266252640729931e-02 +9.96010325368780868871e-01 -3.96031820734601414102e-02 +1.58600000000000000000e+08 +9.95820443918286279938e-01 -4.94954038628715592418e-02 +3.81042869700090429397e-03 +7.66637404773824887583e-02 +3.81042869700090429397e-03 +7.66637404773824887583e-02 +9.95820443918286279938e-01 -4.94954038628717118975e-02 +1.59200000000000000000e+08 +9.95533038118758040191e-01 -5.89078191406332413171e-02 +4.35823776215493469827e-03 +7.36535445293586832349e-02 +4.35823776215493469827e-03 +7.36535445293586832349e-02 +9.95533038118758040191e-01 -5.89078191406333107061e-02 +1.59800000000000000000e+08 +9.95162759411343800231e-01 -6.78788250619020705479e-02 +4.83281680415686455687e-03 +7.08533081143968568316e-02 +4.83281680415686455687e-03 +7.08533081143968568316e-02 +9.95162759411343800231e-01 -6.78788250619021260590e-02 +1.60400000000000000000e+08 +9.94721960433816665414e-01 -7.64428976009169786066e-02 +5.24442547538221150172e-03 +6.82436871696847635604e-02 +5.24442547538221150172e-03 +6.82436871696847635604e-02 +9.94721960433816665414e-01 -7.64428976009169924843e-02 +1.61000000000000000000e+08 +9.94221090190744782866e-01 -8.46310666735910210878e-02 +5.60173077184180582405e-03 +6.58074994660734491347e-02 +5.60173077184180582405e-03 +6.58074994660734491347e-02 +9.94221090190744671844e-01 -8.46310666735909933323e-02 +1.61600000000000000000e+08 +9.93669014581268883468e-01 -9.24713262330513763310e-02 +5.91208147855264414677e-03 +6.35294465455359391726e-02 +5.91208147855264414677e-03 +6.35294465455359391726e-02 +9.93669014581268994490e-01 -9.24713262330513208198e-02 +1.62200000000000000000e+08 +9.93073277654830777195e-01 -9.99889889758773103834e-02 +6.18173062538227360840e-03 +6.13958752519111056190e-02 +6.18173062538227360840e-03 +6.13958752519111056190e-02 +9.93073277654830888217e-01 -9.99889889758772687500e-02 +1.62800000000000000000e+08 +9.92440315547563511878e-01 -1.07206993821614179896e-01 +6.41601666392979316789e-03 +5.93945728307992901196e-02 +6.41601666392979316789e-03 +5.93945728307992901196e-02 +9.92440315547563511878e-01 -1.07206993821614304796e-01 +1.63400000000000000000e+08 +9.91775632447570609784e-01 -1.14146173068393613770e-01 +6.61951169993050658052e-03 +5.75145905133327833836e-02 +6.61951169993050658052e-03 +5.75145905133327833836e-02 +9.91775632447570498762e-01 -1.14146173068393641525e-01 +1.64000000000000000000e+08 +9.91083945940665955732e-01 -1.20825485059557466427e-01 +6.79614330234650475260e-03 +5.57460912981033313018e-02 +6.79614330234650475260e-03 +5.57460912981033313018e-02 +9.91083945940665955732e-01 -1.20825485059557480305e-01 +1.64600000000000000000e+08 +9.90369307548545241282e-01 -1.27262217295047858068e-01 +6.94929501848177630374e-03 +5.40802183215780413184e-02 +6.94929501848177630374e-03 +5.40802183215780413184e-02 +9.90369307548545241282e-01 -1.27262217295047941334e-01 +1.65200000000000000000e+08 +9.89635203077614988842e-01 -1.33472164162939582743e-01 +7.08188965026093891070e-03 +5.25089807763467059099e-02 +7.08188965026093891070e-03 +5.25089807763467059099e-02 +9.89635203077614988842e-01 -1.33472164162939554988e-01 +1.65800000000000000000e+08 +9.88884636466070721106e-01 -1.39469782829222455067e-01 +7.19645851328123281609e-03 +5.10251548140958008370e-02 +7.19645851328123281609e-03 +5.10251548140958008370e-02 +9.88884636466070832128e-01 -1.39469782829222455067e-01 +1.66400000000000000000e+08 +9.88120200087577504888e-01 -1.45268330288619573754e-01 +7.29519925013716666329e-03 +4.96221972704053923553e-02 +7.29519925013716666329e-03 +4.96221972704053923553e-02 +9.88120200087577504888e-01 -1.45268330288619601509e-01 +1.67000000000000000000e+08 +9.87344133895558750957e-01 -1.50879984129472066723e-01 +7.38002425990905066427e-03 +4.82941703836292576812e-02 +7.38002425990905066427e-03 +4.82941703836292576812e-02 +9.87344133895558639935e-01 -1.50879984129472038967e-01 diff --git a/examples/sp/file.cir b/examples/sp/file.cir new file mode 100644 index 000000000..bf248f325 --- /dev/null +++ b/examples/sp/file.cir @@ -0,0 +1,80 @@ +Example circuit to read a Touchstone-format parameter file. + +* This file contains an an analog filter circuit; SP and AC analyses are run +* and the S-parameters are saved in a file. It also contains a behavioural +* circuit that reproduces the original from its saved S-parameters. +* Results from the two versions are plotted together for comparison. +* The behavioural circuit also illustrates the use of a string-valued +* sub-circuit parameter to pass a file name. + +* Derived from: Qucs 1.0.2 C:/Users/Tom Hajjar/.qucs - S/S-parameter_files_ngspice_prj/137MHz_BPF.sch + +* Original circuit for SP analysis + +VP2 _net0 0 dc 0 ac 0.316228 SIN(0 0.316228 1G) portnum 2 z0 50 +VP1 _net1 0 dc 0 ac 0.316228 SIN(0 0.316228 1G) portnum 1 z0 50 +C1 _net2 _net1 4.7P +C5 _net3 _net0 4.7P +C3 _net3 _net2 1P +C4 _net3 0 15P +C2 0 _net2 15P +L2 0 _net3 66N +L1 0 _net2 66N + +.csparam Rbase=50 ; This is required by "wrs2p", below. + +* A version derived from extracted s-parameters, with option for subcircuit. + +VP3 net1 0 dc 0 ac 0.316228 ; Same as VP1 but that must not be loaded. +ri net1 sin 50 +.param in_file="137MHz_BPF.s2p" +X1 sin sout 0 s2p_generic touchstone=in_file +ro sout 0 50 + +* Control section, run simulations. + +.control +* Run an SP analysis, derive group delay and write a Touchstone file + +SP LIN 71 107MEG 167MEG +let Group_Delay = -1*deriv(cph(S_2_1))/(2*pi) +wrs2p new_137MHz_BPF.s2p + +* Now run AC analysis + +alter vp2 ac = 0 +AC LIN 71 107MEG 167MEG +plot group_delay(_net0) sp1.Group_Delay group_delay(sout) +plot db(_net0) cph(_net0) db(sout) cph(sout) +.endc + +* Subcircuit for SP behavioral device + +.SUBCKT s2p_generic 1 2 3 touchstone={touchstone} +* Pin 3 is the reference plane (usually it should be connected to GND) +* HZ S RI R 50 +* Z1 = 50 Z2 = 50 +R1N 1 100 -5.000000e+01 +R1P 100 101 100.000000 +R2N 2 200 -5.000000e+01 +R2P 200 201 100.000000 + +* S11 FREQ R_I + A0101 %vd 100 3 %vd 101 102 m_a0101 + .model m_a0101 xfer file=touchstone span=9 + +* S12 FREQ R_I + A0102 %vd 200 3 %vd 102 3 m_a0102 + .model m_a0102 xfer file=touchstone span=9 offset=3 + +* S21 FREQ R_I + A0201 %vd 100 3 %vd 201 202 m_a0201 + .model m_a0201 xfer file=touchstone span=9 offset=5 + +* S22 FREQ R_I + A0202 %vd 200 3 %vd 202 3 m_a0202 + .model m_a0202 xfer file=touchstone span=9 offset=7 + +.ENDS + +.END From 2e3af2658ab85d4f431260f684d4fecbe58f1367 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 30 Jul 2023 08:37:55 +0200 Subject: [PATCH 16/22] fopen_with_path enable path search (directory of recent inputs or NGSPICE_INPUT_DIR) --- src/xspice/icm/analog/xfer/cfunc.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xspice/icm/analog/xfer/cfunc.mod b/src/xspice/icm/analog/xfer/cfunc.mod index 6da543975..eaa67d5e3 100644 --- a/src/xspice/icm/analog/xfer/cfunc.mod +++ b/src/xspice/icm/analog/xfer/cfunc.mod @@ -45,7 +45,7 @@ static double *read_file(const char *fn, int span, int offset, double vals[9]; char buff[1024]; - fp = fopen(fn, "r"); + fp = fopen_with_path(fn, "r"); if (fp == NULL) { cm_message_printf("Can not open file %s: %s", fn, strerror(errno)); return NULL; From b6585c8e141bdfe576b2c128d95b9103cf996254 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 30 Jul 2023 08:39:47 +0200 Subject: [PATCH 17/22] replace exp10() by pow(10, ...), exp10 not available in VS2022 --- src/xspice/evt/evtprint.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/xspice/evt/evtprint.c b/src/xspice/evt/evtprint.c index 9d9ccb721..e4d560ea2 100644 --- a/src/xspice/evt/evtprint.c +++ b/src/xspice/evt/evtprint.c @@ -736,29 +736,29 @@ EVTprintvcd(wordlist *wl) } else if (tspower < 4) { unit = "ms"; tspower = 3 - tspower; - scale = 1e3 * exp10((double)-tspower); + scale = 1e3 * pow(10, (double)-tspower); } else if (tspower < 7) { unit = "us"; tspower = 6 - tspower; - scale = 1e6 * exp10((double)-tspower); + scale = 1e6 * pow(10, (double)-tspower); } else if (tspower < 10) { unit = "ns"; tspower = 9 - tspower; - scale = 1e9 * exp10((double)-tspower); + scale = 1e9 * pow(10, (double)-tspower); } else if (tspower < 13) { unit = "ps"; tspower = 12 - tspower; - scale = 1e12 * exp10((double)-tspower); + scale = 1e12 * pow(10, (double)-tspower); } else if (tspower < 16) { unit = "fs"; tspower = 15 - tspower; - scale = 1e15 * exp10((double)-tspower); + scale = 1e15 * pow(10, (double)-tspower); } else { // 1 fS is the bottom. unit = "fs"; tspower = 0; scale = 1e15; } - out_printf("$timescale %g %s $end\n", exp10((double)tspower), unit); + out_printf("$timescale %g %s $end\n", pow(10, (double)tspower), unit); } else { double tstep = ckt->CKTstep; From 7e91a23804aba1befd54407565b37d048ae4e441 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 30 Jul 2023 08:40:57 +0200 Subject: [PATCH 18/22] Remove vs2022 linker warning (ctx potentially uninitialized) --- src/xspice/evt/evtprint.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xspice/evt/evtprint.c b/src/xspice/evt/evtprint.c index e4d560ea2..ac97fcde3 100644 --- a/src/xspice/evt/evtprint.c +++ b/src/xspice/evt/evtprint.c @@ -791,6 +791,7 @@ EVTprintvcd(wordlist *wl) more data following it and if so, what the next step is. */ ctx.time = NULL; + ctx.v_index = 0; ctx.last_i = EPRINT_MAXARGS; // Indicate restart more = MIF_FALSE; next_step = 1e30; From f4711676a501802f296932275acb64e4b3b74c86 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 30 Jul 2023 08:41:54 +0200 Subject: [PATCH 19/22] better visibility --- examples/sp/file.cir | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/sp/file.cir b/examples/sp/file.cir index bf248f325..c3a9bbcdf 100644 --- a/examples/sp/file.cir +++ b/examples/sp/file.cir @@ -44,6 +44,7 @@ wrs2p new_137MHz_BPF.s2p alter vp2 ac = 0 AC LIN 71 107MEG 167MEG +set xbrushwidth=2 plot group_delay(_net0) sp1.Group_Delay group_delay(sout) plot db(_net0) cph(_net0) db(sout) cph(sout) .endc From adea3dca5eca2daacbc44608ccbb8c07bea71c92 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 30 Jul 2023 14:42:09 +0200 Subject: [PATCH 20/22] 'current time' instead of 'actual time' --- visualc/sharedspice.vcxproj | 6 +++--- visualc/vngspice-fftw.vcxproj | 12 ++++++------ visualc/vngspice.vcxproj | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/visualc/sharedspice.vcxproj b/visualc/sharedspice.vcxproj index 89bc0fbbe..cb905fbb0 100644 --- a/visualc/sharedspice.vcxproj +++ b/visualc/sharedspice.vcxproj @@ -187,7 +187,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj @@ -235,7 +235,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj @@ -325,7 +325,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj diff --git a/visualc/vngspice-fftw.vcxproj b/visualc/vngspice-fftw.vcxproj index 10bb37c03..62b98b0c8 100644 --- a/visualc/vngspice-fftw.vcxproj +++ b/visualc/vngspice-fftw.vcxproj @@ -296,7 +296,7 @@ lib /machine:x86 /def:..\..\fftw-3.3-dll32\libfftw3-3.def /out:$(IntDir)libfftw3 - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3-3.lib @@ -345,7 +345,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3-3.lib @@ -498,7 +498,7 @@ lib /machine:x86 /def:..\..\fftw-3.3-dll32\libfftw3-3.def /out:$(IntDir)libfftw3 - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3-3.lib @@ -547,7 +547,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3 - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3-3.lib @@ -654,7 +654,7 @@ lib /machine:x86 /def:..\..\fftw-3.3-dll32\libfftw3-3.def /out:$(IntDir)libfftw3 - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3-3.lib @@ -765,7 +765,7 @@ lib /machine:x86 /def:..\..\fftw-3.3-dll32\libfftw3-3.def /out:$(IntDir)libfftw3 - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3-3.lib diff --git a/visualc/vngspice.vcxproj b/visualc/vngspice.vcxproj index 3d14b4ed2..998225ba1 100644 --- a/visualc/vngspice.vcxproj +++ b/visualc/vngspice.vcxproj @@ -302,7 +302,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj @@ -352,7 +352,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj @@ -504,7 +504,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj @@ -554,7 +554,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj @@ -661,7 +661,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj @@ -772,7 +772,7 @@ - force recompilation of conf.c with actual date + force recompilation of conf.c with current date if exist $(IntDir)conf.obj del $(IntDir)conf.obj From f548e8400a22832d13a52d2bdf83dd72666f7549 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 30 Jul 2023 14:44:07 +0200 Subject: [PATCH 21/22] eprvcd [-a] [-t timescale] node node ... timescale is now given by minimum 1fs, maximum 1s. --- src/xspice/evt/evtprint.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/xspice/evt/evtprint.c b/src/xspice/evt/evtprint.c index ac97fcde3..534cad422 100644 --- a/src/xspice/evt/evtprint.c +++ b/src/xspice/evt/evtprint.c @@ -610,16 +610,22 @@ EVTprintvcd(wordlist *wl) char *value; /* Check for the "-a" option (output analog values at timesteps) - * and "-t nn": specifies the VCD timestep as a power of ten. - */ + * and "-t nn": specifies the VCD timestep with range 1fs to 1s */ while (wl && wl->wl_word[0] == '-') { if (wl->wl_word[1] == 'a' && !wl->wl_word[2]) { timesteps = 1; } else if (wl->wl_word[1] == 't' && !wl->wl_word[2]) { wl = wl->wl_next; - if (wl) - tspower = atoi(wl->wl_word); + if (wl) { + double input; + int error = 0; + char* inword = wl->wl_word; + input = INPevaluate(&inword, &error, 0); + tspower = (int)ceil(- 1. * log10(input)); + if (tspower < 0) + tspower = 0; + } else break; } else { From 4246b3112653a7f26f6d3bd1b89031178f8db7df Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sun, 30 Jul 2023 16:01:15 +0200 Subject: [PATCH 22/22] Revert "Marcel Hendrix's fix for Bug #324 -" This reverts commit d3a8634afe172bbe34ffeed6e05d4fe5091189c5. --- src/frontend/inpcom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index ddbd0670f..1726feed6 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -3199,7 +3199,7 @@ static void inp_stripcomments_line(char *s, bool cs) /* look for comments */ while ((c = *d) != '\0') { d++; - if (!cs && *d == ';') { + if (*d == ';') { break; } /* outside of .control section, and not in PS mode */