185 lines
4.9 KiB
C
185 lines
4.9 KiB
C
/*
|
|
* This file is part of the OSDI component of NGSPICE.
|
|
* Copyright© 2022 SemiMod GmbH.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Author: Pascal Kuthe <pascal.kuthe@semimod.de>
|
|
*/
|
|
|
|
#include "ngspice/iferrmsg.h"
|
|
#include "ngspice/ngspice.h"
|
|
#include "ngspice/typedefs.h"
|
|
|
|
#include "osdidefs.h"
|
|
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
static int osdi_param_access(OsdiParamOpvar *param_info, bool write_value,
|
|
IFvalue *value, void *ptr) {
|
|
size_t len;
|
|
void *val_ptr;
|
|
switch (param_info->flags & PARA_TY_MASK) {
|
|
case PARA_TY_REAL:
|
|
len = sizeof(double);
|
|
if (param_info->len) {
|
|
len *= param_info->len;
|
|
val_ptr = value->v.vec.rVec;
|
|
} else {
|
|
val_ptr = &value->rValue;
|
|
}
|
|
break;
|
|
case PARA_TY_INT:
|
|
len = sizeof(int);
|
|
if (param_info->len) {
|
|
len *= param_info->len;
|
|
val_ptr = value->v.vec.iVec;
|
|
} else {
|
|
val_ptr = &value->iValue;
|
|
}
|
|
break;
|
|
case PARA_TY_STR:
|
|
len = sizeof(char *);
|
|
if (param_info->len) {
|
|
len *= param_info->len;
|
|
val_ptr = value->v.vec.cVec;
|
|
} else {
|
|
val_ptr = &value->cValue;
|
|
}
|
|
break;
|
|
default:
|
|
return (E_PARMVAL);
|
|
}
|
|
if (write_value) {
|
|
memcpy(val_ptr, ptr, len);
|
|
} else {
|
|
memcpy(ptr, val_ptr, len);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int osdi_write_param(void *dst, IFvalue *value, int param,
|
|
const OsdiDescriptor *descr) {
|
|
// value may be NULL as a result of a bad parse from INPgetValue
|
|
// catch it before dereferencing it
|
|
if (dst == NULL || value == NULL) {
|
|
return (E_PANIC);
|
|
}
|
|
|
|
OsdiParamOpvar *param_info = &descr->param_opvar[param];
|
|
|
|
if (param_info->len) {
|
|
if ((uint32_t)value->v.numValue != param_info->len) {
|
|
return (E_PARMVAL);
|
|
}
|
|
}
|
|
|
|
return osdi_param_access(param_info, false, value, dst);
|
|
}
|
|
|
|
extern int OSDIparam(int param, IFvalue *value, GENinstance *instPtr,
|
|
IFvalue *select) {
|
|
|
|
NG_IGNORE(select);
|
|
OsdiRegistryEntry *entry = osdi_reg_entry_inst(instPtr);
|
|
const OsdiDescriptor *descr = entry->descriptor;
|
|
|
|
if (param >= (int)descr->num_instance_params) {
|
|
// special handling for temperature parameters
|
|
OsdiExtraInstData *inst = osdi_extra_instance_data(entry, instPtr);
|
|
if (param == (int)entry->dt) {
|
|
inst->dt = value->rValue;
|
|
inst->dt_given = true;
|
|
return (OK);
|
|
}
|
|
if (param == (int)entry->temp) {
|
|
inst->temp = value->rValue;
|
|
inst->temp_given = true;
|
|
return (OK);
|
|
}
|
|
|
|
return (E_BADPARM);
|
|
}
|
|
|
|
void *inst = osdi_instance_data(entry, instPtr);
|
|
void *dst = descr->access(inst, NULL, (uint32_t)param,
|
|
ACCESS_FLAG_SET | ACCESS_FLAG_INSTANCE);
|
|
|
|
return osdi_write_param(dst, value, param, descr);
|
|
}
|
|
|
|
extern int OSDImParam(int param, IFvalue *value, GENmodel *modelPtr) {
|
|
OsdiRegistryEntry *entry = osdi_reg_entry_model(modelPtr);
|
|
const OsdiDescriptor *descr = entry->descriptor;
|
|
|
|
if (param > (int)descr->num_params ||
|
|
param < (int)descr->num_instance_params) {
|
|
return (E_BADPARM);
|
|
}
|
|
|
|
void *model = osdi_model_data(modelPtr);
|
|
void *dst = descr->access(NULL, model, (uint32_t)param, ACCESS_FLAG_SET);
|
|
|
|
return osdi_write_param(dst, value, param, descr);
|
|
}
|
|
|
|
static int osdi_read_param(void *src, IFvalue *value, int id,
|
|
const OsdiDescriptor *descr) {
|
|
if (src == NULL || value == NULL) {
|
|
return (E_PANIC);
|
|
}
|
|
|
|
OsdiParamOpvar *param_info = &descr->param_opvar[id];
|
|
|
|
if (param_info->len) {
|
|
value->v.numValue = (int)param_info->len;
|
|
}
|
|
|
|
return osdi_param_access(param_info, true, value, src);
|
|
}
|
|
|
|
extern int OSDIask(CKTcircuit *ckt, GENinstance *instPtr, int id,
|
|
IFvalue *value, IFvalue *select) {
|
|
NG_IGNORE(select);
|
|
NG_IGNORE(ckt);
|
|
|
|
OsdiRegistryEntry *entry = osdi_reg_entry_inst(instPtr);
|
|
void *inst = osdi_instance_data(entry, instPtr);
|
|
void *model = osdi_model_data_from_inst(instPtr);
|
|
|
|
const OsdiDescriptor *descr = entry->descriptor;
|
|
|
|
if (id >= (int)(descr->num_params + descr->num_opvars)) {
|
|
return (E_BADPARM);
|
|
}
|
|
uint32_t flags = ACCESS_FLAG_READ;
|
|
if (id < (int)descr->num_instance_params) {
|
|
flags |= ACCESS_FLAG_INSTANCE;
|
|
}
|
|
|
|
void *src = descr->access(inst, model, (uint32_t)id, flags);
|
|
return osdi_read_param(src, value, id, descr);
|
|
}
|
|
|
|
extern int OSDImAsk(CKTcircuit *ckt, GENmodel *modelPtr, int id,
|
|
IFvalue *value) {
|
|
|
|
NG_IGNORE(ckt);
|
|
|
|
OsdiRegistryEntry *entry = osdi_reg_entry_model(modelPtr);
|
|
const OsdiDescriptor *descr = entry->descriptor;
|
|
|
|
void *model = osdi_model_data(modelPtr);
|
|
|
|
if (id >= (int)(descr->num_params)) {
|
|
return (E_BADPARM);
|
|
}
|
|
|
|
void *src = descr->access(NULL, model, (uint32_t)id, ACCESS_FLAG_READ);
|
|
return osdi_read_param(src, value, id, descr);
|
|
}
|