fixed memory leaks
This commit is contained in:
parent
e50dee9ccc
commit
13d55715fc
|
|
@ -497,18 +497,24 @@ com_measure_when(
|
|||
}
|
||||
|
||||
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 (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
|
||||
value2 = d2->v_realdata[i];
|
||||
value2 = d2->v_realdata[i2];
|
||||
} else if (sp_check) {
|
||||
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
|
||||
value2 = d2->v_realdata[i];
|
||||
value2 = d2->v_realdata[i2];
|
||||
} else {
|
||||
value2 = d2->v_realdata[i];
|
||||
value2 = d2->v_realdata[i2];
|
||||
}
|
||||
} else {
|
||||
value2 = NAN;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@ extern bool ft_batchmode;
|
|||
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:
|
||||
meas command inside .control ... .endc loop or manually entered.
|
||||
meas has to be followed by the standard tokens (see measure_extract_variables()).
|
||||
|
|
@ -44,6 +48,7 @@ com_meas(wordlist *wl)
|
|||
wordlist *wl_index;
|
||||
struct dvec *d;
|
||||
int err = 0;
|
||||
double subst_val;
|
||||
|
||||
int fail;
|
||||
double result = 0;
|
||||
|
|
@ -76,7 +81,8 @@ com_meas(wordlist *wl)
|
|||
vec_found = wl_index->wl_word;
|
||||
/* token may be already a value, maybe 'LAST', which we have to keep, or maybe a vector */
|
||||
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 (err) {
|
||||
/* 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)) {
|
||||
/* get its value */
|
||||
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) {
|
||||
vec_found = equal_ptr + 1;
|
||||
if (!cieq(vec_found, "LAST")) {
|
||||
INPevaluate(&vec_found, &err, 1);
|
||||
subst_val = INPevaluate(&vec_found, &err, 1);
|
||||
if (err) {
|
||||
d = vec_get(vec_found);
|
||||
/* 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]);
|
||||
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 {
|
||||
|
|
|
|||
|
|
@ -143,6 +143,14 @@ struct CKTcircuit {
|
|||
* opt-out. */
|
||||
int CKTosdiStepReject;
|
||||
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
|
||||
* sanitize_jacobian during CKTload. When > 0, the model evaluation
|
||||
* 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
|
||||
* convergence (residual-vector check); revert to
|
||||
* SPICE3 solution-only behaviour. */
|
||||
OPT_NOSTATERESTORE, /* `.option nostaterestore` opts out of the dctran
|
||||
* failed-attempt device-state restore. */
|
||||
OPT_EQNS,
|
||||
OPT_REORDTIME,
|
||||
OPT_METHOD,
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ struct TSKtask {
|
|||
unsigned int TSKnoDtClear:1; /* `.option nodtclear` disables the
|
||||
* small-dt CKTnoncon clear in
|
||||
* 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 TSKbadMos3:1; /* flag for MOS3 models */
|
||||
unsigned int TSKkeepOpInfo:1; /* flag for small signal analyses */
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ NIiter(CKTcircuit *ckt, int maxIter)
|
|||
ckt->CKTrhsOld[0] = 0;
|
||||
|
||||
/* 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
|
||||
* the default behaviour of Spectre/HSPICE DEVlimvds-style
|
||||
* 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
|
||||
* 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 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
|
||||
* inside descr->eval() — this simulator-side limiter then
|
||||
* 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;
|
||||
/* Compute current iteration's max|Δv|. Needed both
|
||||
* 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 = &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 */
|
||||
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->CKTosdiStepRejectOff = task->TSKnoOsdiStepReject;
|
||||
ckt->CKTdtClearOff = task->TSKnoDtClear;
|
||||
ckt->CKTstateRestoreOff = task->TSKnoStateRestore;
|
||||
ckt->CKTosdiVlim = task->TSKosdiVlim;
|
||||
ckt->CKTosdiVlimVds = task->TSKosdiVlimVds;
|
||||
ckt->CKTosdiVlimVgs = task->TSKosdiVlimVgs;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ CKTsetOpt(CKTcircuit *ckt, JOB *anal, int opt, IFvalue *val)
|
|||
case OPT_NODTCLEAR:
|
||||
task->TSKnoDtClear = (val->iValue != 0);
|
||||
break;
|
||||
case OPT_NOSTATERESTORE:
|
||||
task->TSKnoStateRestore = (val->iValue != 0);
|
||||
break;
|
||||
case OPT_GMIN:
|
||||
task->TSKgmin = val->rValue;
|
||||
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" },
|
||||
{ "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" },
|
||||
{ "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" },
|
||||
{ "gshunt", OPT_GSHUNT,IF_SET|IF_REAL,"Shunt conductance" },
|
||||
{ "reltol", OPT_RELTOL,IF_SET|IF_REAL ,"Relative error tolerence"},
|
||||
|
|
|
|||
|
|
@ -773,8 +773,14 @@ resume:
|
|||
* retries) until the state explodes and dt collapses to
|
||||
* delmin. Re-prime the working state from the last ACCEPTED
|
||||
* point so every retry starts from physical values, exactly
|
||||
* like a first attempt does. */
|
||||
if (ckt->CKTstate0 && ckt->CKTstate1)
|
||||
* like a first attempt does.
|
||||
*
|
||||
* 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,
|
||||
(size_t) ckt->CKTnumStates * sizeof(double));
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ INPevaluate(char **line, int *error, int gobble)
|
|||
char *tmpline;
|
||||
|
||||
/* 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;
|
||||
|
||||
if (gobble) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue