Updated osdiregistry.c and osdi.h to hopefully make OSDI files from all current, known flavors run without crashing
This commit is contained in:
parent
d429f24bb3
commit
17ea132b3a
|
|
@ -37,7 +37,7 @@
|
|||
#define JACOBIAN_ENTRY_REACT_CONST 2
|
||||
#define JACOBIAN_ENTRY_RESIST 4
|
||||
#define JACOBIAN_ENTRY_REACT 8
|
||||
/* OSDI v0.5 (2C AC delay) — entry has a delay-coupling part loaded
|
||||
/* OpenVA OSDI — entry has a delay-coupling part loaded
|
||||
* x e^{-jw*td} during AC (touches both real and imag matrix parts). */
|
||||
#define JACOBIAN_ENTRY_DELAY 16
|
||||
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
#define EVAL_RET_FLAG_FATAL 2
|
||||
#define EVAL_RET_FLAG_FINISH 4
|
||||
#define EVAL_RET_FLAG_STOP 8
|
||||
/* OSDI v0.5 axis-3 step rejection. Model raises this when it detects
|
||||
/* OpenVA OSDI step rejection. Model raises this when it detects
|
||||
* an ill-conditioned regime (degenerate Jacobian, predicted-voltage
|
||||
* out of validity, internal-node blow-up). ngspice cuts the transient
|
||||
* step and retries with smaller delta instead of iterating fruitlessly
|
||||
|
|
@ -72,8 +72,7 @@
|
|||
* step-rejection semantics when the model itself doesn't set the flag. */
|
||||
#define EVAL_RET_FLAG_REJECT_STEP 16
|
||||
|
||||
/* OSDI v0.5 axis-4 event-driven analog operators. See
|
||||
* OSDI_0_5_DESIGN.md in the OpenVA tree for the full design.
|
||||
/* OpenVA OSDI event-driven analog operators.
|
||||
*
|
||||
* EVENT — the model wrote one or more entries into the
|
||||
* pending_events array of OsdiSimInfo. The simulator
|
||||
|
|
@ -84,14 +83,11 @@
|
|||
* track them across consecutive accepted evals and
|
||||
* bisect on sign-flip per the corresponding
|
||||
* OsdiCrossExprMeta direction.
|
||||
*
|
||||
* S3a (this commit) defines the bits; S3b implements the runtime
|
||||
* loop logic that acts on them.
|
||||
*/
|
||||
#define EVAL_RET_FLAG_EVENT 32
|
||||
#define EVAL_RET_FLAG_CROSS 64
|
||||
|
||||
/* OSDI v0.5 OsdiEventKind discriminants (§2.6 of the design doc).
|
||||
/* OpenVA OSDI OsdiEventKind discriminants.
|
||||
* Stored in the `kind` field of OsdiEventRequest (filled by the
|
||||
* model) and OsdiEventSlotMeta (defined by OpenVA at compile time)
|
||||
* to tell the simulator which kind of analog-block event-control
|
||||
|
|
@ -128,13 +124,12 @@ typedef struct OsdiSimParas {
|
|||
char **vals_str;
|
||||
}OsdiSimParas;
|
||||
|
||||
/* OSDI v0.5 — event request slot in OsdiSimInfo.pending_events.
|
||||
/* OpenVA OSDI — event request slot in OsdiSimInfo.pending_events.
|
||||
*
|
||||
* The model writes one of these per eval() per active timer/event
|
||||
* body that wants the simulator to advance to a specific future
|
||||
* time. The simulator consumes the slots, schedules the requests,
|
||||
* and zeros at_time before the next eval to indicate "consumed".
|
||||
* See OSDI_0_5_DESIGN.md §2.5 for the layout and lifecycle.
|
||||
*/
|
||||
typedef struct OsdiEventRequest {
|
||||
double at_time; /* zero / NaN = no request from this slot */
|
||||
|
|
@ -142,7 +137,7 @@ typedef struct OsdiEventRequest {
|
|||
uint32_t kind; /* OSDI_EVENT_KIND_* */
|
||||
}OsdiEventRequest;
|
||||
|
||||
/* OSDI v0.5 — per-cross-expression metadata in OsdiDescriptor.
|
||||
/* OpenVA OSDI — per-cross-expression metadata in OsdiDescriptor.
|
||||
*
|
||||
* One entry per `@(cross(...))` body the model declares. OpenVA
|
||||
* fills this at compile time from the body's explicit arguments
|
||||
|
|
@ -158,7 +153,7 @@ typedef struct OsdiCrossExprMeta {
|
|||
* cross is bracketed */
|
||||
}OsdiCrossExprMeta;
|
||||
|
||||
/* OSDI v0.5 — per-event-slot metadata in OsdiDescriptor.
|
||||
/* OpenVA OSDI — per-event-slot metadata in OsdiDescriptor.
|
||||
*
|
||||
* One entry per `@(cross)` / `@(timer)` / `@(initial_step)` /
|
||||
* `@(final_step)` body. `kind` is the OSDI_EVENT_KIND_*
|
||||
|
|
@ -177,7 +172,7 @@ typedef struct OsdiSimInfo {
|
|||
double *prev_state;
|
||||
double *next_state;
|
||||
uint32_t flags;
|
||||
/* OSDI v0.5 — see OSDI_0_5_DESIGN.md §2.3.
|
||||
/* OpenVA OSDI event-driven state.
|
||||
* Allocated per-instance by setup_instance (sized from the
|
||||
* descriptor's num_cross_exprs / num_event_slots). Zero-init
|
||||
* is safe and represents "no event-driven state for this
|
||||
|
|
@ -190,7 +185,7 @@ typedef struct OsdiSimInfo {
|
|||
uint32_t at_scheduled_event; /* bool, widened to u32 for ABI
|
||||
* stability across compilers */
|
||||
uint32_t fired_event_id;
|
||||
/* S3c — when at_scheduled_event != 0, this carries the true
|
||||
/* When at_scheduled_event != 0, this carries the true
|
||||
* scheduled t_event the simulator originally computed (e.g.
|
||||
* the linear-interpolated cross-expr crossing time). The
|
||||
* simulator can't always land EXACTLY on t_event, so it fires
|
||||
|
|
@ -199,19 +194,19 @@ typedef struct OsdiSimInfo {
|
|||
* last_crossing lowering reads THIS field instead of abstime
|
||||
* to latch the correct crossing time. */
|
||||
double scheduled_event_time;
|
||||
/* OSDI v0.5 — set to 1 by the simulator on the eval(s) of the final
|
||||
/* OpenVA OSDI — set to 1 by the simulator on the eval(s) of the final
|
||||
* transient timepoint (CKTtime == CKTfinalTime), 0 otherwise. Lets a
|
||||
* model gate an `@(final_step)` body. Appended at the struct tail so
|
||||
* older .osdi binaries (which never read it) stay ABI-compatible. */
|
||||
uint32_t at_final_step;
|
||||
/* OSDI v0.5 (axis 2) — the current Newton iteration index (1-based,
|
||||
/* OpenVA OSDI — the current Newton iteration index (1-based,
|
||||
* per-Newton-solve; resets each NIiter call), forwarded from
|
||||
* ckt->CKTosdiNewtonIter. Lets a model / compiler-synthesised $limit
|
||||
* make its damping iteration-aware (tighten as the count climbs to
|
||||
* break oscillation). Appended at the struct tail so older .osdi
|
||||
* binaries (which never read it) stay ABI-compatible. */
|
||||
uint32_t newton_iter;
|
||||
/* OSDI v0.5 (2C — absdelay exact transport). Tail-appended, ABI-safe.
|
||||
/* OpenVA OSDI (absdelay exact transport). Tail-appended, ABI-safe.
|
||||
* delay_input : per-site scratch (sized num_delay_sites); the model
|
||||
* writes its current input x there each eval. The
|
||||
* simulator pushes (abstime, delay_input[site]) into
|
||||
|
|
@ -335,12 +330,12 @@ typedef struct OsdiDescriptor {
|
|||
void (*load_jacobian_react)(void *inst, void* model, double alpha);
|
||||
void (*load_jacobian_tran)(void *inst, void* model, double alpha);
|
||||
|
||||
/* OSDI v0.4 fields — present in the descriptor produced by
|
||||
* OpenVA / openvaf-reloaded for some time but not previously
|
||||
* declared in this header (ngspice didn't need them). Added
|
||||
* now because the OSDI v0.5 fields below sit after them and
|
||||
* the C struct must mirror the binary's layout to compute
|
||||
* the right offsets. */
|
||||
/* OpenVAF-Reloaded OSDI fields — present in the descriptor
|
||||
* produced by OpenVAF-Reloaded and OpenVA but not previously
|
||||
* declared in this header (ngspice didn't need them). Declared
|
||||
* because the OpenVA OSDI fields below sit after them and the
|
||||
* C struct must mirror the binary's layout to compute the
|
||||
* right offsets. */
|
||||
uint32_t (*given_flag_model)(void *model, uint32_t id);
|
||||
uint32_t (*given_flag_instance)(void *inst, uint32_t id);
|
||||
uint32_t num_resistive_jacobian_entries;
|
||||
|
|
@ -352,29 +347,30 @@ typedef struct OsdiDescriptor {
|
|||
void (*load_jacobian_with_offset_resist)(void *inst, void* model, size_t offset);
|
||||
void (*load_jacobian_with_offset_react)(void *inst, void* model, size_t offset);
|
||||
|
||||
/* OSDI v0.5 — event-driven analog operators (§2.4 of the design
|
||||
* doc). S3a (this commit) declares the field layout; S3b uses
|
||||
* `num_cross_exprs` / `num_event_slots` to size the per-instance
|
||||
* SimInfo arrays and walks the metadata arrays to drive the
|
||||
* bisection state machine. Models that don't use cross/timer
|
||||
* features emit zero for the counts and NULL for the metadata
|
||||
* pointers, so older non-0.5 binaries (where these fields don't
|
||||
* exist) read as zero via the OSDI_DESCRIPTOR_SIZE bounds-check
|
||||
* the loader already enforces. */
|
||||
/* OpenVA OSDI — event-driven analog operators. The simulator
|
||||
* uses `num_cross_exprs` / `num_event_slots` to size the
|
||||
* per-instance SimInfo arrays and walks the metadata arrays to
|
||||
* drive the bisection state machine. Models that don't use
|
||||
* cross/timer features emit zero for the counts and NULL for the
|
||||
* metadata pointers. Older binaries (OpenVAF / OpenVAF-Reloaded,
|
||||
* where these fields don't exist) also read as zero: the loader
|
||||
* copies each descriptor into a zeroed full-size struct at load
|
||||
* time (osdiregistry.c), so all tail fields beyond the file's
|
||||
* real descriptor are guaranteed 0. */
|
||||
uint32_t num_cross_exprs;
|
||||
OsdiCrossExprMeta *cross_expr_metadata;
|
||||
uint32_t num_event_slots;
|
||||
OsdiEventSlotMeta *event_slot_metadata;
|
||||
|
||||
/* OSDI v0.5 (2C — absdelay exact transport). Number of per-instance
|
||||
/* OpenVA OSDI (absdelay exact transport). Number of per-instance
|
||||
* transport-delay "sites" (one per absdelay call site in the model).
|
||||
* The simulator sizes and manages a (time, value) ring buffer per site
|
||||
* per instance; the model records its input each eval and reads delayed
|
||||
* values via SimInfo.delay_read. Zero for models with no absdelay.
|
||||
* Tail-appended — ABI-safe via the OSDI_DESCRIPTOR_SIZE bounds check. */
|
||||
* Tail-appended — ABI-safe via the loader's zeroed-copy normalization. */
|
||||
uint32_t num_delay_sites;
|
||||
|
||||
/* OSDI v0.5 (2C AC delay — 1B). The delay-coupling jacobian category:
|
||||
/* OpenVA OSDI (AC delay). The delay-coupling jacobian category:
|
||||
* absdelay's AC contribution. num_delay_jacobian_entries jacobian entries
|
||||
* carry a delay part (flagged JACOBIAN_ENTRY_DELAY). write_jacobian_array
|
||||
* _delay(inst, model, dst) writes their raw values (ddx(-input)) into dst[
|
||||
|
|
@ -387,13 +383,13 @@ typedef struct OsdiDescriptor {
|
|||
void (*write_jacobian_array_delay)(void *inst, void *model, double *dst);
|
||||
uint32_t *delay_jacobian_sites;
|
||||
|
||||
/* OSDI 0.5 — per-instance persistent state (transition()/slew()/event
|
||||
/* OpenVA OSDI — per-instance persistent state (transition()/slew()/event
|
||||
* toolkit). Byte offset and slot count of the persistent_state f64 array
|
||||
* inside the instance struct. The simulator snapshots this array and DEFERS
|
||||
* its commit to accepted steps only, so predictor / Newton iterates can't
|
||||
* corrupt the previous-accepted value the model reads back. Both zero for
|
||||
* models with no persistent state. Tail-appended — ABI-safe via the
|
||||
* OSDI_DESCRIPTOR_SIZE bounds check. */
|
||||
* loader's zeroed-copy normalization. */
|
||||
uint32_t persistent_state_offset;
|
||||
uint32_t persistent_state_count;
|
||||
}OsdiDescriptor;
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ int OSDIacLoad(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
descr->load_jacobian_resist(inst, model);
|
||||
descr->load_jacobian_react(inst, model, ckt->CKTomega);
|
||||
|
||||
/* OSDI v0.5 (2C AC delay — 1B). absdelay's exact AC phase: each delay
|
||||
/* OpenVA OSDI (2C AC delay — 1B). absdelay's exact AC phase: each delay
|
||||
* jacobian entry's value V (= ddx(-input), computed at the OP) is stamped
|
||||
* as V * e^{-jw*td(site)} into the complex matrix -- V*cos(w*td) into the
|
||||
* real part and V*(-sin(w*td)) into the imag part. This is the
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ double osdi_limitlog(bool init, bool *check, double vnew, double vold,
|
|||
return res;
|
||||
}
|
||||
|
||||
/* OSDI v0.5 (2C) — absdelay exact-transport reader. Bound to
|
||||
/* OpenVA OSDI (2C) — absdelay exact-transport reader. Bound to
|
||||
* SimInfo.delay_read; the model calls it mid-eval to obtain
|
||||
* x(abstime - td) by linear interpolation over the per-instance ring
|
||||
* (accepted (time,value) samples, oldest..newest). SimInfo.delay_state
|
||||
|
|
@ -108,7 +108,7 @@ double osdi_delay_read(const OsdiSimInfo *info, uint32_t site, double td,
|
|||
if (max_td >= 0.0 && td > max_td)
|
||||
td = max_td;
|
||||
|
||||
/* OSDI v0.5 (2C AC delay) — stash the (clamped) td so OSDIacLoad can read
|
||||
/* OpenVA OSDI (2C AC delay) — stash the (clamped) td so OSDIacLoad can read
|
||||
* td(OP) for this site's e^{-jw*td} delay jacobian. */
|
||||
if (extra->delay_td_arr)
|
||||
extra->delay_td_arr[site] = td;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ typedef struct OsdiExtraInstData {
|
|||
bool dt_given;
|
||||
uint32_t eval_flags;
|
||||
|
||||
/* OSDI v0.5 — event-driven analog operators (S3b).
|
||||
/* OpenVA OSDI — event-driven analog operators (S3b).
|
||||
*
|
||||
* Per-instance scratch buffers for the SimInfo.cross_expr and
|
||||
* .pending_events pointers. Lazily allocated on first eval if
|
||||
|
|
@ -97,14 +97,14 @@ typedef struct OsdiExtraInstData {
|
|||
uint32_t scheduled_count;
|
||||
bool cross_init;
|
||||
|
||||
/* OSDI v0.5 (S3c) — abstime of the last accepted eval that
|
||||
/* OpenVA OSDI (S3c) — abstime of the last accepted eval that
|
||||
* latched prev_cross_expr_arr. Used as the lower bound for
|
||||
* interpolating the crossing time when the next eval detects a
|
||||
* sign flip. Default -1.0 (no prior eval); the first latched
|
||||
* eval sets it to the eval's abstime. */
|
||||
double prev_eval_time;
|
||||
|
||||
/* OSDI v0.5 — the SECOND prior accepted (time, cross_expr) sample,
|
||||
/* OpenVA OSDI — the SECOND prior accepted (time, cross_expr) sample,
|
||||
* kept so the crossing time can be QUADRATICALLY interpolated from
|
||||
* three points (t_prev2, t_prev, t_now) -> O(dt^3) error, instead of
|
||||
* the 2-point linear fit -> O(dt^2). The cross_expr VALUE already
|
||||
|
|
@ -119,7 +119,7 @@ typedef struct OsdiExtraInstData {
|
|||
double *prev2_cross_expr_arr;
|
||||
double prev2_eval_time;
|
||||
|
||||
/* OSDI v0.5 (2C) — absdelay exact-transport delay rings. Lazily
|
||||
/* OpenVA OSDI (2C) — absdelay exact-transport delay rings. Lazily
|
||||
* allocated on first eval when descr->num_delay_sites > 0.
|
||||
* delay_input_arr[site] : current input written by the model each eval
|
||||
* (exposed as SimInfo.delay_input); pushed into the ring at accept.
|
||||
|
|
@ -130,7 +130,7 @@ typedef struct OsdiExtraInstData {
|
|||
* points back at THIS struct so SimInfo.delay_read can reach them. */
|
||||
double *delay_input_arr;
|
||||
double *delay_maxtd_arr;
|
||||
/* OSDI v0.5 (2C AC delay) — last td the model passed to delay_read per site,
|
||||
/* OpenVA OSDI (2C AC delay) — last td the model passed to delay_read per site,
|
||||
* stashed by osdi_delay_read. At the AC operating point this holds td(OP),
|
||||
* which OSDIacLoad uses for e^{-jw*td} on that site's delay jacobian. */
|
||||
double *delay_td_arr;
|
||||
|
|
@ -139,7 +139,7 @@ typedef struct OsdiExtraInstData {
|
|||
uint32_t *delay_count;
|
||||
uint32_t *delay_cap;
|
||||
|
||||
/* OSDI 0.5 — DEFERRED-COMMIT snapshot of the model's persistent_state array
|
||||
/* OpenVA OSDI — DEFERRED-COMMIT snapshot of the model's persistent_state array
|
||||
* (transition()/slew()/event toolkit). Sized to
|
||||
* entry->persistent_state_count, lazily allocated on first eval. Holds the
|
||||
* value as of the last ACCEPTED step. Each eval restores the live
|
||||
|
|
@ -196,7 +196,7 @@ double osdi_limitlog(bool init, bool *icheck, double vnew, double vold,
|
|||
double osdi_fetlim(bool init, bool *icheck, double vnew, double vold,
|
||||
double vto);
|
||||
|
||||
/* OSDI v0.5 (2C) — absdelay exact-transport reader (bound to
|
||||
/* OpenVA OSDI (2C) — absdelay exact-transport reader (bound to
|
||||
* SimInfo.delay_read). */
|
||||
double osdi_delay_read(const OsdiSimInfo *info, uint32_t site, double td,
|
||||
double max_td);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ OsdiSimParas get_simparams(const CKTcircuit *ckt) {
|
|||
return sim_params_;
|
||||
}
|
||||
|
||||
/* OSDI v0.5 (S3b) — per-instance event-state preparation BEFORE
|
||||
/* OpenVA OSDI (S3b) — per-instance event-state preparation BEFORE
|
||||
* descr->eval is called. Lazy-allocate cross_expr / pending_events
|
||||
* buffers (sized from the descriptor), wire them onto the per-eval
|
||||
* SimInfo, and decide whether this eval is at a previously
|
||||
|
|
@ -217,7 +217,7 @@ static double osdi_cross_time(double t0, double v0,
|
|||
return (denom > 0.0) ? t1 + span * (fabs(v1) / denom) : t2;
|
||||
}
|
||||
|
||||
/* OSDI v0.5 — post-eval processing.
|
||||
/* OpenVA OSDI — post-eval processing.
|
||||
*
|
||||
* S3b: drain model-written pending_events into the sorted
|
||||
* scheduled_events queue.
|
||||
|
|
@ -321,7 +321,7 @@ static void eval(const OsdiDescriptor *descr, const GENinstance *gen_inst,
|
|||
OsdiNgspiceHandle handle =
|
||||
(OsdiNgspiceHandle){.kind = 3, .name = gen_inst->GENname};
|
||||
|
||||
/* OSDI v0.5 — per-instance scratch SimInfo with event-state
|
||||
/* OpenVA OSDI — per-instance scratch SimInfo with event-state
|
||||
* pointers wired up. Originals stay shared/read-only across the
|
||||
* OMP parallel region. */
|
||||
OsdiSimInfo sim_info_local = *sim_info;
|
||||
|
|
@ -572,7 +572,7 @@ static void load(CKTcircuit *ckt, const GENinstance *gen_inst, void *model,
|
|||
}
|
||||
}
|
||||
|
||||
/* OSDI v0.5 (2C) — push one accepted (time, value) sample into delay ring
|
||||
/* OpenVA OSDI (2C) — push one accepted (time, value) sample into delay ring
|
||||
* `s`, growing capacity geometrically, then prune leading samples that can
|
||||
* no longer bracket any delay <= maxtd (keeping >= 2 for interpolation).
|
||||
* maxtd < 0 means unbounded — capped at a defensive ceiling so a deck that
|
||||
|
|
@ -614,7 +614,7 @@ static void osdi_delay_push(OsdiExtraInstData *extra, uint32_t s, double t,
|
|||
}
|
||||
}
|
||||
|
||||
/* OSDI 0.5 — DEFERRED-COMMIT persistent state.
|
||||
/* OpenVA OSDI — DEFERRED-COMMIT persistent state.
|
||||
*
|
||||
* The model's persistent_state array (transition()/slew()/event toolkit) is
|
||||
* read-modify-written in place during eval, so a predictor eval and every
|
||||
|
|
@ -662,7 +662,7 @@ static void osdi_persist_commit(const OsdiRegistryEntry *entry, void *inst,
|
|||
memcpy(extra->persist_snapshot, live, (size_t)n * sizeof(double));
|
||||
}
|
||||
|
||||
/* OSDI v0.5 (2C) — DEVaccept hook. Fires once per ACCEPTED transient step
|
||||
/* OpenVA OSDI (2C) — DEVaccept hook. Fires once per ACCEPTED transient step
|
||||
* (from CKTaccept); records each instance's current delay input (written by
|
||||
* the model during the converged eval) into its per-site transport-delay
|
||||
* ring. Only the accepted trajectory is recorded, which the model itself
|
||||
|
|
@ -777,7 +777,7 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
sim_info.flags |= CALC_REACT_JACOBIAN | CALC_REACT_RESIDUAL |
|
||||
CALC_REACT_LIM_RHS | ANALYSIS_TRAN;
|
||||
|
||||
/* OSDI 0.5 — flag the final transient timepoint so a model can fire
|
||||
/* OpenVA OSDI — flag the final transient timepoint so a model can fire
|
||||
* an @(final_step) body. dctran puts a hard breakpoint at
|
||||
* CKTfinalTime, so the last accepted step lands exactly on it. */
|
||||
if (AlmostEqualUlps(ckt->CKTtime, ckt->CKTfinalTime, 100)) {
|
||||
|
|
@ -908,7 +908,7 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
ckt->CKTnoncon++;
|
||||
}
|
||||
|
||||
/* Axis-3 (OSDI v0.5): a model has raised REJECT_STEP, signalling that
|
||||
/* Axis-3 (OpenVA OSDI): a model has raised REJECT_STEP, signalling that
|
||||
* its linearization is invalid at the current operating point (predicted
|
||||
* voltage outside model validity, internal-node blow-up, ...). NIiter
|
||||
* will observe CKTosdiStepReject after CKTload returns and bail with
|
||||
|
|
|
|||
|
|
@ -400,9 +400,8 @@ extern OsdiObjectFile load_object_file(const char *input) {
|
|||
} else {
|
||||
/* Original OpenVAF binaries don't publish OSDI_DESCRIPTOR_SIZE
|
||||
* and must be v0.3 exactly. OSDI_VERSION_MAJOR_CURR /
|
||||
* OSDI_VERSION_MINOR_CURR now track the current
|
||||
* openvaf-reloaded/OpenVA version (0.5 as of S3a) so the
|
||||
* v0.3 check is hard-coded here. */
|
||||
* OSDI_VERSION_MINOR_CURR track the current OpenVA OSDI
|
||||
* version, so the v0.3 check is hard-coded here. */
|
||||
if (OSDI_VERSION_MAJOR != 0 || OSDI_VERSION_MINOR != 3) {
|
||||
printf("NGSPICE only supports OSDI v0.3 (original OpenVAF) "
|
||||
"or v0.4+ (OpenVAF-reloaded / OpenVA) but \"%s\" uses "
|
||||
|
|
@ -411,7 +410,11 @@ extern OsdiObjectFile load_object_file(const char *input) {
|
|||
txfree(path);
|
||||
return INVALID_OBJECT;
|
||||
}
|
||||
descriptor_size = sizeof(OsdiDescriptor);
|
||||
/* The v0.3 descriptor ends right where the v0.4 fields begin: it is
|
||||
* the prefix of the current struct up to given_flag_model. Using
|
||||
* sizeof(OsdiDescriptor) here would walk a multi-descriptor v0.3
|
||||
* file with the wrong stride. */
|
||||
descriptor_size = offsetof(OsdiDescriptor, given_flag_model);
|
||||
}
|
||||
|
||||
GET_CONST(OSDI_NUM_DESCRIPTORS, uint32_t);
|
||||
|
|
@ -461,12 +464,31 @@ extern OsdiObjectFile load_object_file(const char *input) {
|
|||
}
|
||||
|
||||
OsdiRegistryEntry *dst = TMALLOC(OsdiRegistryEntry, OSDI_NUM_DESCRIPTORS);
|
||||
|
||||
char* desc_ptr = (char*)OSDI_DESCRIPTORS;
|
||||
|
||||
/* Normalize the file's descriptors to this build's layout. The .osdi
|
||||
* stores an array with stride descriptor_size, which for a v0.3/v0.4 file
|
||||
* is smaller than the current struct (and for a future version may be
|
||||
* larger). Copy each descriptor into a zeroed full-size OsdiDescriptor so
|
||||
* every field this build knows about reads as a true zero when the file
|
||||
* predates it — downstream code (osdiload.c, osditrunc.c) reads tail
|
||||
* fields like num_cross_exprs without per-field size checks. The copies
|
||||
* only hold counts/offsets and pointers back into the .so, which stays
|
||||
* loaded for the lifetime of the process. */
|
||||
OsdiDescriptor *descriptors = TMALLOC(OsdiDescriptor, OSDI_NUM_DESCRIPTORS);
|
||||
memset(descriptors, 0, sizeof(OsdiDescriptor) * OSDI_NUM_DESCRIPTORS);
|
||||
{
|
||||
size_t copy_size = descriptor_size < sizeof(OsdiDescriptor)
|
||||
? descriptor_size
|
||||
: sizeof(OsdiDescriptor);
|
||||
for (uint32_t i = 0; i < OSDI_NUM_DESCRIPTORS; i++)
|
||||
memcpy(&descriptors[i],
|
||||
(const char *)OSDI_DESCRIPTORS + (size_t)i * descriptor_size,
|
||||
copy_size);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < OSDI_NUM_DESCRIPTORS; i++) {
|
||||
const OsdiDescriptor *descr = (OsdiDescriptor*)desc_ptr;
|
||||
desc_ptr += descriptor_size;
|
||||
|
||||
const OsdiDescriptor *descr = &descriptors[i];
|
||||
|
||||
uint32_t dt = descr->num_params + descr->num_opvars;
|
||||
bool has_m = false;
|
||||
uint32_t temp = descr->num_params + descr->num_opvars + 1;
|
||||
|
|
@ -491,28 +513,11 @@ extern OsdiObjectFile load_object_file(const char *input) {
|
|||
|
||||
size_t inst_off = calc_osdi_instance_data_off(descr);
|
||||
size_t noise_off = calc_osdi_noise_off(descr);
|
||||
/* OSDI v0.5 (2C) — only trust num_delay_sites if the published
|
||||
* descriptor size actually reaches that field; a pre-2C .osdi has a
|
||||
* smaller descriptor and reading it would dereference past its slot. */
|
||||
uint32_t num_delay_sites =
|
||||
(descriptor_size >= offsetof(OsdiDescriptor, num_delay_sites) +
|
||||
sizeof(uint32_t))
|
||||
? descr->num_delay_sites
|
||||
: 0u;
|
||||
|
||||
/* Persistent-state offset/count: only trust them if the published
|
||||
* descriptor actually reaches these tail fields (a pre-0.5 .osdi has a
|
||||
* smaller descriptor). */
|
||||
uint32_t persistent_state_count =
|
||||
(descriptor_size >= offsetof(OsdiDescriptor, persistent_state_count) +
|
||||
sizeof(uint32_t))
|
||||
? descr->persistent_state_count
|
||||
: 0u;
|
||||
uint32_t persistent_state_offset =
|
||||
(descriptor_size >= offsetof(OsdiDescriptor, persistent_state_offset) +
|
||||
sizeof(uint32_t))
|
||||
? descr->persistent_state_offset
|
||||
: 0u;
|
||||
/* v0.5 tail fields: the normalized copy guarantees these read as zero
|
||||
* when the .osdi predates them, so no per-field size checks needed. */
|
||||
uint32_t num_delay_sites = descr->num_delay_sites;
|
||||
uint32_t persistent_state_count = descr->persistent_state_count;
|
||||
uint32_t persistent_state_offset = descr->persistent_state_offset;
|
||||
|
||||
dst[i] = (OsdiRegistryEntry){
|
||||
.descriptor = descr,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ int OSDItrunc(GENmodel *in_model, CKTcircuit *ckt, double *timestep) {
|
|||
bool has_boundstep = offset != UINT32_MAX;
|
||||
offset += entry->inst_offset;
|
||||
|
||||
/* OSDI v0.5 (S3b) — clamp the proposed timestep against any
|
||||
/* OpenVA OSDI (S3b) — clamp the proposed timestep against any
|
||||
* pending scheduled events on instances of this model. Each
|
||||
* instance has a sorted per-instance queue of scheduled events;
|
||||
* the earliest one bounds dt so the simulator lands exactly on
|
||||
|
|
|
|||
Loading…
Reference in New Issue