From c60ab4203dec370f59c211ef5f73c3c421b012bd Mon Sep 17 00:00:00 2001 From: DSPOM Date: Tue, 19 Jul 2022 18:17:02 +0200 Subject: [PATCH] update osdi version --- src/Makefile.am | 1 - src/osdi/Makefile.am | 2 +- src/osdi/exported.txt | 6 -- src/osdi/osdi.h | 28 +++++++- src/osdi/osdicallbacks.c | 88 +++++++++++++++++++++++++ src/osdi/osdidefs.h | 15 ++++- src/osdi/osdiinit.c | 37 ----------- src/osdi/osdiload.c | 40 +++++++++--- src/osdi/osdiregistry.c | 51 ++++++++++++++- src/osdi/osdisetup.c | 13 +++- src/spicelib/analysis/acan.c | 5 +- test_cases/diode/diode.c | 123 ++++++++++++++++++++++++++++------- 12 files changed, 324 insertions(+), 85 deletions(-) delete mode 100644 src/osdi/exported.txt create mode 100644 src/osdi/osdicallbacks.c diff --git a/src/Makefile.am b/src/Makefile.am index 26f397966..2dd35b484 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 += \ diff --git a/src/osdi/Makefile.am b/src/osdi/Makefile.am index 2a22c3b99..f23a7b8eb 100644 --- a/src/osdi/Makefile.am +++ b/src/osdi/Makefile.am @@ -15,7 +15,7 @@ libosdi_la_SOURCES = \ osdiitf.h \ osditrunc.c \ osdipzld.c \ - exported.txt + osdicallbacks.c diff --git a/src/osdi/exported.txt b/src/osdi/exported.txt deleted file mode 100644 index 242368ceb..000000000 --- a/src/osdi/exported.txt +++ /dev/null @@ -1,6 +0,0 @@ -{ - extern "C" - { - osdi_log; - }; -}; diff --git a/src/osdi/osdi.h b/src/osdi/osdi.h index 07fabd841..837b9780d 100644 --- a/src/osdi/osdi.h +++ b/src/osdi/osdi.h @@ -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); - diff --git a/src/osdi/osdicallbacks.c b/src/osdi/osdicallbacks.c new file mode 100644 index 000000000..de7b1dc97 --- /dev/null +++ b/src/osdi/osdicallbacks.c @@ -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; +} diff --git a/src/osdi/osdidefs.h b/src/osdi/osdidefs.h index 09d83fe0e..21bae0050 100644 --- a/src/osdi/osdidefs.h +++ b/src/osdi/osdidefs.h @@ -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); diff --git a/src/osdi/osdiinit.c b/src/osdi/osdiinit.c index 44c1ce578..2a2a2200d 100644 --- a/src/osdi/osdiinit.c +++ b/src/osdi/osdiinit.c @@ -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); - } -} diff --git a/src/osdi/osdiload.c b/src/osdi/osdiload.c index 7c18c5fa6..880a6775d 100644 --- a/src/osdi/osdiload.c +++ b/src/osdi/osdiload.c @@ -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) { diff --git a/src/osdi/osdiregistry.c b/src/osdi/osdiregistry.c index 144239af2..3dbd19728 100644 --- a/src/osdi/osdiregistry.c +++ b/src/osdi/osdiregistry.c @@ -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++) { diff --git a/src/osdi/osdisetup.c b/src/osdi/osdisetup.c index 167cf7463..182b53a96 100644 --- a/src/osdi/osdisetup.c +++ b/src/osdi/osdisetup.c @@ -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; } } diff --git a/src/spicelib/analysis/acan.c b/src/spicelib/analysis/acan.c index da8d5bd39..1c45856c9 100644 --- a/src/spicelib/analysis/acan.c +++ b/src/spicelib/analysis/acan.c @@ -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) { diff --git a/test_cases/diode/diode.c b/test_cases/diode/diode.c index 75daef690..cecd5fb3e 100644 --- a/test_cases/diode/diode.c +++ b/test_cases/diode/diode.c @@ -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;