add openmp support for osdi
This commit is contained in:
parent
95712ea48a
commit
23e9d417a4
|
|
@ -189,7 +189,7 @@ typedef struct OsdiDescriptor {
|
|||
double temperature, uint32_t num_terminals,
|
||||
OsdiSimParas *sim_params, OsdiInitInfo *res);
|
||||
|
||||
uint32_t (*eval)(void *handle, void *inst, void *model, OsdiSimInfo *info);
|
||||
uint32_t (*eval)(void *handle, void *inst, void *model, const OsdiSimInfo *info);
|
||||
void (*load_noise)(void *inst, void *model, double freq, double *noise_dens,
|
||||
double *ln_noise_dens);
|
||||
void (*load_residual_resist)(void *inst, void* model, double *dst);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ typedef struct OsdiExtraInstData {
|
|||
double temp;
|
||||
bool temp_given;
|
||||
bool dt_given;
|
||||
bool finish;
|
||||
uint32_t eval_flags;
|
||||
|
||||
} ALIGN(MAX_ALIGN) OsdiExtraInstData;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,11 +28,10 @@ char *sim_params[NUM_SIM_PARAMS + 1] = {
|
|||
"gdev", "gmin", "tnom", "simulatorVersion", "sourceScaleFactor", NULL};
|
||||
char *sim_params_str[1] = {NULL};
|
||||
|
||||
double sim_param_vals[NUM_SIM_PARAMS] = {0,0,0,0,0};
|
||||
double sim_param_vals[NUM_SIM_PARAMS] = {0, 0, 0, 0, 0};
|
||||
|
||||
/* values returned by $simparam*/
|
||||
OsdiSimParas get_simparams(const CKTcircuit *ckt) {
|
||||
|
||||
double simulatorVersion = strtod(PACKAGE_VERSION, NULL);
|
||||
double gdev = ckt->CKTgmin;
|
||||
double sourceScaleFactor = ckt->CKTsrcFact;
|
||||
|
|
@ -48,6 +47,71 @@ OsdiSimParas get_simparams(const CKTcircuit *ckt) {
|
|||
return sim_params_;
|
||||
}
|
||||
|
||||
static void eval(const OsdiDescriptor *descr, const GENinstance *gen_inst,
|
||||
void *inst, OsdiExtraInstData *extra_inst_data,
|
||||
const void *model, const OsdiSimInfo *sim_info) {
|
||||
|
||||
OsdiNgspiceHandle handle =
|
||||
(OsdiNgspiceHandle){.kind = 3, .name = gen_inst->GENname};
|
||||
/* TODO initial conditions? */
|
||||
extra_inst_data->eval_flags = descr->eval(&handle, inst, model, sim_info);
|
||||
}
|
||||
|
||||
static void load(CKTcircuit *ckt, const GENinstance *gen_inst, void *model,
|
||||
void *inst, OsdiExtraInstData *extra_inst_data, bool is_tran,
|
||||
bool is_init_tran, const OsdiDescriptor *descr) {
|
||||
double dump;
|
||||
if (is_tran) {
|
||||
/* load dc matrix and capacitances (charge derivative multiplied with
|
||||
* CKTag[0]) */
|
||||
descr->load_jacobian_tran(inst, model, ckt->CKTag[0]);
|
||||
|
||||
/* load static rhs and dynamic linearized rhs (SUM Vb * dIa/dVb)*/
|
||||
descr->load_spice_rhs_tran(inst, model, ckt->CKTrhs, ckt->CKTrhsOld,
|
||||
ckt->CKTag[0]);
|
||||
|
||||
uint32_t *node_mapping =
|
||||
(uint32_t *)(((char *)inst) + descr->node_mapping_offset);
|
||||
|
||||
/* use numeric integration to obtain the remainer of the RHS*/
|
||||
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) {
|
||||
|
||||
double residual_react =
|
||||
*((double *)(((char *)inst) + descr->nodes[i].react_residual_off));
|
||||
|
||||
/* store charges in state vector*/
|
||||
ckt->CKTstate0[state] = residual_react;
|
||||
if (is_init_tran) {
|
||||
ckt->CKTstate1[state] = residual_react;
|
||||
}
|
||||
|
||||
/* we only care about the numeric integration itself not ceq/geq
|
||||
because those are already calculated by load_jacobian_tran and
|
||||
load_spice_rhs_tran*/
|
||||
NIintegrate(ckt, &dump, &dump, 0, state);
|
||||
|
||||
/* add the numeric derivative to the rhs */
|
||||
ckt->CKTrhs[node_mapping[i]] -= ckt->CKTstate0[state + 1];
|
||||
|
||||
if (is_init_tran) {
|
||||
ckt->CKTstate1[state + 1] = ckt->CKTstate0[state + 1];
|
||||
}
|
||||
|
||||
state += 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* copy internal derivatives into global matrix */
|
||||
descr->load_jacobian_resist(inst, model);
|
||||
|
||||
/* calculate spice RHS from internal currents and store into global RHS
|
||||
*/
|
||||
descr->load_spice_rhs_dc(inst, model, ckt->CKTrhs, ckt->CKTrhsOld);
|
||||
}
|
||||
}
|
||||
|
||||
extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
||||
OsdiNgspiceHandle handle;
|
||||
GENmodel *gen_model;
|
||||
|
|
@ -113,6 +177,35 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
|
||||
OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
uint32_t eval_flags = 0;
|
||||
|
||||
#ifdef USE_OMP
|
||||
/* use openmp 3.0 tasks to parallelize linked list transveral */
|
||||
#pragma omp parallel
|
||||
#pragma omp single
|
||||
{
|
||||
for (gen_model = inModel; gen_model; gen_model = gen_model->GENnextModel) {
|
||||
void *model = osdi_model_data(gen_model);
|
||||
|
||||
for (gen_inst = gen_model->GENinstances; gen_inst;
|
||||
gen_inst = gen_inst->GENnextInstance) {
|
||||
|
||||
void *inst = osdi_instance_data(entry, gen_inst);
|
||||
|
||||
OsdiExtraInstData *extra_inst_data =
|
||||
osdi_extra_instance_data(entry, gen_inst);
|
||||
|
||||
#pragma omp task firstprivate(gen_inst, inst, extra_inst_data, model)
|
||||
eval(descr, gen_inst, inst, extra_inst_data, model, &sim_info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* init small signal analysis does not require loading values into
|
||||
* matrix/rhs*/
|
||||
if (is_init_smsig) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (gen_model = inModel; gen_model; gen_model = gen_model->GENnextModel) {
|
||||
void *model = osdi_model_data(gen_model);
|
||||
|
|
@ -120,92 +213,49 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
for (gen_inst = gen_model->GENinstances; gen_inst;
|
||||
gen_inst = gen_inst->GENnextInstance) {
|
||||
void *inst = osdi_instance_data(entry, gen_inst);
|
||||
OsdiExtraInstData *extra_inst_data =
|
||||
osdi_extra_instance_data(entry, gen_inst);
|
||||
load(ckt, gen_inst, model, inst, extra_inst_data, is_tran, is_init_tran,
|
||||
descr);
|
||||
eval_flags |= extra_inst_data->eval_flags;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (gen_model = inModel; gen_model; gen_model = gen_model->GENnextModel) {
|
||||
void *model = osdi_model_data(gen_model);
|
||||
|
||||
/* hpyothetically this could run in parallel we do not write any shared
|
||||
data here*/
|
||||
handle = (OsdiNgspiceHandle){.kind = 3, .name = gen_inst->GENname};
|
||||
/* TODO initial conditions? */
|
||||
uint32_t ret_flags = descr->eval(&handle, inst, model, &sim_info);
|
||||
for (gen_inst = gen_model->GENinstances; gen_inst;
|
||||
gen_inst = gen_inst->GENnextInstance) {
|
||||
void *inst = osdi_instance_data(entry, gen_inst);
|
||||
|
||||
/* call to $fatal in Verilog-A abort!*/
|
||||
if (ret_flags & EVAL_RET_FLAG_FATAL) {
|
||||
return E_PANIC;
|
||||
}
|
||||
OsdiExtraInstData *extra_inst_data =
|
||||
osdi_extra_instance_data(entry, gen_inst);
|
||||
eval(descr, gen_inst, inst, extra_inst_data, model, &sim_info);
|
||||
|
||||
/* init small signal analysis does not require loading values into
|
||||
* matrix/rhs*/
|
||||
if (is_init_smsig) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* handle calls to $finish, $limit, $stop
|
||||
* TODO actually do something with extra_inst_data->finish and
|
||||
* extra_inst_data->limt
|
||||
* */
|
||||
OsdiExtraInstData *extra_inst_data =
|
||||
osdi_extra_instance_data(entry, gen_inst);
|
||||
if (ret_flags & EVAL_RET_FLAG_FINISH) {
|
||||
extra_inst_data->finish = true;
|
||||
}
|
||||
if (ret_flags & EVAL_RET_FLAG_LIM) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = gen_inst;
|
||||
|
||||
}
|
||||
if (ret_flags & EVAL_RET_FLAG_STOP) {
|
||||
ret = (E_PAUSE);
|
||||
}
|
||||
|
||||
if (is_tran) {
|
||||
/* load dc matrix and capacitances (charge derivative multiplied with
|
||||
* CKTag[0]) */
|
||||
descr->load_jacobian_tran(inst, model, ckt->CKTag[0]);
|
||||
|
||||
/* load static rhs and dynamic linearized rhs (SUM Vb * dIa/dVb)*/
|
||||
descr->load_spice_rhs_tran(inst, model, ckt->CKTrhs, ckt->CKTrhsOld,
|
||||
ckt->CKTag[0]);
|
||||
|
||||
uint32_t *node_mapping =
|
||||
(uint32_t *)(((char *)inst) + descr->node_mapping_offset);
|
||||
|
||||
/* use numeric integration to obtain the remainer of the RHS*/
|
||||
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) {
|
||||
|
||||
double residual_react = *((
|
||||
double *)(((char *)inst) + descr->nodes[i].react_residual_off));
|
||||
|
||||
/* store charges in state vector*/
|
||||
ckt->CKTstate0[state] = residual_react;
|
||||
if (is_init_tran) {
|
||||
ckt->CKTstate1[state] = residual_react;
|
||||
}
|
||||
|
||||
/* we only care about the numeric integration itself not ceq/geq
|
||||
because those are already calculated by load_jacobian_tran and
|
||||
load_spice_rhs_tran*/
|
||||
NIintegrate(ckt, &dump, &dump, 0, state);
|
||||
|
||||
/* add the numeric derivative to the rhs */
|
||||
ckt->CKTrhs[node_mapping[i]] -= ckt->CKTstate0[state + 1];
|
||||
|
||||
if (is_init_tran) {
|
||||
ckt->CKTstate1[state + 1] = ckt->CKTstate0[state + 1];
|
||||
}
|
||||
|
||||
state += 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* copy internal derivatives into global matrix */
|
||||
descr->load_jacobian_resist(inst, model);
|
||||
|
||||
/* calculate spice RHS from internal currents and store into global RHS
|
||||
*/
|
||||
descr->load_spice_rhs_dc(inst, model, ckt->CKTrhs, ckt->CKTrhsOld);
|
||||
if (!is_init_smsig) {
|
||||
load(ckt, gen_inst, model, inst, extra_inst_data, is_tran, is_init_tran,
|
||||
descr);
|
||||
eval_flags |= extra_inst_data->eval_flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
/* call to $fatal in Verilog-A abort simulation!*/
|
||||
if (eval_flags & EVAL_RET_FLAG_FATAL) {
|
||||
return E_PANIC;
|
||||
}
|
||||
|
||||
if (eval_flags & EVAL_RET_FLAG_LIM) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = gen_inst;
|
||||
}
|
||||
|
||||
if (eval_flags & EVAL_RET_FLAG_STOP) {
|
||||
return E_PAUSE;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue