update osdi version
This commit is contained in:
parent
321ea03444
commit
c60ab4203d
|
|
@ -185,7 +185,6 @@ endif
|
||||||
|
|
||||||
if OSDI_WANTED
|
if OSDI_WANTED
|
||||||
ngspice_LDADD += osdi/libosdi.la
|
ngspice_LDADD += osdi/libosdi.la
|
||||||
ngspice_LDFLAGS += -Wl,--dynamic-list=$(top_srcdir)/src/osdi/exported.txt
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ngspice_LDADD += \
|
ngspice_LDADD += \
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ libosdi_la_SOURCES = \
|
||||||
osdiitf.h \
|
osdiitf.h \
|
||||||
osditrunc.c \
|
osditrunc.c \
|
||||||
osdipzld.c \
|
osdipzld.c \
|
||||||
exported.txt
|
osdicallbacks.c
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
osdi_log;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
@ -36,6 +36,17 @@
|
||||||
#define CALC_REACT_JACOBIAN 8
|
#define CALC_REACT_JACOBIAN 8
|
||||||
#define CALC_NOISE 16
|
#define CALC_NOISE 16
|
||||||
#define CALC_OP 32
|
#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_LIM 1
|
||||||
#define EVAL_RET_FLAG_FATAL 2
|
#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 {
|
typedef struct OsdiSimParas {
|
||||||
char **names;
|
char **names;
|
||||||
double *vals;
|
double *vals;
|
||||||
|
|
@ -67,6 +84,8 @@ typedef struct OsdiSimInfo {
|
||||||
OsdiSimParas paras;
|
OsdiSimParas paras;
|
||||||
double abstime;
|
double abstime;
|
||||||
double *prev_solve;
|
double *prev_solve;
|
||||||
|
double *prev_state;
|
||||||
|
double *next_state;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
}OsdiSimInfo;
|
}OsdiSimInfo;
|
||||||
|
|
||||||
|
|
@ -102,6 +121,8 @@ typedef struct OsdiNode {
|
||||||
char *residual_units;
|
char *residual_units;
|
||||||
uint32_t resist_residual_off;
|
uint32_t resist_residual_off;
|
||||||
uint32_t react_residual_off;
|
uint32_t react_residual_off;
|
||||||
|
uint32_t resist_limit_rhs_off;
|
||||||
|
uint32_t react_limit_rhs_off;
|
||||||
bool is_flow;
|
bool is_flow;
|
||||||
}OsdiNode;
|
}OsdiNode;
|
||||||
|
|
||||||
|
|
@ -144,6 +165,9 @@ typedef struct OsdiDescriptor {
|
||||||
uint32_t node_mapping_offset;
|
uint32_t node_mapping_offset;
|
||||||
uint32_t jacobian_ptr_resist_offset;
|
uint32_t jacobian_ptr_resist_offset;
|
||||||
|
|
||||||
|
uint32_t num_states;
|
||||||
|
uint32_t state_idx_off;
|
||||||
|
|
||||||
uint32_t bound_step_offset;
|
uint32_t bound_step_offset;
|
||||||
|
|
||||||
uint32_t instance_size;
|
uint32_t instance_size;
|
||||||
|
|
@ -162,6 +186,8 @@ typedef struct OsdiDescriptor {
|
||||||
double *ln_noise_dens);
|
double *ln_noise_dens);
|
||||||
void (*load_residual_resist)(void *inst, void* model, double *dst);
|
void (*load_residual_resist)(void *inst, void* model, double *dst);
|
||||||
void (*load_residual_react)(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,
|
void (*load_spice_rhs_dc)(void *inst, void* model, double *dst,
|
||||||
double* prev_solve);
|
double* prev_solve);
|
||||||
void (*load_spice_rhs_tran)(void *inst, void* model, double *dst,
|
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);
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -30,7 +30,6 @@ typedef struct OsdiExtraInstData {
|
||||||
double temp;
|
double temp;
|
||||||
bool temp_given;
|
bool temp_given;
|
||||||
bool dt_given;
|
bool dt_given;
|
||||||
bool lim;
|
|
||||||
bool finish;
|
bool finish;
|
||||||
|
|
||||||
} __attribute__((aligned(sizeof(max_align_t)))) OsdiExtraInstData;
|
} __attribute__((aligned(sizeof(max_align_t)))) OsdiExtraInstData;
|
||||||
|
|
@ -52,3 +51,17 @@ typedef struct OsdiNgspiceHandle {
|
||||||
|
|
||||||
/* values returned by $simparam*/
|
/* values returned by $simparam*/
|
||||||
OsdiSimParas get_simparams(const CKTcircuit *ckt);
|
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);
|
||||||
|
|
|
||||||
|
|
@ -177,40 +177,3 @@ extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) {
|
||||||
|
|
||||||
return OSDIinfo;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -49,14 +49,19 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
||||||
|
|
||||||
bool is_init_smsig = ckt->CKTmode & MODEINITSMSIG;
|
bool is_init_smsig = ckt->CKTmode & MODEINITSMSIG;
|
||||||
bool is_sweep = ckt->CKTmode & MODEDCTRANCURVE;
|
bool is_sweep = ckt->CKTmode & MODEDCTRANCURVE;
|
||||||
|
bool is_dc = ckt->CKTmode & (MODEDCOP | MODEDCTRANCURVE);
|
||||||
bool is_ac = ckt->CKTmode & (MODEAC | MODEINITSMSIG);
|
bool is_ac = ckt->CKTmode & (MODEAC | MODEINITSMSIG);
|
||||||
bool is_tran = ckt->CKTmode & (MODETRAN);
|
bool is_tran = ckt->CKTmode & (MODETRAN);
|
||||||
|
bool is_tran_op = ckt->CKTmode & (MODETRANOP);
|
||||||
bool is_init_tran = ckt->CKTmode & MODEINITTRAN;
|
bool is_init_tran = ckt->CKTmode & MODEINITTRAN;
|
||||||
|
bool is_init_junc = ckt->CKTmode & MODEINITJCT;
|
||||||
|
|
||||||
OsdiSimInfo sim_info = {
|
OsdiSimInfo sim_info = {
|
||||||
.paras = get_simparams(ckt),
|
.paras = get_simparams(ckt),
|
||||||
.abstime = is_tran ? ckt->CKTtime : 0.0,
|
.abstime = is_tran ? ckt->CKTtime : 0.0,
|
||||||
.prev_solve = ckt->CKTrhsOld,
|
.prev_solve = ckt->CKTrhsOld,
|
||||||
|
.prev_state = ckt->CKTstates[0],
|
||||||
|
.next_state = ckt->CKTstates[0],
|
||||||
.flags = CALC_RESIST_JACOBIAN,
|
.flags = CALC_RESIST_JACOBIAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -64,20 +69,37 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
||||||
sim_info.flags |= CALC_OP;
|
sim_info.flags |= CALC_OP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_init_smsig) {
|
if (is_dc) {
|
||||||
sim_info.flags |= CALC_RESIST_RESIDUAL;
|
sim_info.flags |= ANALYSIS_DC | ANALYSIS_STATIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_tran || is_ac) {
|
if (!is_init_smsig) {
|
||||||
sim_info.flags |= CALC_REACT_JACOBIAN;
|
sim_info.flags |= CALC_RESIST_RESIDUAL | ENABLE_LIM | CALC_RESIST_LIM_RHS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_tran) {
|
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) {
|
if (ckt->CKTmode & MODEACNOISE) {
|
||||||
sim_info.flags |= CALC_NOISE;
|
sim_info.flags |= CALC_NOISE | ANALYSIS_NOISE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
|
|
@ -119,7 +141,9 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
||||||
extra_inst_data->finish = true;
|
extra_inst_data->finish = true;
|
||||||
}
|
}
|
||||||
if (ret_flags & EVAL_RET_FLAG_LIM) {
|
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) {
|
if (ret_flags & EVAL_RET_FLAG_STOP) {
|
||||||
ret = (E_PAUSE);
|
ret = (E_PAUSE);
|
||||||
|
|
@ -138,7 +162,7 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
||||||
(uint32_t *)(((char *)inst) + descr->node_mapping_offset);
|
(uint32_t *)(((char *)inst) + descr->node_mapping_offset);
|
||||||
|
|
||||||
/* use numeric integration to obtain the remainer of the RHS*/
|
/* 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++) {
|
for (uint32_t i = 0; i < descr->num_nodes; i++) {
|
||||||
if (descr->nodes[i].react_residual_off != UINT32_MAX) {
|
if (descr->nodes[i].react_residual_off != UINT32_MAX) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,23 @@ static size_t calc_osdi_instance_data_off(const OsdiDescriptor *descr) {
|
||||||
} \
|
} \
|
||||||
const ty *name = (ty *)sym;
|
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;
|
static NGHASHPTR known_object_files = NULL;
|
||||||
#define DUMMYDATA ((void *)42)
|
#define DUMMYDATA ((void *)42)
|
||||||
/**
|
/**
|
||||||
|
|
@ -229,7 +246,8 @@ extern OsdiObjectFile load_object_file(const char *input) {
|
||||||
}
|
}
|
||||||
const char *path = resolve_input_path(input);
|
const char *path = resolve_input_path(input);
|
||||||
if (!path) {
|
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;
|
return INVALID_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,6 +279,37 @@ extern OsdiObjectFile load_object_file(const char *input) {
|
||||||
GET_CONST(OSDI_NUM_DESCRIPTORS, uint32_t);
|
GET_CONST(OSDI_NUM_DESCRIPTORS, uint32_t);
|
||||||
GET_PTR(OSDI_DESCRIPTORS, OsdiDescriptor);
|
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);
|
OsdiRegistryEntry *dst = TMALLOC(OsdiRegistryEntry, OSDI_NUM_DESCRIPTORS);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < OSDI_NUM_DESCRIPTORS; i++) {
|
for (uint32_t i = 0; i < OSDI_NUM_DESCRIPTORS; i++) {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
static int init_matrix(SMPmatrix *matrix, const OsdiDescriptor *descr,
|
||||||
void *inst) {
|
void *inst) {
|
||||||
uint32_t *node_mapping =
|
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);
|
uint32_t *node_ids = TMALLOC(uint32_t, descr->num_nodes);
|
||||||
|
|
||||||
/* determine the number of states required by each instance */
|
/* 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++) {
|
for (uint32_t i = 0; i < descr->num_nodes; i++) {
|
||||||
if (descr->nodes[i].react_residual_off != UINT32_MAX) {
|
if (descr->nodes[i].react_residual_off != UINT32_MAX) {
|
||||||
num_states += 2;
|
num_states += 2;
|
||||||
|
|
@ -269,6 +279,7 @@ int OSDIsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
|
||||||
|
|
||||||
/* reserve space in the state vector*/
|
/* reserve space in the state vector*/
|
||||||
gen_inst->GENstate = *states;
|
gen_inst->GENstate = *states;
|
||||||
|
write_state_ids(descr, inst, (uint32_t)*states);
|
||||||
*states += num_states;
|
*states += num_states;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,8 +86,9 @@ ACan(CKTcircuit *ckt, int restart)
|
||||||
fprintf(stderr, "ERROR: AC startfreq <= 0\n");
|
fprintf(stderr, "ERROR: AC startfreq <= 0\n");
|
||||||
return E_PARMVAL;
|
return E_PARMVAL;
|
||||||
}
|
}
|
||||||
job->ACfreqDelta =
|
double num_steps = floor(fabs(log10(job->ACstopFreq/job->ACstartFreq))*job->ACnumberSteps);
|
||||||
exp(log(10.0)/job->ACnumberSteps);
|
job->ACfreqDelta = exp((log(job->ACstopFreq/job->ACstartFreq))/ num_steps);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case OCTAVE:
|
case OCTAVE:
|
||||||
if (job->ACstartFreq <= 0) {
|
if (job->ACstartFreq <= 0) {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ extern uint32_t OSDI_VERSION_MAJOR;
|
||||||
extern uint32_t OSDI_VERSION_MINOR;
|
extern uint32_t OSDI_VERSION_MINOR;
|
||||||
extern uint32_t OSDI_NUM_DESCRIPTORS;
|
extern uint32_t OSDI_NUM_DESCRIPTORS;
|
||||||
extern OsdiDescriptor OSDI_DESCRIPTORS[1];
|
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
|
#define IGNORE(x) (void)x
|
||||||
|
|
||||||
|
|
@ -88,6 +92,10 @@ typedef struct DiodeInstace {
|
||||||
bool mfactor_given;
|
bool mfactor_given;
|
||||||
double temperature;
|
double temperature;
|
||||||
double residual_resist[NUM_NODES];
|
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_A;
|
||||||
double residual_react_CI;
|
double residual_react_CI;
|
||||||
double jacobian_resist[NUM_MATRIX];
|
double jacobian_resist[NUM_MATRIX];
|
||||||
|
|
@ -96,6 +104,7 @@ typedef struct DiodeInstace {
|
||||||
double *jacobian_ptr_resist[NUM_MATRIX];
|
double *jacobian_ptr_resist[NUM_MATRIX];
|
||||||
double *jacobian_ptr_react[NUM_MATRIX];
|
double *jacobian_ptr_react[NUM_MATRIX];
|
||||||
uint32_t node_off[NUM_NODES];
|
uint32_t node_off[NUM_NODES];
|
||||||
|
uint32_t state_idx;
|
||||||
} DiodeInstace;
|
} DiodeInstace;
|
||||||
|
|
||||||
#define EXP_LIM 80.0
|
#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};
|
*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
|
// implementation of the eval function as defined in the OSDI spec
|
||||||
static uint32_t eval(void *handle, void *inst_, void *model_,
|
static uint32_t eval(void *handle, void *inst_, void *model_,
|
||||||
OsdiSimInfo *info) {
|
OsdiSimInfo *info) {
|
||||||
|
|
@ -297,6 +309,7 @@ static uint32_t eval(void *handle, void *inst_, void *model_,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ret_flags = 0;
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// evaluate model equations
|
// 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 is_t = model->Is * pow(tdev_tnom, model->zetais);
|
||||||
double vt = t_dev * pk / pq;
|
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
|
// derivatives w.r.t. temperature
|
||||||
double rs_dt = model->zetars * model->Rs *
|
double rs_dt = model->zetars * model->Rs *
|
||||||
pow(tdev_tnom, model->zetars - 1.0) / model->Tnom;
|
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;
|
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) {
|
if (info->flags & CALC_REACT_RESIDUAL) {
|
||||||
// write react rhs
|
// write react rhs
|
||||||
inst->residual_react_A = qd * mfactor;
|
inst->residual_react_A = qd * mfactor;
|
||||||
inst->residual_react_CI = -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
|
// write Jacobian
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
@ -449,7 +490,7 @@ static uint32_t eval(void *handle, void *inst_, void *model_,
|
||||||
inst->jacobian_react[CI_TNODE] = -qd_dtj * mfactor;
|
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
|
// 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;
|
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) \
|
#define LOAD_MATRIX_RESIST(name) \
|
||||||
*inst->jacobian_ptr_resist[name] += inst->jacobian_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 vc = prev_solve[inst->node_off[C]];
|
||||||
double vdtj = prev_solve[inst->node_off[TNODE]];
|
double vdtj = prev_solve[inst->node_off[TNODE]];
|
||||||
|
|
||||||
dst[inst->node_off[A]] +=
|
dst[inst->node_off[A]] += inst->jacobian_resist[A_A] * va +
|
||||||
inst->jacobian_resist[A_A] * va + inst->jacobian_resist[A_TNODE] * vdtj +
|
inst->jacobian_resist[A_TNODE] * vdtj +
|
||||||
inst->jacobian_resist[A_CI] * vci - inst->residual_resist[A];
|
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 +
|
dst[inst->node_off[CI]] += inst->jacobian_resist[CI_A] * va +
|
||||||
inst->jacobian_resist[CI_TNODE] * vdtj +
|
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];
|
inst->residual_resist[CI];
|
||||||
|
|
||||||
dst[inst->node_off[C]] +=
|
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);
|
load_spice_rhs_dc(inst_, model, dst, prev_solve);
|
||||||
|
|
||||||
// add contributions due to reactive elements
|
// add contributions due to reactive elements
|
||||||
dst[inst->node_off[A]] += alpha * (inst->jacobian_react[A_A] * va +
|
dst[inst->node_off[A]] +=
|
||||||
inst->jacobian_react[A_CI] * vci +
|
alpha *
|
||||||
inst->jacobian_react[A_TNODE] * vdtj);
|
(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 +
|
dst[inst->node_off[CI]] +=
|
||||||
inst->jacobian_react[CI_A] * va +
|
alpha *
|
||||||
inst->jacobian_react[CI_TNODE] * vdtj);
|
(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) \
|
#define RESIST_RESIDUAL_OFF(NODE) \
|
||||||
|
|
@ -640,8 +704,8 @@ const OsdiNode nodes[NUM_NODES] = {
|
||||||
#define JACOBI_ENTRY(N1, N2) \
|
#define JACOBI_ENTRY(N1, N2) \
|
||||||
{ \
|
{ \
|
||||||
.nodes = {N1, N2}, .flags = JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT, \
|
.nodes = {N1, N2}, .flags = JACOBIAN_ENTRY_RESIST | JACOBIAN_ENTRY_REACT, \
|
||||||
.react_ptr_off = \
|
.react_ptr_off = offsetof(DiodeInstace, jacobian_ptr_react) + \
|
||||||
offsetof(DiodeInstace, jacobian_ptr_react) + sizeof(double*) * N1##_##N2 \
|
sizeof(double *) * N1##_##N2 \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RESIST_JACOBI_ENTRY(N1, N2) \
|
#define RESIST_JACOBI_ENTRY(N1, N2) \
|
||||||
|
|
@ -813,21 +877,30 @@ OsdiDescriptor OSDI_DESCRIPTORS[1] = {{
|
||||||
// step size bound
|
// step size bound
|
||||||
.bound_step_offset = UINT32_MAX,
|
.bound_step_offset = UINT32_MAX,
|
||||||
|
|
||||||
|
.num_states = 1,
|
||||||
|
.state_idx_off = offsetof(DiodeInstace, state_idx),
|
||||||
|
|
||||||
// memory
|
// memory
|
||||||
.instance_size = sizeof(DiodeInstace),
|
.instance_size = sizeof(DiodeInstace),
|
||||||
.model_size = sizeof(DiodeModel),
|
.model_size = sizeof(DiodeModel),
|
||||||
|
|
||||||
// setup
|
// setup
|
||||||
.access = &osdi_access,
|
.access = osdi_access,
|
||||||
.setup_model = &setup_model,
|
.setup_model = setup_model,
|
||||||
.setup_instance = &setup_instance,
|
.setup_instance = setup_instance,
|
||||||
.eval = &eval,
|
.eval = eval,
|
||||||
.load_noise = &load_noise,
|
.load_noise = load_noise,
|
||||||
.load_residual_resist = &load_residual_resist,
|
.load_residual_resist = load_residual_resist,
|
||||||
.load_residual_react = &load_residual_react,
|
.load_residual_react = load_residual_react,
|
||||||
.load_spice_rhs_dc = &load_spice_rhs_dc,
|
.load_spice_rhs_dc = load_spice_rhs_dc,
|
||||||
.load_spice_rhs_tran = &load_spice_rhs_tran,
|
.load_spice_rhs_tran = load_spice_rhs_tran,
|
||||||
.load_jacobian_resist = &load_jacobian_resist,
|
.load_jacobian_resist = load_jacobian_resist,
|
||||||
.load_jacobian_react = &load_jacobian_react,
|
.load_jacobian_react = load_jacobian_react,
|
||||||
.load_jacobian_tran = &load_jacobian_tran,
|
.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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue