update osdi version

This commit is contained in:
DSPOM 2022-07-19 18:17:02 +02:00
parent 321ea03444
commit c60ab4203d
12 changed files with 324 additions and 85 deletions

View File

@ -185,7 +185,6 @@ endif
if OSDI_WANTED
ngspice_LDADD += osdi/libosdi.la
ngspice_LDFLAGS += -Wl,--dynamic-list=$(top_srcdir)/src/osdi/exported.txt
endif
ngspice_LDADD += \

View File

@ -15,7 +15,7 @@ libosdi_la_SOURCES = \
osdiitf.h \
osditrunc.c \
osdipzld.c \
exported.txt
osdicallbacks.c

View File

@ -1,6 +0,0 @@
{
extern "C"
{
osdi_log;
};
};

View File

@ -36,6 +36,17 @@
#define CALC_REACT_JACOBIAN 8
#define CALC_NOISE 16
#define CALC_OP 32
#define CALC_RESIST_LIM_RHS 64
#define CALC_REACT_LIM_RHS 128
#define ENABLE_LIM 256
#define INIT_LIM 512
#define ANALYSIS_NOISE 1024
#define ANALYSIS_DC 2048
#define ANALYSIS_AC 4096
#define ANALYSIS_TRAN 8192
#define ANALYSIS_IC 16384
#define ANALYSIS_STATIC 32768
#define ANALYSIS_NODESET 65536
#define EVAL_RET_FLAG_LIM 1
#define EVAL_RET_FLAG_FATAL 2
@ -56,6 +67,12 @@
typedef struct OsdiLimFunction {
char *name;
uint32_t num_args;
void *func_ptr;
}OsdiLimFunction;
typedef struct OsdiSimParas {
char **names;
double *vals;
@ -67,6 +84,8 @@ typedef struct OsdiSimInfo {
OsdiSimParas paras;
double abstime;
double *prev_solve;
double *prev_state;
double *next_state;
uint32_t flags;
}OsdiSimInfo;
@ -102,6 +121,8 @@ typedef struct OsdiNode {
char *residual_units;
uint32_t resist_residual_off;
uint32_t react_residual_off;
uint32_t resist_limit_rhs_off;
uint32_t react_limit_rhs_off;
bool is_flow;
}OsdiNode;
@ -144,6 +165,9 @@ typedef struct OsdiDescriptor {
uint32_t node_mapping_offset;
uint32_t jacobian_ptr_resist_offset;
uint32_t num_states;
uint32_t state_idx_off;
uint32_t bound_step_offset;
uint32_t instance_size;
@ -162,6 +186,8 @@ typedef struct OsdiDescriptor {
double *ln_noise_dens);
void (*load_residual_resist)(void *inst, void* model, double *dst);
void (*load_residual_react)(void *inst, void* model, double *dst);
void (*load_limit_rhs_resist)(void *inst, void* model, double *dst);
void (*load_limit_rhs_react)(void *inst, void* model, double *dst);
void (*load_spice_rhs_dc)(void *inst, void* model, double *dst,
double* prev_solve);
void (*load_spice_rhs_tran)(void *inst, void* model, double *dst,
@ -173,5 +199,3 @@ typedef struct OsdiDescriptor {
extern void osdi_log(void *handle, char* msg, uint32_t lvl);

88
src/osdi/osdicallbacks.c Normal file
View File

@ -0,0 +1,88 @@
#include "ngspice/devdefs.h"
#include "osdidefs.h"
void osdi_log(void *handle_, char *msg, uint32_t lvl) {
OsdiNgspiceHandle *handle = handle_;
FILE *dst = stdout;
switch (lvl & LOG_LVL_MASK) {
case LOG_LVL_DEBUG:
printf("OSDI(debug) %s: ", handle->name);
break;
case LOG_LVL_DISPLAY:
printf("OSDI %s: ", handle->name);
break;
case LOG_LVL_INFO:
printf("OSDI(info) %s: ", handle->name);
break;
case LOG_LVL_WARN:
fprintf(stderr, "OSDI(warn) %s: ", handle->name);
dst = stderr;
break;
case LOG_LVL_ERR:
fprintf(stderr, "OSDI(err) %s: ", handle->name);
dst = stderr;
break;
case LOG_LVL_FATAL:
fprintf(stderr, "OSDI(fatal) %s: ", handle->name);
dst = stderr;
break;
default:
fprintf(stderr, "OSDI(unkown) %s", handle->name);
break;
}
if (lvl & LOG_FMT_ERR) {
fprintf(dst, "failed to format\"%s\"\n", msg);
} else {
fprintf(dst, "%s", msg);
}
}
double osdi_pnjlim(bool init, bool *check, double vnew, double vold, double vt,
double vcrit) {
if (init) {
*check = true;
return vcrit;
}
int icheck = 0;
double res = DEVpnjlim(vnew, vold, vt, vcrit, &icheck);
*check = icheck != 0;
return res;
}
double osdi_limvds(bool init, bool *check, double vnew, double vold) {
if (init) {
*check = true;
return 0.1;
}
double res = DEVlimvds(vnew, vold);
if (res != vnew) {
*check = true;
}
return res;
}
double osdi_fetlim(bool init, bool *check, double vnew, double vold,
double vto) {
if (init) {
*check = true;
return vto + 0.1;
}
double res = DEVfetlim(vnew, vold, vto);
if (res != vnew) {
*check = true;
}
return res;
}
double osdi_limitlog(bool init, bool *check, double vnew, double vold,
double LIM_TOL) {
if (init) {
*check = true;
return 0.0;
}
int icheck = 0;
double res = DEVlimitlog(vnew, vold, LIM_TOL, &icheck);
*check = icheck != 0;
return res;
}

View File

@ -30,7 +30,6 @@ typedef struct OsdiExtraInstData {
double temp;
bool temp_given;
bool dt_given;
bool lim;
bool finish;
} __attribute__((aligned(sizeof(max_align_t)))) OsdiExtraInstData;
@ -52,3 +51,17 @@ typedef struct OsdiNgspiceHandle {
/* values returned by $simparam*/
OsdiSimParas get_simparams(const CKTcircuit *ckt);
typedef void (*osdi_log_ptr)(void *handle, char *msg, uint32_t lvl);
void osdi_log(void *handle_, char *msg, uint32_t lvl);
typedef void (*osdi_log_ptr)(void *handle, char *msg, uint32_t lvl);
double osdi_pnjlim(bool init, bool *icheck, double vnew, double vold, double vt,
double vcrit);
double osdi_limvds(bool init, bool *icheck, double vnew, double vold);
double osdi_limitlog(bool init, bool *icheck, double vnew, double vold,
double LIM_TOL);
double osdi_fetlim(bool init, bool *icheck, double vnew, double vold,
double vto);

View File

@ -177,40 +177,3 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) {
return OSDIinfo;
}
extern void osdi_log(void *handle_, char *msg, uint32_t lvl) {
OsdiNgspiceHandle *handle = handle_;
FILE *dst = stdout;
switch (lvl & LOG_LVL_MASK) {
case LOG_LVL_DEBUG:
printf("OSDI(debug) %s: ", handle->name);
break;
case LOG_LVL_DISPLAY:
printf("OSDI %s: ", handle->name);
break;
case LOG_LVL_INFO:
printf("OSDI(info) %s: ", handle->name);
break;
case LOG_LVL_WARN:
fprintf(stderr, "OSDI(warn) %s: ", handle->name);
dst = stderr;
break;
case LOG_LVL_ERR:
fprintf(stderr, "OSDI(err) %s: ", handle->name);
dst = stderr;
break;
case LOG_LVL_FATAL:
fprintf(stderr, "OSDI(fatal) %s: ", handle->name);
dst = stderr;
break;
default:
fprintf(stderr, "OSDI(unkown) %s", handle->name);
break;
}
if (lvl & LOG_FMT_ERR) {
fprintf(dst, "failed to format\"%s\"\n", msg);
} else {
fprintf(dst, "%s", msg);
}
}

View File

@ -49,14 +49,19 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
bool is_init_smsig = ckt->CKTmode & MODEINITSMSIG;
bool is_sweep = ckt->CKTmode & MODEDCTRANCURVE;
bool is_dc = ckt->CKTmode & (MODEDCOP | MODEDCTRANCURVE);
bool is_ac = ckt->CKTmode & (MODEAC | MODEINITSMSIG);
bool is_tran = ckt->CKTmode & (MODETRAN);
bool is_tran_op = ckt->CKTmode & (MODETRANOP);
bool is_init_tran = ckt->CKTmode & MODEINITTRAN;
bool is_init_junc = ckt->CKTmode & MODEINITJCT;
OsdiSimInfo sim_info = {
.paras = get_simparams(ckt),
.abstime = is_tran ? ckt->CKTtime : 0.0,
.prev_solve = ckt->CKTrhsOld,
.prev_state = ckt->CKTstates[0],
.next_state = ckt->CKTstates[0],
.flags = CALC_RESIST_JACOBIAN,
};
@ -64,20 +69,37 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
sim_info.flags |= CALC_OP;
}
if (!is_init_smsig) {
sim_info.flags |= CALC_RESIST_RESIDUAL;
if (is_dc) {
sim_info.flags |= ANALYSIS_DC | ANALYSIS_STATIC;
}
if (is_tran || is_ac) {
sim_info.flags |= CALC_REACT_JACOBIAN;
if (!is_init_smsig) {
sim_info.flags |= CALC_RESIST_RESIDUAL | ENABLE_LIM | CALC_RESIST_LIM_RHS;
}
if (is_tran) {
sim_info.flags |= CALC_REACT_RESIDUAL;
sim_info.flags |= CALC_REACT_JACOBIAN | CALC_REACT_RESIDUAL |
CALC_REACT_LIM_RHS | ANALYSIS_TRAN;
}
if (is_tran_op) {
sim_info.flags |= ANALYSIS_TRAN;
}
if (is_ac) {
sim_info.flags |= CALC_REACT_JACOBIAN | ANALYSIS_AC;
}
if (is_init_tran) {
sim_info.flags |= ANALYSIS_IC | ANALYSIS_STATIC;
}
if (is_init_junc) {
sim_info.flags |= INIT_LIM;
}
if (ckt->CKTmode & MODEACNOISE) {
sim_info.flags |= CALC_NOISE;
sim_info.flags |= CALC_NOISE | ANALYSIS_NOISE;
}
int ret = OK;
@ -119,7 +141,9 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
extra_inst_data->finish = true;
}
if (ret_flags & EVAL_RET_FLAG_LIM) {
extra_inst_data->lim = true;
ckt->CKTnoncon++;
ckt->CKTtroubleElt = gen_inst;
}
if (ret_flags & EVAL_RET_FLAG_STOP) {
ret = (E_PAUSE);
@ -138,7 +162,7 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
(uint32_t *)(((char *)inst) + descr->node_mapping_offset);
/* use numeric integration to obtain the remainer of the RHS*/
int state = gen_inst->GENstate;
int state = gen_inst->GENstate + (int) descr->num_states;
for (uint32_t i = 0; i < descr->num_nodes; i++) {
if (descr->nodes[i].react_residual_off != UINT32_MAX) {

View File

@ -205,6 +205,23 @@ static size_t calc_osdi_instance_data_off(const OsdiDescriptor *descr) {
} \
const ty *name = (ty *)sym;
#define INIT_CALLBACK(name, ty) \
sym = GET_SYM(handle, STRINGIFY(name)); \
if (sym) { \
ty *slot = (ty *)sym; \
*slot = name; \
}
#define IS_LIM_FUN(fun_name, num_args_, val) \
if (strcmp(lim_table[i].name, fun_name) == 0) { \
if (lim_table[i].num_args == num_args_) { \
lim_table[i].func_ptr = (void *)val; \
continue; \
} else { \
expected_args = num_args_; \
} \
}
static NGHASHPTR known_object_files = NULL;
#define DUMMYDATA ((void *)42)
/**
@ -229,7 +246,8 @@ extern OsdiObjectFile load_object_file(const char *input) {
}
const char *path = resolve_input_path(input);
if (!path) {
printf("Error opening osdi lib \"%s\": No such file or directory!\n", input);
printf("Error opening osdi lib \"%s\": No such file or directory!\n",
input);
return INVALID_OBJECT;
}
@ -261,6 +279,37 @@ extern OsdiObjectFile load_object_file(const char *input) {
GET_CONST(OSDI_NUM_DESCRIPTORS, uint32_t);
GET_PTR(OSDI_DESCRIPTORS, OsdiDescriptor);
INIT_CALLBACK(osdi_log, osdi_log_ptr)
uint32_t lim_table_len = 0;
sym = GET_SYM(handle, "OSDI_LIM_TABLE_LEN");
if (sym) {
lim_table_len = *((uint32_t *)sym);
}
sym = GET_SYM(handle, "OSDI_LIM_TABLE");
OsdiLimFunction *lim_table = NULL;
if (sym) {
lim_table = (OsdiLimFunction *)sym;
} else {
lim_table_len = 0;
}
for (uint32_t i = 0; i < lim_table_len; i++) {
int expected_args = -1;
IS_LIM_FUN("pnjlim", 2, osdi_pnjlim)
IS_LIM_FUN("limvds", 0, osdi_limvds)
IS_LIM_FUN("fetlim", 1, osdi_fetlim)
IS_LIM_FUN("limitlog", 1, osdi_limitlog)
if (expected_args == -1) {
printf("warning(osdi): unkown $limit function \"%s\"", lim_table[i].name);
} else {
printf("warning(osdi): unexpected number of arguments %i (expected %i) "
"for \"%s\", ignoring...",
lim_table[i].num_args, expected_args, lim_table[i].name);
}
}
OsdiRegistryEntry *dst = TMALLOC(OsdiRegistryEntry, OSDI_NUM_DESCRIPTORS);
for (uint32_t i = 0; i < OSDI_NUM_DESCRIPTORS; i++) {

View File

@ -134,6 +134,16 @@ static void write_node_mapping(const OsdiDescriptor *descr, void *inst,
}
}
/* NGSPICE state vectors for an instance are always continous so we just write
* state_start .. state_start + num_state to state_idx */
static void write_state_ids(const OsdiDescriptor *descr, void *inst,
uint32_t state_start) {
uint32_t *state_idx = (uint32_t *)(((char *)inst) + descr->state_idx_off);
for (uint32_t i = 0; i < descr->num_states; i++) {
state_idx[i] = state_start + i;
}
}
static int init_matrix(SMPmatrix *matrix, const OsdiDescriptor *descr,
void *inst) {
uint32_t *node_mapping =
@ -184,7 +194,7 @@ int OSDIsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
uint32_t *node_ids = TMALLOC(uint32_t, descr->num_nodes);
/* determine the number of states required by each instance */
int num_states = 0;
int num_states = (int)descr->num_states;
for (uint32_t i = 0; i < descr->num_nodes; i++) {
if (descr->nodes[i].react_residual_off != UINT32_MAX) {
num_states += 2;
@ -269,6 +279,7 @@ int OSDIsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
/* reserve space in the state vector*/
gen_inst->GENstate = *states;
write_state_ids(descr, inst, (uint32_t)*states);
*states += num_states;
}
}

View File

@ -86,8 +86,9 @@ ACan(CKTcircuit *ckt, int restart)
fprintf(stderr, "ERROR: AC startfreq <= 0\n");
return E_PARMVAL;
}
job->ACfreqDelta =
exp(log(10.0)/job->ACnumberSteps);
double num_steps = floor(fabs(log10(job->ACstopFreq/job->ACstartFreq))*job->ACnumberSteps);
job->ACfreqDelta = exp((log(job->ACstopFreq/job->ACstartFreq))/ num_steps);
break;
case OCTAVE:
if (job->ACstartFreq <= 0) {

View File

@ -22,6 +22,10 @@ extern uint32_t OSDI_VERSION_MAJOR;
extern uint32_t OSDI_VERSION_MINOR;
extern uint32_t OSDI_NUM_DESCRIPTORS;
extern OsdiDescriptor OSDI_DESCRIPTORS[1];
extern OsdiLimFunction OSDI_LIM_TABLE[1];
extern uint32_t OSDI_LIM_TABLE_LEN;
#define sqrt2 1.4142135623730950488016887242097
#define IGNORE(x) (void)x
@ -88,6 +92,10 @@ typedef struct DiodeInstace {
bool mfactor_given;
double temperature;
double residual_resist[NUM_NODES];
double lim_rhs_resist_A;
double lim_rhs_resist_CI;
double lim_rhs_react_A;
double lim_rhs_react_CI;
double residual_react_A;
double residual_react_CI;
double jacobian_resist[NUM_MATRIX];
@ -96,6 +104,7 @@ typedef struct DiodeInstace {
double *jacobian_ptr_resist[NUM_MATRIX];
double *jacobian_ptr_react[NUM_MATRIX];
uint32_t node_off[NUM_NODES];
uint32_t state_idx;
} DiodeInstace;
#define EXP_LIM 80.0
@ -273,6 +282,9 @@ static void setup_instance(void *handle, void *inst_, void *model_,
*res = (OsdiInitInfo){.flags = 0, .num_errors = 0, .errors = NULL};
}
#define CONSTsqrt2 1.4142135623730950488016887242097
typedef double (*pnjlim_t)(bool, bool *, double, double, double, double);
// implementation of the eval function as defined in the OSDI spec
static uint32_t eval(void *handle, void *inst_, void *model_,
OsdiSimInfo *info) {
@ -297,6 +309,7 @@ static uint32_t eval(void *handle, void *inst_, void *model_,
}
}
uint32_t ret_flags = 0;
////////////////////////////////
// evaluate model equations
////////////////////////////////
@ -311,6 +324,22 @@ static uint32_t eval(void *handle, void *inst_, void *model_,
double is_t = model->Is * pow(tdev_tnom, model->zetais);
double vt = t_dev * pk / pq;
double delvaci = 0.0;
if (info->flags & ENABLE_LIM && OSDI_LIM_TABLE[0].func_ptr) {
double vte = inst->temperature * pk / pq;
bool icheck = false;
double vaci_old = info->prev_state[inst->state_idx];
pnjlim_t pnjlim = OSDI_LIM_TABLE[0].func_ptr;
double vaci_new = pnjlim(info->flags & INIT_LIM, &icheck, vaci, vaci_old,
vte, vte * log(vte / (sqrt2 * model->Is)));
printf("%g %g\n", vaci, vaci_new);
delvaci = vaci_new - vaci;
vaci = vaci_new;
info->prev_state[inst->state_idx] = vaci;
} else {
printf("ok?");
}
// derivatives w.r.t. temperature
double rs_dt = model->zetars * model->Rs *
pow(tdev_tnom, model->zetars - 1.0) / model->Tnom;
@ -398,12 +427,24 @@ static uint32_t eval(void *handle, void *inst_, void *model_,
inst->residual_resist[TNODE] = -ith * mfactor + irth * mfactor;
}
if (info->flags & CALC_RESIST_LIM_RHS) {
// write resist rhs
inst->lim_rhs_resist_A = gd * mfactor * delvaci;
inst->lim_rhs_resist_CI = -gd * mfactor * delvaci;
}
if (info->flags & CALC_REACT_RESIDUAL) {
// write react rhs
inst->residual_react_A = qd * mfactor;
inst->residual_react_CI = -qd * mfactor;
}
if (info->flags & CALC_REACT_LIM_RHS) {
// write resist rhs
inst->lim_rhs_react_A = qd_vaci * mfactor * delvaci;
inst->lim_rhs_react_CI = -qd_vaci * mfactor * delvaci;
}
//////////////////
// write Jacobian
//////////////////
@ -449,7 +490,7 @@ static uint32_t eval(void *handle, void *inst_, void *model_,
inst->jacobian_react[CI_TNODE] = -qd_dtj * mfactor;
}
return 0;
return ret_flags;
}
// TODO implementation of the load_noise function as defined in the OSDI spec
@ -486,6 +527,25 @@ static void load_residual_react(void *inst_, void *model, double *dst) {
dst[inst->node_off[CI]] += inst->residual_react_CI;
}
// implementation of the load_lim_rhs_resist function as defined in the OSDI
// spec
static void load_lim_rhs_resist(void *inst_, void *model, double *dst) {
DiodeInstace *inst = (DiodeInstace *)inst_;
IGNORE(model);
dst[inst->node_off[A]] += inst->lim_rhs_resist_A;
dst[inst->node_off[CI]] += inst->lim_rhs_resist_CI;
}
// implementation of the load_lim_rhs_react function as defined in the OSDI spec
static void load_lim_rhs_react(void *inst_, void *model, double *dst) {
DiodeInstace *inst = (DiodeInstace *)inst_;
IGNORE(model);
dst[inst->node_off[A]] += inst->lim_rhs_react_A;
dst[inst->node_off[CI]] += inst->lim_rhs_react_CI;
}
#define LOAD_MATRIX_RESIST(name) \
*inst->jacobian_ptr_resist[name] += inst->jacobian_resist[name];
@ -558,13 +618,15 @@ static void load_spice_rhs_dc(void *inst_, void *model, double *dst,
double vc = prev_solve[inst->node_off[C]];
double vdtj = prev_solve[inst->node_off[TNODE]];
dst[inst->node_off[A]] +=
inst->jacobian_resist[A_A] * va + inst->jacobian_resist[A_TNODE] * vdtj +
inst->jacobian_resist[A_CI] * vci - inst->residual_resist[A];
dst[inst->node_off[A]] += inst->jacobian_resist[A_A] * va +
inst->jacobian_resist[A_TNODE] * vdtj +
inst->jacobian_resist[A_CI] * vci +
inst->lim_rhs_resist_A - inst->residual_resist[A];
dst[inst->node_off[CI]] += inst->jacobian_resist[CI_A] * va +
inst->jacobian_resist[CI_TNODE] * vdtj +
inst->jacobian_resist[CI_CI] * vci -
inst->jacobian_resist[CI_CI] * vci +
inst->lim_rhs_resist_CI -
inst->residual_resist[CI];
dst[inst->node_off[C]] +=
@ -592,13 +654,15 @@ static void load_spice_rhs_tran(void *inst_, void *model, double *dst,
load_spice_rhs_dc(inst_, model, dst, prev_solve);
// add contributions due to reactive elements
dst[inst->node_off[A]] += alpha * (inst->jacobian_react[A_A] * va +
inst->jacobian_react[A_CI] * vci +
inst->jacobian_react[A_TNODE] * vdtj);
dst[inst->node_off[A]] +=
alpha *
(inst->jacobian_react[A_A] * va + inst->jacobian_react[A_CI] * vci +
inst->jacobian_react[A_TNODE] * vdtj + inst->lim_rhs_react_A);
dst[inst->node_off[CI]] += alpha * (inst->jacobian_react[CI_CI] * vci +
inst->jacobian_react[CI_A] * va +
inst->jacobian_react[CI_TNODE] * vdtj);
dst[inst->node_off[CI]] +=
alpha *
(inst->jacobian_react[CI_CI] * vci + inst->jacobian_react[CI_A] * va +
inst->jacobian_react[CI_TNODE] * vdtj + inst->lim_rhs_react_CI);
}
#define RESIST_RESIDUAL_OFF(NODE) \
@ -640,8 +704,8 @@ const OsdiNode nodes[NUM_NODES] = {
#define JACOBI_ENTRY(N1, N2) \
{ \
.nodes = {N1, N2}, .flags = JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT, \
.react_ptr_off = \
offsetof(DiodeInstace, jacobian_ptr_react) + sizeof(double*) * N1##_##N2 \
.react_ptr_off = offsetof(DiodeInstace, jacobian_ptr_react) + \
sizeof(double *) * N1##_##N2 \
}
#define RESIST_JACOBI_ENTRY(N1, N2) \
@ -813,21 +877,30 @@ OsdiDescriptor OSDI_DESCRIPTORS[1] = {{
// step size bound
.bound_step_offset = UINT32_MAX,
.num_states = 1,
.state_idx_off = offsetof(DiodeInstace, state_idx),
// memory
.instance_size = sizeof(DiodeInstace),
.model_size = sizeof(DiodeModel),
// setup
.access = &osdi_access,
.setup_model = &setup_model,
.setup_instance = &setup_instance,
.eval = &eval,
.load_noise = &load_noise,
.load_residual_resist = &load_residual_resist,
.load_residual_react = &load_residual_react,
.load_spice_rhs_dc = &load_spice_rhs_dc,
.load_spice_rhs_tran = &load_spice_rhs_tran,
.load_jacobian_resist = &load_jacobian_resist,
.load_jacobian_react = &load_jacobian_react,
.load_jacobian_tran = &load_jacobian_tran,
.access = osdi_access,
.setup_model = setup_model,
.setup_instance = setup_instance,
.eval = eval,
.load_noise = load_noise,
.load_residual_resist = load_residual_resist,
.load_residual_react = load_residual_react,
.load_spice_rhs_dc = load_spice_rhs_dc,
.load_spice_rhs_tran = load_spice_rhs_tran,
.load_jacobian_resist = load_jacobian_resist,
.load_jacobian_react = load_jacobian_react,
.load_jacobian_tran = load_jacobian_tran,
.load_limit_rhs_react = load_lim_rhs_react,
.load_limit_rhs_resist = load_lim_rhs_resist,
}};
OsdiLimFunction OSDI_LIM_TABLE[1] = {{.name = "pnjlim", .num_args = 2}};
uint32_t OSDI_LIM_TABLE_LEN = 1;