210 lines
6.4 KiB
C
210 lines
6.4 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/stringutil.h"
|
|
|
|
#include "ngspice/config.h"
|
|
#include "ngspice/devdefs.h"
|
|
#include "ngspice/iferrmsg.h"
|
|
#include "ngspice/memory.h"
|
|
#include "ngspice/ngspice.h"
|
|
#include "ngspice/typedefs.h"
|
|
|
|
#include "osdi.h"
|
|
#include "osdidefs.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
/*
|
|
* This function converts the information in (a list of) OsdiParamOpvar in
|
|
* descr->param_opvar to the internal ngspice representation (IFparm).
|
|
*/
|
|
static int write_param_info(IFparm **dst, const OsdiDescriptor *descr,
|
|
uint32_t start, uint32_t end, bool has_m) {
|
|
for (uint32_t i = start; i < end; i++) {
|
|
OsdiParamOpvar *para = &descr->param_opvar[i];
|
|
uint32_t num_names = para->num_alias + 1;
|
|
|
|
int dataType = IF_ASK;
|
|
if ((para->flags & (uint32_t)PARA_KIND_OPVAR) == 0) {
|
|
dataType |= IF_SET;
|
|
}
|
|
|
|
switch (para->flags & PARA_TY_MASK) {
|
|
case PARA_TY_REAL:
|
|
dataType |= IF_REAL;
|
|
break;
|
|
case PARA_TY_INT:
|
|
dataType |= IF_INTEGER;
|
|
break;
|
|
case PARA_TY_STR:
|
|
dataType |= IF_STRING;
|
|
break;
|
|
default:
|
|
errRtn = "get_osdi_info";
|
|
errMsg = tprintf("Unknown OSDI type %d for parameter %s!",
|
|
para->flags & PARA_TY_MASK, para->name[0]);
|
|
return -1;
|
|
}
|
|
|
|
if (para->len != 0) {
|
|
dataType |= IF_VECTOR;
|
|
}
|
|
|
|
for (uint32_t j = 0; j < num_names; j++) {
|
|
if (j != 0) {
|
|
dataType |= IF_UNINTERESTING;
|
|
}
|
|
char *para_name = copy(para->name[j]);
|
|
if (para_name[0] == '$') {
|
|
para_name[0] = '_';
|
|
}
|
|
strtolower(para_name);
|
|
(*dst)[j] = (IFparm){.keyword = para_name,
|
|
.id = (int)i,
|
|
.description = para->description,
|
|
.dataType = dataType};
|
|
}
|
|
if (!has_m && !strcmp(para->name[0], "$mfactor")) {
|
|
(*dst)[num_names] = (IFparm){.keyword = "m",
|
|
.id = (int)i,
|
|
.description = para->description,
|
|
.dataType = dataType};
|
|
*dst += 1;
|
|
}
|
|
|
|
*dst += num_names;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/**
|
|
* This function creates a SPICEdev instance for a specific OsdiDescriptor by
|
|
* populating the SPICEdev struct with descriptor specific metadata and pointers
|
|
* to the descriptor independent functions.
|
|
* */
|
|
extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry) {
|
|
const OsdiDescriptor *descr = entry->descriptor;
|
|
|
|
// allocate and fill terminal names array
|
|
char **termNames = TMALLOC(char *, descr->num_terminals);
|
|
for (uint32_t i = 0; i < descr->num_terminals; i++) {
|
|
termNames[i] = descr->nodes[i].name;
|
|
}
|
|
|
|
// allocate and fill instance params (and opvars)
|
|
int *num_instance_para_names = TMALLOC(int, 1);
|
|
for (uint32_t i = 0; i < descr->num_instance_params; i++) {
|
|
*num_instance_para_names += (int)(1 + descr->param_opvar[i].num_alias);
|
|
}
|
|
for (uint32_t i = descr->num_params;
|
|
i < descr->num_opvars + descr->num_params; i++) {
|
|
*num_instance_para_names += (int)(1 + descr->param_opvar[i].num_alias);
|
|
}
|
|
if (entry->dt != UINT32_MAX) {
|
|
*num_instance_para_names += 1;
|
|
}
|
|
|
|
if (entry->temp != UINT32_MAX) {
|
|
*num_instance_para_names += 1;
|
|
}
|
|
|
|
if (!entry->has_m) {
|
|
*num_instance_para_names += 1;
|
|
}
|
|
|
|
IFparm *instance_para_names = TMALLOC(IFparm, *num_instance_para_names);
|
|
IFparm *dst = instance_para_names;
|
|
|
|
if (entry->dt != UINT32_MAX) {
|
|
dst[0] = (IFparm){"dt", (int)entry->dt, IF_REAL | IF_SET,
|
|
"Instance delta temperature"};
|
|
dst += 1;
|
|
}
|
|
|
|
if (entry->temp != UINT32_MAX) {
|
|
dst[0] = (IFparm){"temp", (int)entry->temp, IF_REAL | IF_SET,
|
|
"Instance temperature"};
|
|
dst += 1;
|
|
}
|
|
write_param_info(&dst, descr, 0, descr->num_instance_params, entry->has_m);
|
|
write_param_info(&dst, descr, descr->num_params,
|
|
descr->num_params + descr->num_opvars, true);
|
|
|
|
// allocate and fill model params
|
|
int *num_model_para_names = TMALLOC(int, 1);
|
|
for (uint32_t i = descr->num_instance_params; i < descr->num_params; i++) {
|
|
*num_model_para_names += (int)(1 + descr->param_opvar[i].num_alias);
|
|
}
|
|
IFparm *model_para_names = TMALLOC(IFparm, *num_model_para_names);
|
|
dst = model_para_names;
|
|
write_param_info(&dst, descr, descr->num_instance_params, descr->num_params,
|
|
true);
|
|
|
|
// Allocate SPICE device
|
|
SPICEdev *OSDIinfo = TMALLOC(SPICEdev, 1);
|
|
|
|
// fill information
|
|
OSDIinfo->DEVpublic = (IFdevice){
|
|
.name = descr->name,
|
|
.description = "A simulator independent device loaded with OSDI",
|
|
// TODO why extra indirection? Optional ports?
|
|
.terms = (int *)&descr->num_terminals,
|
|
.numNames = (int *)&descr->num_terminals,
|
|
.termNames = termNames,
|
|
.numInstanceParms = num_instance_para_names,
|
|
.instanceParms = instance_para_names,
|
|
.numModelParms = num_model_para_names,
|
|
.modelParms = model_para_names,
|
|
.flags = DEV_DEFAULT,
|
|
.registry_entry = (void *)entry,
|
|
};
|
|
|
|
size_t inst_off = entry->inst_offset;
|
|
|
|
int *inst_size = TMALLOC(int, 1);
|
|
*inst_size =
|
|
(int)(inst_off + descr->instance_size + sizeof(OsdiExtraInstData));
|
|
OSDIinfo->DEVinstSize = inst_size;
|
|
|
|
size_t model_off = osdi_model_data_off();
|
|
int *model_size = TMALLOC(int, 1);
|
|
*model_size = (int)(model_off + descr->model_size);
|
|
OSDIinfo->DEVmodSize = model_size;
|
|
|
|
// fill generic functions
|
|
OSDIinfo->DEVparam = OSDIparam;
|
|
OSDIinfo->DEVmodParam = OSDImParam;
|
|
OSDIinfo->DEVask = OSDIask;
|
|
OSDIinfo->DEVmodAsk = OSDImAsk;
|
|
OSDIinfo->DEVsetup = OSDIsetup;
|
|
OSDIinfo->DEVpzSetup = OSDIsetup;
|
|
OSDIinfo->DEVtemperature = OSDItemp;
|
|
OSDIinfo->DEVunsetup = OSDIunsetup;
|
|
OSDIinfo->DEVload = OSDIload;
|
|
OSDIinfo->DEVacLoad = OSDIacLoad;
|
|
OSDIinfo->DEVpzLoad = OSDIpzLoad;
|
|
OSDIinfo->DEVtrunc = OSDItrunc;
|
|
OSDIinfo->DEVnoise = OSDInoise;
|
|
|
|
#ifdef KLU
|
|
OSDIinfo->DEVbindCSC = OSDIbindCSC;
|
|
OSDIinfo->DEVbindCSCComplex = OSDIbindCSCComplex;
|
|
OSDIinfo->DEVbindCSCComplexToReal = OSDIbindCSCComplexToReal;
|
|
#endif
|
|
|
|
return OSDIinfo;
|
|
}
|