fixed memory leaks
This commit is contained in:
parent
e50dee9ccc
commit
13d55715fc
|
|
@ -497,18 +497,24 @@ com_measure_when(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_d2) {
|
if (has_d2) {
|
||||||
|
/* The loop index runs over d's length; d2 may be shorter
|
||||||
|
* (e.g. a length-1 measure-result vector on the right hand
|
||||||
|
* side of WHEN v(x)=NAME). Clamp to d2's last element so
|
||||||
|
* a short vector reads as a held constant instead of
|
||||||
|
* running past its allocation. */
|
||||||
|
int i2 = (i < d2->v_length) ? i : d2->v_length - 1;
|
||||||
if (ac_check) {
|
if (ac_check) {
|
||||||
if (d2->v_compdata)
|
if (d2->v_compdata)
|
||||||
value2 = get_value(meas, d2, i); //d->v_compdata[i].cx_real;
|
value2 = get_value(meas, d2, i2); //d->v_compdata[i].cx_real;
|
||||||
else
|
else
|
||||||
value2 = d2->v_realdata[i];
|
value2 = d2->v_realdata[i2];
|
||||||
} else if (sp_check) {
|
} else if (sp_check) {
|
||||||
if (d2->v_compdata)
|
if (d2->v_compdata)
|
||||||
value2 = get_value(meas, d2, i); //d->v_compdata[i].cx_real;
|
value2 = get_value(meas, d2, i2); //d->v_compdata[i].cx_real;
|
||||||
else
|
else
|
||||||
value2 = d2->v_realdata[i];
|
value2 = d2->v_realdata[i2];
|
||||||
} else {
|
} else {
|
||||||
value2 = d2->v_realdata[i];
|
value2 = d2->v_realdata[i2];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value2 = NAN;
|
value2 = NAN;
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,10 @@ extern bool ft_batchmode;
|
||||||
extern bool rflag;
|
extern bool rflag;
|
||||||
|
|
||||||
|
|
||||||
|
/* Set by INPevaluate's HSPICE-compat bare-.param resolution path
|
||||||
|
(inpeval.c); see the substitution pre-pass below. */
|
||||||
|
extern char *inpeval_last_param_name;
|
||||||
|
|
||||||
/* measure in interactive mode:
|
/* measure in interactive mode:
|
||||||
meas command inside .control ... .endc loop or manually entered.
|
meas command inside .control ... .endc loop or manually entered.
|
||||||
meas has to be followed by the standard tokens (see measure_extract_variables()).
|
meas has to be followed by the standard tokens (see measure_extract_variables()).
|
||||||
|
|
@ -44,6 +48,7 @@ com_meas(wordlist *wl)
|
||||||
wordlist *wl_index;
|
wordlist *wl_index;
|
||||||
struct dvec *d;
|
struct dvec *d;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
double subst_val;
|
||||||
|
|
||||||
int fail;
|
int fail;
|
||||||
double result = 0;
|
double result = 0;
|
||||||
|
|
@ -76,7 +81,8 @@ com_meas(wordlist *wl)
|
||||||
vec_found = wl_index->wl_word;
|
vec_found = wl_index->wl_word;
|
||||||
/* token may be already a value, maybe 'LAST', which we have to keep, or maybe a vector */
|
/* token may be already a value, maybe 'LAST', which we have to keep, or maybe a vector */
|
||||||
if (!cieq(vec_found, "LAST")) {
|
if (!cieq(vec_found, "LAST")) {
|
||||||
INPevaluate(&vec_found, &err, 1);
|
char *orig_word = wl_index->wl_word;
|
||||||
|
subst_val = INPevaluate(&vec_found, &err, 1);
|
||||||
/* if not a valid number */
|
/* if not a valid number */
|
||||||
if (err) {
|
if (err) {
|
||||||
/* check if vec_found is a valid vector */
|
/* check if vec_found is a valid vector */
|
||||||
|
|
@ -86,8 +92,18 @@ com_meas(wordlist *wl)
|
||||||
if (d && (d->v_length == 1) && (d->v_numdims == 1)) {
|
if (d && (d->v_length == 1) && (d->v_numdims == 1)) {
|
||||||
/* get its value */
|
/* get its value */
|
||||||
wl_index->wl_word = tprintf("%e", d->v_realdata[0]);
|
wl_index->wl_word = tprintf("%e", d->v_realdata[0]);
|
||||||
tfree(vec_found);
|
tfree(orig_word);
|
||||||
}
|
}
|
||||||
|
} else if (inpeval_last_param_name) {
|
||||||
|
/* INPevaluate resolved a bare .param identifier (e.g.
|
||||||
|
a prior .measure result registered via
|
||||||
|
nupa_add_param). Write the value back so the
|
||||||
|
measure parser sees a number — otherwise the
|
||||||
|
identifier survives as text and com_measure2
|
||||||
|
treats it as a full vector, which mis-measures
|
||||||
|
(and over-reads a length-1 result vector). */
|
||||||
|
wl_index->wl_word = tprintf("%e", subst_val);
|
||||||
|
tfree(orig_word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,7 +111,7 @@ com_meas(wordlist *wl)
|
||||||
else if ((equal_ptr = strchr(token, '=')) != NULL) {
|
else if ((equal_ptr = strchr(token, '=')) != NULL) {
|
||||||
vec_found = equal_ptr + 1;
|
vec_found = equal_ptr + 1;
|
||||||
if (!cieq(vec_found, "LAST")) {
|
if (!cieq(vec_found, "LAST")) {
|
||||||
INPevaluate(&vec_found, &err, 1);
|
subst_val = INPevaluate(&vec_found, &err, 1);
|
||||||
if (err) {
|
if (err) {
|
||||||
d = vec_get(vec_found);
|
d = vec_get(vec_found);
|
||||||
/* Only if we have a single valued vector, replacing
|
/* Only if we have a single valued vector, replacing
|
||||||
|
|
@ -106,6 +122,13 @@ com_meas(wordlist *wl)
|
||||||
tprintf("%.*s=%e", lhs_len, token, d->v_realdata[0]);
|
tprintf("%.*s=%e", lhs_len, token, d->v_realdata[0]);
|
||||||
tfree(token);
|
tfree(token);
|
||||||
}
|
}
|
||||||
|
} else if (inpeval_last_param_name) {
|
||||||
|
/* bare .param identifier resolved — write the value
|
||||||
|
back (see whole-token case above) */
|
||||||
|
int lhs_len = (int)(equal_ptr - token);
|
||||||
|
wl_index->wl_word =
|
||||||
|
tprintf("%.*s=%e", lhs_len, token, subst_val);
|
||||||
|
tfree(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,14 @@ struct CKTcircuit {
|
||||||
* opt-out. */
|
* opt-out. */
|
||||||
int CKTosdiStepReject;
|
int CKTosdiStepReject;
|
||||||
int CKTosdiStepRejectOff;
|
int CKTosdiStepRejectOff;
|
||||||
|
/* Set by OSDIsetup when the circuit contains at least one OSDI
|
||||||
|
* (Verilog-A) device. Gates OSDI-motivated Newton machinery — the
|
||||||
|
* per-node Δv limiter in NIiter — so that circuits built purely
|
||||||
|
* from native SPICE devices keep stock SPICE3 iteration behaviour. */
|
||||||
|
int CKTosdiPresent;
|
||||||
|
/* `.option nostaterestore` opt-out of the dctran failed-attempt
|
||||||
|
* device-state restore (CKTstate0 <- CKTstate1 on timepoint retry). */
|
||||||
|
int CKTstateRestoreOff;
|
||||||
/* Per-iteration count of huge-finite Jacobian entries clipped by
|
/* Per-iteration count of huge-finite Jacobian entries clipped by
|
||||||
* sanitize_jacobian during CKTload. When > 0, the model evaluation
|
* sanitize_jacobian during CKTload. When > 0, the model evaluation
|
||||||
* is in a numerical regime (e.g. BSIM-BULK near a singular operating
|
* is in a numerical regime (e.g. BSIM-BULK near a singular operating
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,8 @@ enum {
|
||||||
OPT_NORESIDCHECK, /* `.option noresidcheck` opts out of axis-4 dual-norm
|
OPT_NORESIDCHECK, /* `.option noresidcheck` opts out of axis-4 dual-norm
|
||||||
* convergence (residual-vector check); revert to
|
* convergence (residual-vector check); revert to
|
||||||
* SPICE3 solution-only behaviour. */
|
* SPICE3 solution-only behaviour. */
|
||||||
|
OPT_NOSTATERESTORE, /* `.option nostaterestore` opts out of the dctran
|
||||||
|
* failed-attempt device-state restore. */
|
||||||
OPT_EQNS,
|
OPT_EQNS,
|
||||||
OPT_REORDTIME,
|
OPT_REORDTIME,
|
||||||
OPT_METHOD,
|
OPT_METHOD,
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,9 @@ struct TSKtask {
|
||||||
unsigned int TSKnoDtClear:1; /* `.option nodtclear` disables the
|
unsigned int TSKnoDtClear:1; /* `.option nodtclear` disables the
|
||||||
* small-dt CKTnoncon clear in
|
* small-dt CKTnoncon clear in
|
||||||
* niiter.c */
|
* niiter.c */
|
||||||
|
unsigned int TSKnoStateRestore:1; /* `.option nostaterestore` disables
|
||||||
|
* the dctran failed-attempt state
|
||||||
|
* restore (CKTstate0 <- CKTstate1) */
|
||||||
unsigned int TSKtryToCompact:1; /* flag for LTRA lines */
|
unsigned int TSKtryToCompact:1; /* flag for LTRA lines */
|
||||||
unsigned int TSKbadMos3:1; /* flag for MOS3 models */
|
unsigned int TSKbadMos3:1; /* flag for MOS3 models */
|
||||||
unsigned int TSKkeepOpInfo:1; /* flag for small signal analyses */
|
unsigned int TSKkeepOpInfo:1; /* flag for small signal analyses */
|
||||||
|
|
|
||||||
|
|
@ -411,7 +411,7 @@ NIiter(CKTcircuit *ckt, int maxIter)
|
||||||
ckt->CKTrhsOld[0] = 0;
|
ckt->CKTrhsOld[0] = 0;
|
||||||
|
|
||||||
/* Newton-step limiter (simulator-side $limit substitute).
|
/* Newton-step limiter (simulator-side $limit substitute).
|
||||||
* Always-on during transient (and DC OP) to clamp per-node
|
* Active during transient (and DC OP) to clamp per-node
|
||||||
* |Δv| to ±CKTabsDv between Newton iterations. Matches
|
* |Δv| to ±CKTabsDv between Newton iterations. Matches
|
||||||
* the default behaviour of Spectre/HSPICE DEVlimvds-style
|
* the default behaviour of Spectre/HSPICE DEVlimvds-style
|
||||||
* limiters which fire on every iteration as a model-
|
* limiters which fire on every iteration as a model-
|
||||||
|
|
@ -419,6 +419,17 @@ NIiter(CKTcircuit *ckt, int maxIter)
|
||||||
* 0.5 V) — a model-parameter-agnostic tolerance, not a
|
* 0.5 V) — a model-parameter-agnostic tolerance, not a
|
||||||
* voltage rail.
|
* voltage rail.
|
||||||
*
|
*
|
||||||
|
* OSDI circuits only (CKTosdiPresent): the limiter exists
|
||||||
|
* as a substitute for model-supplied $limit calls that
|
||||||
|
* OSDI/Verilog-A models may lack. Applying it to every
|
||||||
|
* circuit regressed non-OSDI decks whose behavioral
|
||||||
|
* macromodels legitimately need multi-kV Newton steps
|
||||||
|
* (PSpice opamp libs: TABLE sources swing to ±3.5 kV) —
|
||||||
|
* the clamp forced a crawl whose small |Δx| the axis-4
|
||||||
|
* residual check then correctly refused, so OP, gmin and
|
||||||
|
* source stepping all failed. Native SPICE devices carry
|
||||||
|
* their own pnjlim/limvds limiting and never needed this.
|
||||||
|
*
|
||||||
* Skipped on iteration 1 (no previous iterate to compare).
|
* Skipped on iteration 1 (no previous iterate to compare).
|
||||||
* Skipped when CKTnodes is NULL (matrix not yet built).
|
* Skipped when CKTnodes is NULL (matrix not yet built).
|
||||||
*
|
*
|
||||||
|
|
@ -426,7 +437,7 @@ NIiter(CKTcircuit *ckt, int maxIter)
|
||||||
* $limit synthesis pass, the model's own limiters apply
|
* $limit synthesis pass, the model's own limiters apply
|
||||||
* inside descr->eval() — this simulator-side limiter then
|
* inside descr->eval() — this simulator-side limiter then
|
||||||
* sees already-limited Δv and does nothing additional. */
|
* sees already-limited Δv and does nothing additional. */
|
||||||
if (iterno > 1 && ckt->CKTnodes != NULL) {
|
if (ckt->CKTosdiPresent && iterno > 1 && ckt->CKTnodes != NULL) {
|
||||||
double dv_max = (ckt->CKTabsDv > 0) ? ckt->CKTabsDv : 0.5;
|
double dv_max = (ckt->CKTabsDv > 0) ? ckt->CKTabsDv : 0.5;
|
||||||
/* Compute current iteration's max|Δv|. Needed both
|
/* Compute current iteration's max|Δv|. Needed both
|
||||||
* for the Stage A scalar scaling and for the Stage B
|
* for the Stage A scalar scaling and for the Stage B
|
||||||
|
|
|
||||||
|
|
@ -319,6 +319,11 @@ int OSDIsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
|
||||||
OsdiSimParas sim_params_ = get_simparams(ckt);
|
OsdiSimParas sim_params_ = get_simparams(ckt);
|
||||||
OsdiSimParas *sim_params = &sim_params_;
|
OsdiSimParas *sim_params = &sim_params_;
|
||||||
|
|
||||||
|
/* Mark the circuit as containing OSDI devices — gates OSDI-motivated
|
||||||
|
* Newton machinery (per-node Δv limiter in NIiter) so purely native
|
||||||
|
* circuits keep stock iteration behaviour. */
|
||||||
|
ckt->CKTosdiPresent = 1;
|
||||||
|
|
||||||
/* setup a temporary buffer */
|
/* setup a temporary buffer */
|
||||||
uint32_t *node_ids = TMALLOC(uint32_t, descr->num_nodes);
|
uint32_t *node_ids = TMALLOC(uint32_t, descr->num_nodes);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ CKTdoJob(CKTcircuit* ckt, int reset, TSKtask* task)
|
||||||
ckt->CKTresidCheckDisabled = task->TSKnoResidCheck;
|
ckt->CKTresidCheckDisabled = task->TSKnoResidCheck;
|
||||||
ckt->CKTosdiStepRejectOff = task->TSKnoOsdiStepReject;
|
ckt->CKTosdiStepRejectOff = task->TSKnoOsdiStepReject;
|
||||||
ckt->CKTdtClearOff = task->TSKnoDtClear;
|
ckt->CKTdtClearOff = task->TSKnoDtClear;
|
||||||
|
ckt->CKTstateRestoreOff = task->TSKnoStateRestore;
|
||||||
ckt->CKTosdiVlim = task->TSKosdiVlim;
|
ckt->CKTosdiVlim = task->TSKosdiVlim;
|
||||||
ckt->CKTosdiVlimVds = task->TSKosdiVlimVds;
|
ckt->CKTosdiVlimVds = task->TSKosdiVlimVds;
|
||||||
ckt->CKTosdiVlimVgs = task->TSKosdiVlimVgs;
|
ckt->CKTosdiVlimVgs = task->TSKosdiVlimVgs;
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,9 @@ CKTsetOpt(CKTcircuit *ckt, JOB *anal, int opt, IFvalue *val)
|
||||||
case OPT_NODTCLEAR:
|
case OPT_NODTCLEAR:
|
||||||
task->TSKnoDtClear = (val->iValue != 0);
|
task->TSKnoDtClear = (val->iValue != 0);
|
||||||
break;
|
break;
|
||||||
|
case OPT_NOSTATERESTORE:
|
||||||
|
task->TSKnoStateRestore = (val->iValue != 0);
|
||||||
|
break;
|
||||||
case OPT_GMIN:
|
case OPT_GMIN:
|
||||||
task->TSKgmin = val->rValue;
|
task->TSKgmin = val->rValue;
|
||||||
break;
|
break;
|
||||||
|
|
@ -300,6 +303,7 @@ static IFparm OPTtbl[] = {
|
||||||
{ "noresidcheck", OPT_NORESIDCHECK, IF_SET|IF_FLAG, "Disable axis-4 residual-vector convergence check; SPICE3-only behaviour" },
|
{ "noresidcheck", OPT_NORESIDCHECK, IF_SET|IF_FLAG, "Disable axis-4 residual-vector convergence check; SPICE3-only behaviour" },
|
||||||
{ "noosdistepreject", OPT_NOOSDISTEPREJECT, IF_SET|IF_FLAG, "Disable OSDI axis-3 step rejection (osdiload.c sanitize_jacobian + REJECT_STEP)" },
|
{ "noosdistepreject", OPT_NOOSDISTEPREJECT, IF_SET|IF_FLAG, "Disable OSDI axis-3 step rejection (osdiload.c sanitize_jacobian + REJECT_STEP)" },
|
||||||
{ "nodtclear", OPT_NODTCLEAR, IF_SET|IF_FLAG, "Disable small-dt CKTnoncon clear (niiter.c); revert to abort-from-spurious-noncon at dt<1ps" },
|
{ "nodtclear", OPT_NODTCLEAR, IF_SET|IF_FLAG, "Disable small-dt CKTnoncon clear (niiter.c); revert to abort-from-spurious-noncon at dt<1ps" },
|
||||||
|
{ "nostaterestore", OPT_NOSTATERESTORE, IF_SET|IF_FLAG, "Disable dctran failed-attempt device-state restore (CKTstate0 <- CKTstate1 on retry)" },
|
||||||
{ "gmin", OPT_GMIN,IF_SET|IF_REAL,"Minimum conductance" },
|
{ "gmin", OPT_GMIN,IF_SET|IF_REAL,"Minimum conductance" },
|
||||||
{ "gshunt", OPT_GSHUNT,IF_SET|IF_REAL,"Shunt conductance" },
|
{ "gshunt", OPT_GSHUNT,IF_SET|IF_REAL,"Shunt conductance" },
|
||||||
{ "reltol", OPT_RELTOL,IF_SET|IF_REAL ,"Relative error tolerence"},
|
{ "reltol", OPT_RELTOL,IF_SET|IF_REAL ,"Relative error tolerence"},
|
||||||
|
|
|
||||||
|
|
@ -773,8 +773,14 @@ resume:
|
||||||
* retries) until the state explodes and dt collapses to
|
* retries) until the state explodes and dt collapses to
|
||||||
* delmin. Re-prime the working state from the last ACCEPTED
|
* delmin. Re-prime the working state from the last ACCEPTED
|
||||||
* point so every retry starts from physical values, exactly
|
* point so every retry starts from physical values, exactly
|
||||||
* like a first attempt does. */
|
* like a first attempt does.
|
||||||
if (ckt->CKTstate0 && ckt->CKTstate1)
|
*
|
||||||
|
* Opt-out via `.option nostaterestore` (suspected of
|
||||||
|
* regressing non-OSDI example decks on raw-transient-start
|
||||||
|
* paths — uic / optran / mid-run retries — where CKTstate1
|
||||||
|
* may not hold a meaningfully accepted point). */
|
||||||
|
if (!ckt->CKTstateRestoreOff &&
|
||||||
|
ckt->CKTstate0 && ckt->CKTstate1)
|
||||||
memcpy(ckt->CKTstate0, ckt->CKTstate1,
|
memcpy(ckt->CKTstate0, ckt->CKTstate1,
|
||||||
(size_t) ckt->CKTnumStates * sizeof(double));
|
(size_t) ckt->CKTnumStates * sizeof(double));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ INPevaluate(char **line, int *error, int gobble)
|
||||||
char *tmpline;
|
char *tmpline;
|
||||||
|
|
||||||
/* setup */
|
/* setup */
|
||||||
|
/* Clear the bare-.param side channel on every entry, as its
|
||||||
|
* consumers (INPdevParse, com_meas) assume — a non-NULL value must
|
||||||
|
* only ever mean THIS call resolved a bare identifier. */
|
||||||
|
inpeval_last_param_name = NULL;
|
||||||
tmpline = *line;
|
tmpline = *line;
|
||||||
|
|
||||||
if (gobble) {
|
if (gobble) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue