feat: use osdi command to load files
Previously OSDI shared object files were loaded from fixed directories. This was unreliable, inconvenient and caused conflicts with XSPICE. This commit remove the old loading mechanism and instead introduces the `osdi` command that can load (a list of) osdi object files (like the codemodel command for XSPICE). A typical usecase will use this as a precommand in the netlist: .control pre_osdi foo.osdi .endc If the specified file is a relative path it is first resolved relative to the parent directory of the netlist. If the osdi command is invoked from the interactive prompt the file is resolved relative to the current working directory instead. This commit also moves osdi from the devices folder to the root src folder like xspice. This better reflects the role of the code as users may otherthwise (mistakenly) assume that osdi is just another handwritten model.
This commit is contained in:
parent
4036e4ec26
commit
469dc127bf
12
configure.ac
12
configure.ac
|
|
@ -146,6 +146,10 @@ AC_ARG_ENABLE([oldapps],
|
|||
AC_ARG_ENABLE([xspice],
|
||||
[AS_HELP_STRING([--enable-xspice], [Enable XSPICE enhancements])])
|
||||
|
||||
# --enable-osdi: define OSDI in the code. This is for osdi support
|
||||
AC_ARG_ENABLE([osdi],
|
||||
[AS_HELP_STRING([--enable-osdi], [Enable OSDI integration])])
|
||||
|
||||
# --enable-cider: define CIDER in the code. This is for CIDER support
|
||||
AC_ARG_ENABLE([cider],
|
||||
[AS_HELP_STRING([--enable-cider], [Enable CIDER enhancements])])
|
||||
|
|
@ -1158,6 +1162,12 @@ AC_SUBST([XSPICEDLLIBS])
|
|||
|
||||
AM_CONDITIONAL([XSPICE_WANTED], [test "x$enable_xspice" = xyes])
|
||||
|
||||
if test "x$enable_osdi" = xyes; then
|
||||
AC_MSG_RESULT([OSDI features included])
|
||||
AC_DEFINE([OSDI], [1], [The OSDI enhancements])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([OSDI_WANTED], [test "x$enable_osdi" = xyes])
|
||||
|
||||
# Add CIDER enhancements to ngspice.
|
||||
if test "x$enable_cider" = xyes; then
|
||||
|
|
@ -1373,7 +1383,6 @@ AC_CONFIG_FILES([Makefile
|
|||
src/spicelib/devices/hfet1/Makefile
|
||||
src/spicelib/devices/hfet2/Makefile
|
||||
src/spicelib/devices/hicum2/Makefile
|
||||
src/spicelib/devices/osdi/Makefile
|
||||
src/spicelib/devices/hisim2/Makefile
|
||||
src/spicelib/devices/hisimhv1/Makefile
|
||||
src/spicelib/devices/hisimhv2/Makefile
|
||||
|
|
@ -1439,6 +1448,7 @@ AC_CONFIG_FILES([Makefile
|
|||
src/xspice/enh/Makefile
|
||||
src/xspice/ipc/Makefile
|
||||
src/xspice/idn/Makefile
|
||||
src/osdi/Makefile
|
||||
tests/Makefile
|
||||
tests/bsim1/Makefile
|
||||
tests/bsim2/Makefile
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ if XSPICE_WANTED
|
|||
SUBDIRS += xspice
|
||||
endif
|
||||
|
||||
if OSDI_WANTED
|
||||
SUBDIRS += osdi
|
||||
endif
|
||||
|
||||
if CIDER_WANTED
|
||||
SUBDIRS += ciderlib
|
||||
endif
|
||||
|
|
@ -70,7 +74,6 @@ DYNAMIC_DEVICELIBS = \
|
|||
spicelib/devices/hfet1/libhfet.la \
|
||||
spicelib/devices/hfet2/libhfet2.la \
|
||||
spicelib/devices/hicum2/libhicum2.la \
|
||||
spicelib/devices/osdi/libosdi.la \
|
||||
spicelib/devices/hisim2/libhisim2.la \
|
||||
spicelib/devices/hisimhv1/libhisimhv1.la \
|
||||
spicelib/devices/hisimhv2/libhisimhv2.la \
|
||||
|
|
@ -98,6 +101,8 @@ DYNAMIC_DEVICELIBS = \
|
|||
@VLADEV@
|
||||
|
||||
|
||||
|
||||
|
||||
## Build ngspice first:
|
||||
|
||||
## compile the icon:
|
||||
|
|
@ -176,6 +181,10 @@ ngspice_LDADD += \
|
|||
ciderlib/support/libcidersuprt.la
|
||||
endif
|
||||
|
||||
if OSDI_WANTED
|
||||
ngspice_LDADD += osdi/libosdi.la
|
||||
endif
|
||||
|
||||
ngspice_LDADD += \
|
||||
maths/deriv/libderiv.la \
|
||||
maths/cmaths/libcmaths.la \
|
||||
|
|
@ -458,6 +467,11 @@ libspice_la_LIBADD += \
|
|||
ciderlib/support/libcidersuprt.la
|
||||
endif
|
||||
|
||||
|
||||
if OSDI_WANTED
|
||||
libspice_la_LIBADD += osdi/libosdi.la
|
||||
endif
|
||||
|
||||
libspice_la_LIBADD += \
|
||||
maths/deriv/libderiv.la \
|
||||
maths/cmaths/libcmaths.la \
|
||||
|
|
@ -577,6 +591,9 @@ libngspice_la_LIBADD += \
|
|||
ciderlib/support/libcidersuprt.la
|
||||
endif
|
||||
|
||||
|
||||
libngspice_la_LIBADD += osdi/libosdi.la
|
||||
|
||||
libngspice_la_LIBADD += \
|
||||
maths/deriv/libderiv.la \
|
||||
maths/cmaths/libcmaths.la \
|
||||
|
|
|
|||
|
|
@ -18,6 +18,21 @@ void com_codemodel(wordlist *wl)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef OSDI
|
||||
void com_osdi(wordlist *wl)
|
||||
{
|
||||
wordlist *ww;
|
||||
for (ww = wl; ww; ww = ww->wl_next)
|
||||
if (load_osdi(ww->wl_word)) {
|
||||
fprintf(cp_err, "Error: Library %s couldn't be loaded!\n", ww->wl_word);
|
||||
if (ft_stricterror)
|
||||
controlled_exit(EXIT_BAD);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef DEVLIB
|
||||
void com_use(wordlist *wl)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@
|
|||
void com_codemodel(wordlist *wl);
|
||||
#endif
|
||||
|
||||
#ifdef OSDI
|
||||
void com_osdi(wordlist *wl);
|
||||
#endif
|
||||
|
||||
#ifdef DEVLIB
|
||||
void com_use(wordlist *wl);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -268,6 +268,12 @@ struct comm spcp_coms[] = {
|
|||
NULL,
|
||||
"library library ... : Loads the code model libraries." } ,
|
||||
#endif
|
||||
#ifdef OSDI
|
||||
{ "osdi", com_osdi, FALSE, TRUE,
|
||||
{ 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
|
||||
NULL,
|
||||
"library library ... : Loads a osdi library." } ,
|
||||
#endif
|
||||
#ifdef DEVLIB
|
||||
{ "use", com_use, FALSE, TRUE,
|
||||
{ 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS,
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ dgen_next(dgen **dgx)
|
|||
if (!dg->dev_list) {
|
||||
if ((dg->flags & DGEN_ALLDEVS) ||
|
||||
((dg->flags & DGEN_DEFDEVS) &&
|
||||
(ft_sim->devices[dg->dev_type_no]->flags & DEV_DEFAULT_CHECK)))
|
||||
(ft_sim->devices[dg->dev_type_no]->flags & DEV_DEFAULT)))
|
||||
{
|
||||
done = 1;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ Author: 1985 Wayne A. Christopher
|
|||
#include "ngspice/fteinp.h"
|
||||
#include "inp.h"
|
||||
|
||||
#include "ngspice/osdiitf.h"
|
||||
#include "runcoms.h"
|
||||
#include "inpcom.h"
|
||||
#include "circuits.h"
|
||||
|
|
@ -570,7 +571,6 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
if (fp) {
|
||||
cp_vset("inputdir", CP_STRING, dir_name);
|
||||
}
|
||||
tfree(dir_name);
|
||||
|
||||
/* if nothing came back from inp_readall, e.g. after calling ngspice without parameters,
|
||||
just close fp and return to caller */
|
||||
|
|
@ -745,8 +745,16 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
before the circuit structure is set up */
|
||||
if (pre_controls) {
|
||||
pre_controls = wl_reverse(pre_controls);
|
||||
for (wl = pre_controls; wl; wl = wl->wl_next)
|
||||
for (wl = pre_controls; wl; wl = wl->wl_next){
|
||||
#ifdef OSDI
|
||||
inputdir = dir_name;
|
||||
#endif
|
||||
cp_evloop(wl->wl_word);
|
||||
}
|
||||
|
||||
#ifdef OSDI
|
||||
inputdir = NULL;
|
||||
#endif
|
||||
wl_free(pre_controls);
|
||||
}
|
||||
|
||||
|
|
@ -1112,18 +1120,29 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
of commands. Thus this is delegated to a function using a third thread, that
|
||||
only starts when the background thread has finished (sharedspice.c).*/
|
||||
#ifdef SHARED_MODULE
|
||||
for (wl = controls; wl; wl = wl->wl_next)
|
||||
for (wl = controls; wl; wl = wl->wl_next){
|
||||
#ifdef OSDI
|
||||
inputdir = dir_name;
|
||||
#endif
|
||||
if (cp_getvar("controlswait", CP_BOOL, NULL, 0)) {
|
||||
exec_controls(wl_copy(wl));
|
||||
break;
|
||||
}
|
||||
else
|
||||
cp_evloop(wl->wl_word);
|
||||
}
|
||||
#else
|
||||
for (wl = controls; wl; wl = wl->wl_next)
|
||||
for (wl = controls; wl; wl = wl->wl_next){
|
||||
#ifdef OSDI
|
||||
inputdir = dir_name;
|
||||
#endif
|
||||
cp_evloop(wl->wl_word);
|
||||
}
|
||||
#endif
|
||||
wl_free(controls);
|
||||
#ifdef OSDI
|
||||
inputdir = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Now reset everything. Pop the control stack, and fix up the IO
|
||||
|
|
@ -1135,6 +1154,9 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
cp_curerr = lasterr;
|
||||
|
||||
tfree(tt);
|
||||
tfree(dir_name);
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,9 +183,6 @@ extern int DEVmaxnum; /* size of DEVices array */
|
|||
|
||||
|
||||
|
||||
#define DEV_STATIC 0x1
|
||||
#define DEV_DEFAULT_CHECK 0x2
|
||||
#define DEV_DEFAULT (DEV_DEFAULT_CHECK | DEV_STATIC)
|
||||
#define DEV_OSDI 0x4
|
||||
#define DEV_DEFAULT 0x1
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -299,6 +299,10 @@ struct IFdevice {
|
|||
#endif
|
||||
|
||||
int flags; /* DEV_ */
|
||||
|
||||
#ifdef OSDI
|
||||
const void *registry_entry;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ double INPevaluateRKM_R(char **, int *, int);
|
|||
double INPevaluateRKM_C(char **, int *, int);
|
||||
double INPevaluateRKM_L(char **, int *, int);
|
||||
char *INPfindLev(char *, int *);
|
||||
char *INPfindModule(char *);
|
||||
char *INPgetMod(CKTcircuit *, char *, INPmodel **, INPtables *);
|
||||
char *INPgetModBin(CKTcircuit *, char *, INPmodel **, INPtables *, char *);
|
||||
int INPgetTok(char **, char **, int);
|
||||
|
|
@ -146,7 +145,6 @@ int INPtermInsert(CKTcircuit *, char **, INPtables *, CKTnode **);
|
|||
int INPtermSearch(CKTcircuit*, char**, INPtables*, CKTnode**);
|
||||
int INPmkTerm(CKTcircuit *, char **, INPtables *, CKTnode **);
|
||||
int INPtypelook(char *);
|
||||
int INPtypelook_flag(char *, int);
|
||||
int INP2dot(CKTcircuit *, INPtables *, struct card *, TSKtask *, CKTnode *);
|
||||
INPtables *INPtabInit(int);
|
||||
void INPkillMods(void);
|
||||
|
|
|
|||
|
|
@ -279,7 +279,6 @@ extern char *Help_Path;
|
|||
extern char *Lib_Path;
|
||||
extern char *Inp_Path;
|
||||
extern char *Infile_Path;
|
||||
extern char *OSDI_Path;
|
||||
|
||||
#ifdef TCL_MODULE
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright© 2022 SemiMod UG. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ngspice/devdefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct OsdiRegistryEntry {
|
||||
const void *descriptor;
|
||||
uint32_t inst_offset;
|
||||
uint32_t dt;
|
||||
uint32_t temp;
|
||||
} OsdiRegistryEntry;
|
||||
|
||||
typedef struct OsdiObjectFile {
|
||||
OsdiRegistryEntry *entrys;
|
||||
int num_entries;
|
||||
} OsdiObjectFile;
|
||||
|
||||
extern OsdiObjectFile load_object_file(const char *path);
|
||||
extern SPICEdev *osdi_create_spicedev(const OsdiRegistryEntry *entry);
|
||||
|
||||
extern char *inputdir;
|
||||
|
|
@ -72,8 +72,6 @@ ivars(char *argv0)
|
|||
mkvar(&Help_Path, Spice_Lib_Dir, "helpdir", "SPICE_HELP_DIR");
|
||||
/* where spinit is found */
|
||||
mkvar(&Lib_Path, Spice_Lib_Dir, "scripts", "SPICE_SCRIPTS");
|
||||
/* used to search for OSDI models*/
|
||||
mkvar(&OSDI_Path, Spice_Lib_Dir, "osdi", "SPICE_OSDI");
|
||||
/* used to call ngspice with aspice command, not used in Windows mode */
|
||||
mkvar(&Spice_Path, Spice_Exec_Dir, "ngspice", "SPICE_PATH");
|
||||
tfree(temp);
|
||||
|
|
@ -115,5 +113,4 @@ destroy_ivars(void)
|
|||
tfree(Lib_Path);
|
||||
tfree(Spice_Path);
|
||||
tfree(Inp_Path);
|
||||
tfree(OSDI_Path);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ int OSDIacLoad(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
GENmodel *gen_model;
|
||||
GENinstance *gen_inst;
|
||||
|
||||
OsdiRegistryEntry entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry.descriptor;
|
||||
OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
for (gen_model = inModel; gen_model; gen_model = gen_model->GENnextModel) {
|
||||
for (gen_inst = gen_model->GENinstances; gen_inst;
|
||||
gen_inst = gen_inst->GENnextInstance) {
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright© 2022 SemiMod UG. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "ngspice/complex.h"
|
||||
#include "ngspice/fteext.h"
|
||||
#include "ngspice/gendefs.h"
|
||||
#include "ngspice/ifsim.h"
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/noisedef.h"
|
||||
#include "ngspice/typedefs.h"
|
||||
|
||||
#include "osdi.h"
|
||||
#include "osdiext.h"
|
||||
|
||||
#include "stddef.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct OsdiModelData {
|
||||
GENmodel gen;
|
||||
max_align_t data;
|
||||
} OsdiModelData;
|
||||
|
||||
typedef struct OsdiExtraInstData {
|
||||
double dt;
|
||||
double temp;
|
||||
bool temp_given;
|
||||
bool dt_given;
|
||||
bool lim;
|
||||
bool finish;
|
||||
|
||||
} __attribute__((aligned(sizeof(max_align_t)))) OsdiExtraInstData;
|
||||
|
||||
size_t osdi_instance_data_off(const OsdiRegistryEntry *entry);
|
||||
void *osdi_instance_data(const OsdiRegistryEntry *entry, GENinstance *inst);
|
||||
OsdiExtraInstData *osdi_extra_instance_data(const OsdiRegistryEntry *entry,
|
||||
GENinstance *inst);
|
||||
size_t osdi_model_data_off(void);
|
||||
void *osdi_model_data(GENmodel *model);
|
||||
void *osdi_model_data_from_inst(GENinstance *inst);
|
||||
OsdiRegistryEntry *osdi_reg_entry_model(const GENmodel *model);
|
||||
OsdiRegistryEntry *osdi_reg_entry_inst(const GENinstance *inst);
|
||||
|
||||
typedef struct OsdiNgspiceHandle {
|
||||
uint32_t kind;
|
||||
char *name;
|
||||
} OsdiNgspiceHandle;
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
#include "ngspice/smpdefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "osdiitf.h"
|
||||
#include "ngspice/osdiitf.h"
|
||||
|
||||
extern int OSDImParam(int, IFvalue *, GENmodel *);
|
||||
extern int OSDIparam(int, IFvalue *, GENinstance *, IFvalue *);
|
||||
|
|
@ -17,7 +17,7 @@ extern int OSDIunsetup(GENmodel *, CKTcircuit *);
|
|||
extern int OSDIask(CKTcircuit *, GENinstance *, int, IFvalue *, IFvalue *);
|
||||
extern int OSDIload(GENmodel *, CKTcircuit *);
|
||||
extern int OSDItemp(GENmodel *, CKTcircuit *);
|
||||
extern int OSDIacLoad(GENmodel *,CKTcircuit*);
|
||||
extern int OSDIacLoad(GENmodel *, CKTcircuit *);
|
||||
/* extern int OSDIconvTest(GENmodel*,CKTcircuit*); */
|
||||
/* extern int OSDImDelete(GENmodel*); */
|
||||
/* extern int OSDIgetic(GENmodel*,CKTcircuit*); */
|
||||
|
|
@ -11,18 +11,16 @@
|
|||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/typedefs.h"
|
||||
|
||||
#include "../dev.h"
|
||||
|
||||
#include "osdidefs.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.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) {
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
|
|
@ -76,8 +74,8 @@ static int write_param_info(IFparm **dst, const OsdiDescriptor *descr,
|
|||
* populating the SPICEdev struct with descriptor specific metadata and pointers
|
||||
* to the descriptor independent functions.
|
||||
* */
|
||||
static SPICEdev *osdi_init_descr(uint32_t id) {
|
||||
const OsdiDescriptor *descr = registry[id].descriptor;
|
||||
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);
|
||||
|
|
@ -88,31 +86,31 @@ static SPICEdev *osdi_init_descr(uint32_t id) {
|
|||
// 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 += 1 + descr->param_opvar[i].num_alias;
|
||||
*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 += 1 + descr->param_opvar[i].num_alias;
|
||||
*num_instance_para_names += (int) (1 + descr->param_opvar[i].num_alias);
|
||||
}
|
||||
if (registry[id].dt != UINT32_MAX) {
|
||||
if (entry->dt != UINT32_MAX) {
|
||||
*num_instance_para_names += 1;
|
||||
}
|
||||
|
||||
if (registry[id].temp != UINT32_MAX) {
|
||||
if (entry->temp != UINT32_MAX) {
|
||||
*num_instance_para_names += 1;
|
||||
}
|
||||
|
||||
IFparm *instance_para_names = TMALLOC(IFparm, *num_instance_para_names);
|
||||
IFparm *dst = instance_para_names;
|
||||
|
||||
if (registry[id].dt != UINT32_MAX) {
|
||||
dst[0] = (IFparm){"dt", (int)registry[id].dt, IF_REAL | IF_SET,
|
||||
if (entry->dt != UINT32_MAX) {
|
||||
dst[0] = (IFparm){"dt", (int)entry->dt, IF_REAL | IF_SET,
|
||||
"Instance delta temperature"};
|
||||
dst += 1;
|
||||
}
|
||||
|
||||
if (registry[id].temp != UINT32_MAX) {
|
||||
dst[0] = (IFparm){"temp", (int)registry[id].temp, IF_REAL | IF_SET,
|
||||
if (entry->temp != UINT32_MAX) {
|
||||
dst[0] = (IFparm){"temp", (int)entry->temp, IF_REAL | IF_SET,
|
||||
"Instance temperature"};
|
||||
dst += 1;
|
||||
}
|
||||
|
|
@ -123,7 +121,7 @@ static SPICEdev *osdi_init_descr(uint32_t id) {
|
|||
// 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 += 1 + descr->param_opvar[i].num_alias;
|
||||
*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;
|
||||
|
|
@ -144,10 +142,11 @@ static SPICEdev *osdi_init_descr(uint32_t id) {
|
|||
.instanceParms = instance_para_names,
|
||||
.numModelParms = num_model_para_names,
|
||||
.modelParms = model_para_names,
|
||||
.flags = DEV_DEFAULT_CHECK | DEV_OSDI,
|
||||
.flags = DEV_DEFAULT,
|
||||
.registry_entry = (void*) entry,
|
||||
};
|
||||
|
||||
size_t inst_off = registry[id].inst_offset;
|
||||
size_t inst_off = entry->inst_offset;
|
||||
|
||||
int *inst_size = TMALLOC(int, 1);
|
||||
*inst_size =
|
||||
|
|
@ -171,11 +170,3 @@ static SPICEdev *osdi_init_descr(uint32_t id) {
|
|||
|
||||
return OSDIinfo;
|
||||
}
|
||||
|
||||
extern void osdi_get_info(uint32_t off, uint32_t num_descriptors) {
|
||||
SPICEdev **dst = devices() + off;
|
||||
registry_off = off;
|
||||
for (uint32_t i = 0; i < num_descriptors; i++) {
|
||||
dst[i] = osdi_init_descr(i);
|
||||
}
|
||||
}
|
||||
|
|
@ -65,8 +65,8 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
.names_str = sim_params_str,
|
||||
.vals_str = NULL};
|
||||
|
||||
OsdiRegistryEntry entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry.descriptor;
|
||||
OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
|
||||
for (gen_model = inModel; gen_model; gen_model = gen_model->GENnextModel) {
|
||||
void *model = osdi_model_data(gen_model);
|
||||
|
|
@ -76,19 +76,19 @@ 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;
|
||||
OsdiRegistryEntry *entry = osdi_reg_entry_inst(instPtr);
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
|
||||
if (param > (int)descr->num_instance_params) {
|
||||
|
||||
// special handleing for temperature parameters
|
||||
OsdiExtraInstData *inst = osdi_extra_instance_data(entry, instPtr);
|
||||
if (param == (int)entry.dt) {
|
||||
if (param == (int)entry->dt) {
|
||||
inst->dt = value->rValue;
|
||||
inst->dt_given = true;
|
||||
return (OK);
|
||||
}
|
||||
if (param == (int)entry.temp) {
|
||||
if (param == (int)entry->temp) {
|
||||
inst->temp = value->rValue;
|
||||
inst->temp_given = true;
|
||||
return (OK);
|
||||
|
|
@ -106,8 +106,8 @@ extern int OSDIparam(int param, IFvalue *value, GENinstance *instPtr,
|
|||
|
||||
extern int OSDImParam(int param, IFvalue *value, GENmodel *modelPtr) {
|
||||
NG_IGNORE(select);
|
||||
OsdiRegistryEntry entry = osdi_reg_entry_model(modelPtr);
|
||||
const OsdiDescriptor *descr = entry.descriptor;
|
||||
OsdiRegistryEntry *entry = osdi_reg_entry_model(modelPtr);
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
|
||||
if (param > (int)descr->num_params ||
|
||||
param < (int)descr->num_instance_params) {
|
||||
|
|
@ -140,11 +140,11 @@ extern int OSDIask(CKTcircuit *ckt, GENinstance *instPtr, int id,
|
|||
NG_IGNORE(select);
|
||||
NG_IGNORE(ckt);
|
||||
|
||||
OsdiRegistryEntry entry = osdi_reg_entry_inst(instPtr);
|
||||
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;
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
|
||||
if (id > (int)(descr->num_params + descr->num_instance_params)) {
|
||||
return (E_BADPARM);
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* Copyright© 2022 SemiMod UG. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ngspice/hash.h"
|
||||
#include "ngspice/memory.h"
|
||||
#include "ngspice/stringutil.h"
|
||||
#include "osdidefs.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "osdi.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if (!defined HAS_WINGUI) && (!defined __MINGW32__) && (!defined _MSC_VER)
|
||||
|
||||
#include <dlfcn.h> /* to load libraries*/
|
||||
#define OPENLIB(path) dlopen(path, RTLD_LAZY | RTLD_LOCAL)
|
||||
#define GET_SYM(lib, sym) dlsym(lib, sym)
|
||||
#define FREE_DLERR_MSG(msg)
|
||||
|
||||
#else /* ifdef HAS_WINGUI */
|
||||
|
||||
#undef BOOLEAN
|
||||
#include <windows.h>
|
||||
#define OPENLIB(path) LoadLibrary(path)
|
||||
#define GET_SYM(lib, sym) ((void *)GetProcAddress(lib, sym))
|
||||
char *dlerror(void);
|
||||
#define FREE_DLERR_MSG(msg) free_dlerr_msg(msg)
|
||||
static void free_dlerr_msg(char *msg);
|
||||
|
||||
#endif /* ifndef HAS_WINGUI */
|
||||
|
||||
char *inputdir = NULL;
|
||||
|
||||
/* Returns true if path is an absolute path and false if it is a
|
||||
* relative path. No check is done for the existance of the path. */
|
||||
inline static bool is_absolute_pathname(const char *path) {
|
||||
#ifdef _WIN32
|
||||
return !PathIsRelativeA(path);
|
||||
#else
|
||||
return path[0] == DIR_TERM;
|
||||
#endif
|
||||
} /* end of funciton is_absolute_pathname */
|
||||
|
||||
/*-------------------------------------------------------------------------*
|
||||
Look up the variable sourcepath and try everything in the list in order
|
||||
if the file isn't in . and it isn't an abs path name.
|
||||
*-------------------------------------------------------------------------*/
|
||||
|
||||
static char *resolve_path(const char *name) {
|
||||
struct stat st;
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
/* If variable 'mingwpath' is set: convert mingw /d/... to d:/... */
|
||||
if (cp_getvar("mingwpath", CP_BOOL, NULL, 0) && name[0] == DIR_TERM_LINUX &&
|
||||
isalpha_c(name[1]) && name[2] == DIR_TERM_LINUX) {
|
||||
DS_CREATE(ds, 100);
|
||||
if (ds_cat_str(&ds, name) != 0) {
|
||||
fprintf(stderr, "Unable to copy string while resolving path");
|
||||
controlled_exit(EXIT_FAILURE);
|
||||
}
|
||||
char *const buf = ds_get_buf(&ds);
|
||||
buf[0] = buf[1];
|
||||
buf[1] = ':';
|
||||
char *const resolved_path = inp_pathresolve(buf);
|
||||
ds_free(&ds);
|
||||
return resolved_path;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* just try it */
|
||||
if (stat(name, &st) == 0)
|
||||
return copy(name);
|
||||
|
||||
#if !defined(EXT_ASC) && (defined(__MINGW32__) || defined(_MSC_VER))
|
||||
wchar_t wname[BSIZE_SP];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, name, -1, wname,
|
||||
2 * (int)strlen(name) + 1) == 0) {
|
||||
fprintf(stderr, "UTF-8 to UTF-16 conversion failed with 0x%x\n",
|
||||
GetLastError());
|
||||
fprintf(stderr, "%s could not be converted\n", name);
|
||||
return NULL;
|
||||
}
|
||||
if (_waccess(wname, 0) == 0)
|
||||
return copy(name);
|
||||
#endif
|
||||
|
||||
return (char *)NULL;
|
||||
} /* end of function inp_pathresolve */
|
||||
|
||||
static char *resolve_input_path(const char *name) {
|
||||
/* if name is an absolute path name,
|
||||
* or if we haven't anything to prepend anyway
|
||||
*/
|
||||
if (is_absolute_pathname(name)) {
|
||||
return resolve_path(name);
|
||||
}
|
||||
|
||||
if (name[0] == '~' && name[1] == '/') {
|
||||
char *const y = cp_tildexpand(name);
|
||||
if (y) {
|
||||
char *const r = resolve_path(y);
|
||||
txfree(y);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If called from a script inputdir != NULL so try relativ to that dir
|
||||
* Otherwise try relativ to the current workdir
|
||||
*/
|
||||
|
||||
if (inputdir) {
|
||||
DS_CREATE(ds, 100);
|
||||
int rc_ds = 0;
|
||||
rc_ds |= ds_cat_str(&ds, inputdir); /* copy the dir name */
|
||||
const size_t n = ds_get_length(&ds); /* end of copied dir name */
|
||||
|
||||
/* Append a directory separator if not present already */
|
||||
const char ch_last = n > 0 ? inputdir[n - 1] : '\0';
|
||||
if (ch_last != DIR_TERM
|
||||
#ifdef _WIN32
|
||||
&& ch_last != DIR_TERM_LINUX
|
||||
#endif
|
||||
) {
|
||||
rc_ds |= ds_cat_char(&ds, DIR_TERM);
|
||||
}
|
||||
rc_ds |= ds_cat_str(&ds, name); /* append the file name */
|
||||
|
||||
if (rc_ds != 0) {
|
||||
(void)fprintf(cp_err, "Unable to build \"dir\" path name "
|
||||
"in inp_pathresolve_at");
|
||||
controlled_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *const r = resolve_path(ds_get_buf(&ds));
|
||||
ds_free(&ds);
|
||||
return r;
|
||||
} else {
|
||||
DS_CREATE(ds, 100);
|
||||
if (ds_cat_printf(&ds, ".%c%s", DIR_TERM, name) != 0) {
|
||||
(void)fprintf(cp_err,
|
||||
"Unable to build \".\" path name in inp_pathresolve_at");
|
||||
controlled_exit(EXIT_FAILURE);
|
||||
}
|
||||
char *const r = resolve_path(ds_get_buf(&ds));
|
||||
ds_free(&ds);
|
||||
if (r != (char *)NULL) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} /* end of function inp_pathresolve_at */
|
||||
|
||||
/**
|
||||
* Calculates the offset that the OSDI instance data has from the beginning of
|
||||
* the instance data allocated by ngspice. This offset is non trivial because
|
||||
* ngspice must store the terminal pointers before the remaining instance
|
||||
* data. As a result the offset is not constant and a variable amount of
|
||||
* padding must be inserted to ensure correct alginment.
|
||||
*/
|
||||
static size_t calc_osdi_instance_data_off(const OsdiDescriptor *descr) {
|
||||
size_t res = sizeof(GENinstance) /* generic data */
|
||||
+ descr->num_terminals * sizeof(int);
|
||||
size_t padding = sizeof(max_align_t) - res % sizeof(max_align_t);
|
||||
if (padding == sizeof(max_align_t)) {
|
||||
padding = 0;
|
||||
}
|
||||
return res + padding;
|
||||
}
|
||||
|
||||
#define INVALID_OBJECT \
|
||||
(OsdiObjectFile) { .num_entries = -1 }
|
||||
|
||||
#define EMPTY_OBJECT \
|
||||
(OsdiObjectFile) {}
|
||||
|
||||
#define ERR_AND_RET \
|
||||
error = dlerror(); \
|
||||
printf("Error opening osdi lib \"%s\": %s\n", path, error); \
|
||||
FREE_DLERR_MSG(error); \
|
||||
return INVALID_OBJECT;
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
|
||||
#define GET_CONST(name, ty) \
|
||||
sym = GET_SYM(handle, STRINGIFY(name)); \
|
||||
if (!sym) { \
|
||||
ERR_AND_RET \
|
||||
} \
|
||||
const ty name = *((ty *)sym);
|
||||
|
||||
#define GET_PTR(name, ty) \
|
||||
sym = GET_SYM(handle, STRINGIFY(name)); \
|
||||
if (!sym) { \
|
||||
ERR_AND_RET \
|
||||
} \
|
||||
const ty *name = (ty *)sym;
|
||||
|
||||
static NGHASHPTR known_object_files = NULL;
|
||||
#define DUMMYDATA ((void *)42)
|
||||
/**
|
||||
* Loads an object file from the hard drive with the platform equivalent of
|
||||
* dlopen. This function checks that the OSDI version of the object file is
|
||||
* valid and then writes all data into the `registry`.
|
||||
* If any errors occur an appropriate message is written to errMsg
|
||||
*
|
||||
* @param PATH path A path to the shared object file
|
||||
* @param uint32_t* len The amount of entries already written into `registry`
|
||||
* @param uint32_t* capacity The amount of space available in `registry`
|
||||
* before reallocation is required
|
||||
* @returns -1 on error, 0 otherwise
|
||||
*/
|
||||
extern OsdiObjectFile load_object_file(const char *input) {
|
||||
void *handle;
|
||||
char *error;
|
||||
const void *sym;
|
||||
/* ensure the hashtable exists */
|
||||
if (!known_object_files) {
|
||||
known_object_files = nghash_init_pointer(8);
|
||||
}
|
||||
const char *path = resolve_input_path(input);
|
||||
if (!path) {
|
||||
printf("Error opening osdi lib \"%s\": No such file or directory!\n", input);
|
||||
FREE_DLERR_MSG(error);
|
||||
return INVALID_OBJECT;
|
||||
}
|
||||
|
||||
handle = OPENLIB(path);
|
||||
if (!handle) {
|
||||
ERR_AND_RET
|
||||
}
|
||||
|
||||
/* Keep track of loaded shared object files to avoid loading the same model
|
||||
* multiple times. We use the handle as a key because the same SO will always
|
||||
* return the SAME pointer as long as dlclose is not called.
|
||||
* nghash_insert returns NULL if the key (handle) was not already in the table
|
||||
* and the data (DUMMYDATA) that was previously insered (!= NULL) otherwise*/
|
||||
if (nghash_insert(known_object_files, handle, DUMMYDATA)) {
|
||||
return EMPTY_OBJECT;
|
||||
}
|
||||
|
||||
GET_CONST(OSDI_VERSION_MAJOR, uint32_t);
|
||||
GET_CONST(OSDI_VERSION_MINOR, uint32_t);
|
||||
|
||||
if (OSDI_VERSION_MAJOR != OSDI_VERSION_MAJOR_CURR ||
|
||||
OSDI_VERSION_MINOR != OSDI_VERSION_MINOR_CURR) {
|
||||
printf("NGSPICE only supports OSDI v%d.%d but \"%s\" targets v%d.%d!",
|
||||
OSDI_VERSION_MAJOR_CURR, OSDI_VERSION_MINOR_CURR, path,
|
||||
OSDI_VERSION_MAJOR, OSDI_VERSION_MINOR);
|
||||
return INVALID_OBJECT;
|
||||
}
|
||||
|
||||
GET_CONST(OSDI_NUM_DESCRIPTORS, uint32_t);
|
||||
GET_PTR(OSDI_DESCRIPTORS, OsdiDescriptor);
|
||||
|
||||
OsdiRegistryEntry *dst = TMALLOC(OsdiRegistryEntry, OSDI_NUM_DESCRIPTORS);
|
||||
|
||||
for (uint32_t i = 0; i < OSDI_NUM_DESCRIPTORS; i++) {
|
||||
const OsdiDescriptor *descr = &OSDI_DESCRIPTORS[i];
|
||||
|
||||
uint32_t dt = descr->num_params + descr->num_opvars;
|
||||
uint32_t temp = descr->num_params + descr->num_opvars + 1;
|
||||
for (uint32_t param_id = 0; param_id < descr->num_params; param_id++) {
|
||||
OsdiParamOpvar *param = &descr->param_opvar[param_id];
|
||||
for (uint32_t j = 0; j < 1 + param->num_alias; j++) {
|
||||
char *name = param->name[j];
|
||||
if (!strcmp(name, "dt")) {
|
||||
dt = UINT32_MAX;
|
||||
} else if (!strcasecmp(name, "dtemp") || !strcasecmp(name, "dt")) {
|
||||
dt = param_id;
|
||||
} else if (!strcmp(name, "temp")) {
|
||||
temp = UINT32_MAX;
|
||||
} else if (!strcasecmp(name, "temp") ||
|
||||
!strcasecmp(name, "temperature")) {
|
||||
temp = param_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t inst_off = calc_osdi_instance_data_off(descr);
|
||||
dst[i] = (OsdiRegistryEntry){
|
||||
.descriptor = descr,
|
||||
.inst_offset = (uint32_t)inst_off,
|
||||
.dt = dt,
|
||||
.temp = temp,
|
||||
};
|
||||
}
|
||||
|
||||
return (OsdiObjectFile){
|
||||
.entrys = dst,
|
||||
.num_entries = (int)OSDI_NUM_DESCRIPTORS,
|
||||
};
|
||||
}
|
||||
|
||||
inline size_t osdi_instance_data_off(const OsdiRegistryEntry *entry) {
|
||||
return entry->inst_offset;
|
||||
}
|
||||
|
||||
inline void *osdi_instance_data(const OsdiRegistryEntry *entry,
|
||||
GENinstance *inst) {
|
||||
return (void *)(((char *)inst) + osdi_instance_data_off(entry));
|
||||
}
|
||||
|
||||
inline OsdiExtraInstData *
|
||||
osdi_extra_instance_data(const OsdiRegistryEntry *entry, GENinstance *inst) {
|
||||
OsdiDescriptor *descr = (OsdiDescriptor *)entry->descriptor;
|
||||
return (OsdiExtraInstData *)(((char *)inst) + entry->inst_offset +
|
||||
descr->instance_size);
|
||||
}
|
||||
|
||||
inline size_t osdi_model_data_off(void) {
|
||||
return offsetof(OsdiModelData, data);
|
||||
}
|
||||
|
||||
inline void *osdi_model_data(GENmodel *model) {
|
||||
return (void *)&((OsdiModelData *)model)->data;
|
||||
}
|
||||
|
||||
inline void *osdi_model_data_from_inst(GENinstance *inst) {
|
||||
return osdi_model_data(inst->GENmodPtr);
|
||||
}
|
||||
|
||||
inline OsdiRegistryEntry *osdi_reg_entry_model(const GENmodel *model) {
|
||||
return (OsdiRegistryEntry *)ft_sim->devices[model->GENmodType]
|
||||
->registry_entry;
|
||||
}
|
||||
|
||||
inline OsdiRegistryEntry *osdi_reg_entry_inst(const GENinstance *inst) {
|
||||
return osdi_reg_entry_model(inst->GENmodPtr);
|
||||
}
|
||||
|
||||
#if defined(__MINGW32__) || defined(HAS_WINGUI) || defined(_MSC_VER)
|
||||
|
||||
/* For reporting error message if formatting fails */
|
||||
static const char errstr_fmt[] =
|
||||
"Unable to find message in dlerr(). System code = %lu";
|
||||
static char errstr[sizeof errstr_fmt - 3 + 3 * sizeof(unsigned long)];
|
||||
|
||||
char *dlerror(void) {
|
||||
LPVOID lpMsgBuf;
|
||||
|
||||
DWORD rc = FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf, 0, NULL);
|
||||
|
||||
if (rc == 0) { /* FormatMessage failed */
|
||||
(void)sprintf(errstr, errstr_fmt, (unsigned long)GetLastError());
|
||||
return errstr;
|
||||
}
|
||||
|
||||
return lpMsgBuf; /* Return the formatted message */
|
||||
} /* end of function dlerror */
|
||||
|
||||
/* Free message related to dynamic loading */
|
||||
static void free_dlerr_msg(char *msg) {
|
||||
if (msg != errstr) { /* msg is an allocation */
|
||||
LocalFree(msg);
|
||||
}
|
||||
} /* end of function free_dlerr_msg */
|
||||
|
||||
#endif /* Windows emulation of dlerr */
|
||||
|
|
@ -172,8 +172,8 @@ int OSDIsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
|
|||
GENinstance *gen_inst;
|
||||
int err;
|
||||
|
||||
OsdiRegistryEntry entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry.descriptor;
|
||||
OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
|
||||
/* setup a temporary buffer */
|
||||
uint32_t *node_ids = TMALLOC(uint32_t, descr->num_nodes);
|
||||
|
|
@ -280,8 +280,8 @@ extern int OSDItemp(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
int res;
|
||||
GENinstance *gen_inst;
|
||||
|
||||
OsdiRegistryEntry entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry.descriptor;
|
||||
OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
|
||||
for (gen_model = inModel; gen_model != NULL;
|
||||
gen_model = gen_model->GENnextModel) {
|
||||
|
|
@ -332,8 +332,8 @@ extern int OSDIunsetup(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
GENinstance *gen_inst;
|
||||
int num;
|
||||
|
||||
OsdiRegistryEntry entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry.descriptor;
|
||||
OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel);
|
||||
const OsdiDescriptor *descr = entry->descriptor;
|
||||
|
||||
for (gen_model = inModel; gen_model != NULL;
|
||||
gen_model = gen_model->GENnextModel) {
|
||||
|
|
@ -342,6 +342,11 @@ extern int OSDIunsetup(GENmodel *inModel, CKTcircuit *ckt) {
|
|||
gen_inst = gen_inst->GENnextInstance) {
|
||||
void *inst = osdi_instance_data(entry, gen_inst);
|
||||
|
||||
// reset is collapsible
|
||||
bool *is_collapsible =
|
||||
(bool *)(((char *)inst) + descr->is_collapsible_offset);
|
||||
memset(is_collapsible, 0, sizeof(bool) * descr->num_collapsible);
|
||||
|
||||
uint32_t *node_mapping =
|
||||
(uint32_t *)(((char *)inst) + descr->node_mapping_offset);
|
||||
for (uint32_t i = 0; i < descr->num_nodes; i++) {
|
||||
|
|
@ -28,7 +28,6 @@ SUBDIRS = \
|
|||
hfet1 \
|
||||
hfet2 \
|
||||
hicum2 \
|
||||
osdi \
|
||||
hisim2 \
|
||||
hisimhv1 \
|
||||
hisimhv2 \
|
||||
|
|
@ -64,7 +63,6 @@ SUBDIRS += nbjt nbjt2 numd numd2 numos
|
|||
endif
|
||||
|
||||
DIST_SUBDIRS = \
|
||||
osdi \
|
||||
asrc \
|
||||
bjt \
|
||||
bsim1 \
|
||||
|
|
|
|||
|
|
@ -27,25 +27,21 @@
|
|||
* HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
|
||||
* ENHANCEMENTS, OR MODIFICATIONS. */
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "assert.h"
|
||||
#include "ngspice/ngspice.h"
|
||||
|
||||
#include "ngspice/iferrmsg.h"
|
||||
#include "ngspice/devdefs.h"
|
||||
#include "ngspice/ifsim.h"
|
||||
|
||||
#include "dev.h"
|
||||
#include "ngspice/memory.h" /* to alloc, realloc devices*/
|
||||
|
||||
#include "osdi/osdiitf.h"
|
||||
|
||||
|
||||
#ifdef XSPICE
|
||||
/*saj headers for xspice*/
|
||||
#include <string.h> /* for strcpy, strcat*/
|
||||
#if (!defined HAS_WINGUI) && (!defined __MINGW32__) && (!defined _MSC_VER)
|
||||
#include <dlfcn.h> /* to load libraries*/
|
||||
typedef void * funptr_t;
|
||||
typedef void *funptr_t;
|
||||
#define FREE_DLERR_MSG(msg)
|
||||
#else /* ifdef HAS_WINGUI */
|
||||
#undef BOOLEAN
|
||||
|
|
@ -56,32 +52,35 @@ funptr_t dlsym(void *, const char *);
|
|||
char *dlerror(void);
|
||||
#define FREE_DLERR_MSG(msg) free_dlerr_msg(msg)
|
||||
static void free_dlerr_msg(char *msg);
|
||||
#define RTLD_LAZY 1 /* lazy function call binding */
|
||||
#define RTLD_NOW 2 /* immediate function call binding */
|
||||
#define RTLD_GLOBAL 4 /* symbols in this dlopen'ed obj are visible to other
|
||||
* dlopen'ed objs */
|
||||
#define RTLD_LAZY 1 /* lazy function call binding */
|
||||
#define RTLD_NOW 2 /* immediate function call binding */
|
||||
#define RTLD_GLOBAL \
|
||||
4 /* symbols in this dlopen'ed obj are visible to other \
|
||||
* dlopen'ed objs */
|
||||
#endif /* ifndef HAS_WINGUI */
|
||||
|
||||
#include "ngspice/dllitf.h" /* the coreInfo Structure*/
|
||||
#include "ngspice/evtudn.h" /*Use defined nodes */
|
||||
|
||||
Evt_Udn_Info_t **g_evt_udn_info = NULL;
|
||||
Evt_Udn_Info_t **g_evt_udn_info = NULL;
|
||||
int g_evt_num_udn_types = 0;
|
||||
|
||||
/*The digital node type */
|
||||
extern Evt_Udn_Info_t idn_digital_info;
|
||||
int add_device(int n, SPICEdev **devs, int flag);
|
||||
int add_udn(int,Evt_Udn_Info_t **);
|
||||
int add_udn(int, Evt_Udn_Info_t **);
|
||||
|
||||
extern struct coreInfo_t coreInfo; /* cmexport.c */
|
||||
extern struct coreInfo_t coreInfo; /* cmexport.c */
|
||||
#endif
|
||||
|
||||
|
||||
#include "asrc/asrcitf.h"
|
||||
#include "bjt/bjtitf.h"
|
||||
#include "bsim1/bsim1itf.h"
|
||||
#include "bsim2/bsim2itf.h"
|
||||
#include "bsim3/bsim3itf.h"
|
||||
#include "bsim3soi_dd/b3soidditf.h"
|
||||
#include "bsim3soi_fd/b3soifditf.h"
|
||||
#include "bsim3soi_pd/b3soipditf.h"
|
||||
#include "bsim3v0/bsim3v0itf.h"
|
||||
#include "bsim3v1/bsim3v1itf.h"
|
||||
#include "bsim3v32/bsim3v32itf.h"
|
||||
|
|
@ -89,13 +88,11 @@ extern struct coreInfo_t coreInfo; /* cmexport.c */
|
|||
#include "bsim4v5/bsim4v5itf.h"
|
||||
#include "bsim4v6/bsim4v6itf.h"
|
||||
#include "bsim4v7/bsim4v7itf.h"
|
||||
#include "bsim3soi_pd/b3soipditf.h"
|
||||
#include "bsim3soi_fd/b3soifditf.h"
|
||||
#include "bsim3soi_dd/b3soidditf.h"
|
||||
#include "bsimsoi/b4soiitf.h"
|
||||
#include "cap/capitf.h"
|
||||
#include "cccs/cccsitf.h"
|
||||
#include "ccvs/ccvsitf.h"
|
||||
#include "cpl/cplitf.h"
|
||||
#include "csw/cswitf.h"
|
||||
#include "dio/dioitf.h"
|
||||
#include "hfet1/hfetitf.h"
|
||||
|
|
@ -116,7 +113,6 @@ extern struct coreInfo_t coreInfo; /* cmexport.c */
|
|||
#include "mos3/mos3itf.h"
|
||||
#include "mos6/mos6itf.h"
|
||||
#include "mos9/mos9itf.h"
|
||||
#include "cpl/cplitf.h"
|
||||
#include "res/resitf.h"
|
||||
#include "soi3/soi3itf.h"
|
||||
#include "sw/switf.h"
|
||||
|
|
@ -126,16 +122,16 @@ extern struct coreInfo_t coreInfo; /* cmexport.c */
|
|||
#include "vbic/vbicitf.h"
|
||||
#include "vccs/vccsitf.h"
|
||||
#include "vcvs/vcvsitf.h"
|
||||
#include "vsrc/vsrcitf.h"
|
||||
#include "vdmos/vdmositf.h"
|
||||
#include "vsrc/vsrcitf.h"
|
||||
#ifdef ADMS
|
||||
#include "adms/hicum0/hicum0itf.h"
|
||||
#include "adms/mextram/bjt504titf.h"
|
||||
#include "adms/ekv/ekvitf.h"
|
||||
#include "adms/psp102/psp102itf.h"
|
||||
#include "adms/psp103/psp103itf.h"
|
||||
#include "adms/bsimbulk/bsimbulkitf.h"
|
||||
#include "adms/bsimcmg/bsimcmgitf.h"
|
||||
#include "adms/ekv/ekvitf.h"
|
||||
#include "adms/hicum0/hicum0itf.h"
|
||||
#include "adms/mextram/bjt504titf.h"
|
||||
#include "adms/psp102/psp102itf.h"
|
||||
#include "adms/psp103/psp103itf.h"
|
||||
#include "adms/r2_cmc/r2_cmcitf.h"
|
||||
#endif
|
||||
#ifdef CIDER
|
||||
|
|
@ -214,14 +210,14 @@ static SPICEdev *(*static_devices[])(void) = {
|
|||
#endif
|
||||
|
||||
#ifdef ADMS
|
||||
(SPICEdev *(*)(void)) get_hicum0_info,
|
||||
(SPICEdev *(*)(void)) get_bjt504t_info,
|
||||
(SPICEdev *(*)(void)) get_ekv_info,
|
||||
(SPICEdev *(*)(void)) get_psp102_info,
|
||||
(SPICEdev *(*)(void)) get_psp103_info,
|
||||
(SPICEdev *(*)(void)) get_bsimbulk_info,
|
||||
(SPICEdev *(*)(void)) get_bsimcmg_info,
|
||||
(SPICEdev *(*)(void)) get_r2_cmc_info,
|
||||
(SPICEdev * (*)(void)) get_hicum0_info,
|
||||
(SPICEdev * (*)(void)) get_bjt504t_info,
|
||||
(SPICEdev * (*)(void)) get_ekv_info,
|
||||
(SPICEdev * (*)(void)) get_psp102_info,
|
||||
(SPICEdev * (*)(void)) get_psp103_info,
|
||||
(SPICEdev * (*)(void)) get_bsimbulk_info,
|
||||
(SPICEdev * (*)(void)) get_bsimcmg_info,
|
||||
(SPICEdev * (*)(void)) get_r2_cmc_info,
|
||||
#endif
|
||||
|
||||
#ifdef NDEV
|
||||
|
|
@ -233,99 +229,84 @@ static SPICEdev *(*static_devices[])(void) = {
|
|||
static int DEVNUM = NUMELEMS(static_devices);
|
||||
|
||||
/*Make this dynamic for later attempt to make all devices dynamic*/
|
||||
SPICEdev **DEVices=NULL;
|
||||
SPICEdev **DEVices = NULL;
|
||||
|
||||
/*Flag to indicate what device type it is,
|
||||
*0 = normal spice device
|
||||
*1 = xspice device
|
||||
*/
|
||||
#ifdef XSPICE
|
||||
int *DEVicesfl=NULL;
|
||||
int DEVflag(int type){
|
||||
if(type < DEVNUM && type >= 0)
|
||||
int *DEVicesfl = NULL;
|
||||
int DEVflag(int type) {
|
||||
if (type < DEVNUM && type >= 0)
|
||||
return DEVicesfl[type];
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void
|
||||
spice_destroy_devices(void)
|
||||
{
|
||||
void spice_destroy_devices(void) {
|
||||
#ifdef XSPICE
|
||||
tfree(g_evt_udn_info);
|
||||
tfree(DEVicesfl);
|
||||
tfree(g_evt_udn_info);
|
||||
tfree(DEVicesfl);
|
||||
#endif
|
||||
tfree(DEVices);
|
||||
DEVNUM = 0;
|
||||
tfree(DEVices);
|
||||
DEVNUM = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
spice_init_devices(void)
|
||||
{
|
||||
int i;
|
||||
/* Safeguard against double initialization */
|
||||
DEVNUM = NUMELEMS(static_devices);
|
||||
void spice_init_devices(void) {
|
||||
int i;
|
||||
/* Safeguard against double initialization */
|
||||
DEVNUM = NUMELEMS(static_devices);
|
||||
|
||||
#ifdef XSPICE
|
||||
/* Initialize the structs and add digital node type */
|
||||
g_evt_udn_info = TMALLOC(Evt_Udn_Info_t *, 1);
|
||||
g_evt_num_udn_types = 1;
|
||||
g_evt_udn_info[0] = &idn_digital_info;
|
||||
/* Initialize the structs and add digital node type */
|
||||
g_evt_udn_info = TMALLOC(Evt_Udn_Info_t *, 1);
|
||||
g_evt_num_udn_types = 1;
|
||||
g_evt_udn_info[0] = &idn_digital_info;
|
||||
|
||||
DEVicesfl = TMALLOC(int, DEVNUM);
|
||||
/* tmalloc should automatically zero the array! */
|
||||
DEVicesfl = TMALLOC(int, DEVNUM);
|
||||
/* tmalloc should automatically zero the array! */
|
||||
#endif
|
||||
// load the object files and allocate additional space for OSDI devices
|
||||
// this could also be done later with realloc
|
||||
int num_osdi_devices = osdi_load_devices();
|
||||
if (num_osdi_devices < 0) {
|
||||
// TODO error handeling
|
||||
printf("FATAL error during osdi device load\n %s\n", errMsg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DEVices = TMALLOC(SPICEdev *, DEVNUM + num_osdi_devices);
|
||||
DEVices = TMALLOC(SPICEdev *, DEVNUM);
|
||||
|
||||
for (i = 0; i < DEVNUM; i++)
|
||||
DEVices[i] = static_devices[i]();
|
||||
|
||||
osdi_get_info((uint32_t)DEVNUM, (uint32_t)num_osdi_devices);
|
||||
DEVNUM += num_osdi_devices;
|
||||
for (i = 0; i < DEVNUM; i++)
|
||||
DEVices[i] = static_devices[i]();
|
||||
}
|
||||
|
||||
int num_devices(void)
|
||||
{
|
||||
return DEVNUM;
|
||||
}
|
||||
int num_devices(void) { return DEVNUM; }
|
||||
|
||||
IFdevice ** devices_ptr(void)
|
||||
{
|
||||
return (IFdevice **) DEVices;
|
||||
}
|
||||
|
||||
SPICEdev ** devices(void)
|
||||
{
|
||||
return DEVices;
|
||||
}
|
||||
IFdevice **devices_ptr(void) { return (IFdevice **)DEVices; }
|
||||
|
||||
SPICEdev **devices(void) { return DEVices; }
|
||||
|
||||
#ifdef DEVLIB
|
||||
/*not yet usable*/
|
||||
|
||||
#ifdef ADMS
|
||||
#define DEVICES_USED {"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", "bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", \
|
||||
"bsim4soi", "bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", "hisimhv2", \
|
||||
"cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", "ind", "isrc", "jfet", "ltra", "mes", "mesa" ,"mos1", "mos2", "mos3", \
|
||||
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", "vsrc", "hicum0", "bjt504t", "ekv", "psp102", "psp103", "bsimbulk", "bsimcmg"}
|
||||
#define DEVICES_USED \
|
||||
{ \
|
||||
"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", \
|
||||
"bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", "bsim4soi", \
|
||||
"bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", \
|
||||
"hisimhv2", "cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", \
|
||||
"ind", "isrc", "jfet", "ltra", "mes", "mesa", "mos1", "mos2", "mos3", \
|
||||
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", \
|
||||
"vsrc", "hicum0", "bjt504t", "ekv", "psp102", "psp103", "bsimbulk", \
|
||||
"bsimcmg" \
|
||||
}
|
||||
#else
|
||||
#define DEVICES_USED {"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", "bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", \
|
||||
"bsim4soi", "bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", "hisimhv2", \
|
||||
"cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", "ind", "isrc", "jfet", "ltra", "mes", "mesa" ,"mos1", "mos2", "mos3", \
|
||||
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", "vsrc", "hicum2"}
|
||||
#define DEVICES_USED \
|
||||
{ \
|
||||
"asrc", "bjt", "vbic", "bsim1", "bsim2", "bsim3", "bsim3v32", "bsim3v2", \
|
||||
"bsim3v1", "bsim4", "bsim4v5", "bsim4v6", "bsim4v7", "bsim4soi", \
|
||||
"bsim3soipd", "bsim3soifd", "bsim3soidd", "hisim2", "hisimhv1", \
|
||||
"hisimhv2", "cap", "cccs", "ccvs", "csw", "dio", "hfet", "hfet2", \
|
||||
"ind", "isrc", "jfet", "ltra", "mes", "mesa", "mos1", "mos2", "mos3", \
|
||||
"mos6", "mos9", "res", "soi3", "sw", "tra", "urc", "vccs", "vcvs", \
|
||||
"vsrc", "hicum2" \
|
||||
}
|
||||
#endif
|
||||
int load_dev(char *name) {
|
||||
char *msg;
|
||||
|
|
@ -335,57 +316,54 @@ int load_dev(char *name) {
|
|||
SPICEdev *device;
|
||||
|
||||
strcpy(libname, "lib");
|
||||
strcat(libname,name);
|
||||
strcat(libname,".so");
|
||||
strcat(libname, name);
|
||||
strcat(libname, ".so");
|
||||
|
||||
lib = dlopen(libname,RTLD_NOW);
|
||||
if(!lib){
|
||||
lib = dlopen(libname, RTLD_NOW);
|
||||
if (!lib) {
|
||||
msg = dlerror();
|
||||
printf("%s\n", msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
strcpy(libname, "get_");
|
||||
strcat(libname,name);
|
||||
strcat(libname,"_info");
|
||||
fetch = dlsym(lib,libname);
|
||||
strcat(libname, name);
|
||||
strcat(libname, "_info");
|
||||
fetch = dlsym(lib, libname);
|
||||
|
||||
if(!fetch){
|
||||
if (!fetch) {
|
||||
msg = dlerror();
|
||||
printf("%s\n", msg);
|
||||
return 1;
|
||||
}
|
||||
device = ((SPICEdev * (*)(void)) fetch) ();
|
||||
add_device(1,&device,0);
|
||||
device = ((SPICEdev * (*)(void)) fetch)();
|
||||
add_device(1, &device, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load_alldevs(void){
|
||||
void load_alldevs(void) {
|
||||
char *devs[] = DEVICES_USED;
|
||||
int num = NUMELEMS(devs);
|
||||
int i;
|
||||
for(i=0; i< num;i++)
|
||||
for (i = 0; i < num; i++)
|
||||
load_dev(devs[i]);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*-------------------- XSPICE additions below ----------------------*/
|
||||
#ifdef XSPICE
|
||||
#include "ngspice/mif.h"
|
||||
#include "ngspice/cm.h"
|
||||
#include "ngspice/cpextern.h"
|
||||
#include "ngspice/fteext.h" /* for ft_sim */
|
||||
#if defined(XSPICE) || defined(OSDI)
|
||||
|
||||
#include "ngspice/cktdefs.h" /* for DEVmaxnum */
|
||||
#include "ngspice/fteext.h" /* for ft_sim */
|
||||
|
||||
static void relink(void) {
|
||||
|
||||
/*
|
||||
* This replacement done by SDB on 6.11.2003
|
||||
*
|
||||
* ft_sim->numDevices = num_devices();
|
||||
* DEVmaxnum = num_devices();
|
||||
*/
|
||||
/*
|
||||
* This replacement done by SDB on 6.11.2003
|
||||
*
|
||||
* ft_sim->numDevices = num_devices();
|
||||
* DEVmaxnum = num_devices();
|
||||
*/
|
||||
ft_sim->numDevices = DEVNUM;
|
||||
DEVmaxnum = DEVNUM;
|
||||
|
||||
|
|
@ -393,190 +371,203 @@ static void relink(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
int add_device(int n, SPICEdev **devs, int flag){
|
||||
#endif
|
||||
|
||||
/*-------------------- XSPICE additions below ----------------------*/
|
||||
#ifdef XSPICE
|
||||
#include "ngspice/cm.h"
|
||||
#include "ngspice/cpextern.h"
|
||||
#include "ngspice/mif.h"
|
||||
int add_device(int n, SPICEdev **devs, int flag) {
|
||||
int i;
|
||||
int dnum = DEVNUM + n;
|
||||
DEVices = TREALLOC(SPICEdev *, DEVices, dnum);
|
||||
DEVicesfl = TREALLOC(int, DEVicesfl, dnum);
|
||||
for(i = 0; i < n;i++){
|
||||
for (i = 0; i < n; i++) {
|
||||
#ifdef TRACE
|
||||
printf("Added device: %s\n",devs[i]->DEVpublic.name);
|
||||
printf("Added device: %s\n", devs[i]->DEVpublic.name);
|
||||
#endif
|
||||
DEVices[DEVNUM+i] = devs[i];
|
||||
DEVices[DEVNUM + i] = devs[i];
|
||||
|
||||
DEVices[DEVNUM+i]->DEVinstSize = &MIFiSize;
|
||||
DEVices[DEVNUM+i]->DEVmodSize = &MIFmSize;
|
||||
DEVices[DEVNUM + i]->DEVinstSize = &MIFiSize;
|
||||
DEVices[DEVNUM + i]->DEVmodSize = &MIFmSize;
|
||||
|
||||
DEVicesfl[DEVNUM+i] = flag;
|
||||
DEVicesfl[DEVNUM + i] = flag;
|
||||
}
|
||||
DEVNUM += n;
|
||||
relink();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_udn(int n,Evt_Udn_Info_t **udns){
|
||||
int add_udn(int n, Evt_Udn_Info_t **udns) {
|
||||
int i;
|
||||
int utypes = g_evt_num_udn_types + n;
|
||||
g_evt_udn_info = TREALLOC(Evt_Udn_Info_t *, g_evt_udn_info, utypes);
|
||||
for(i = 0; i < n;i++){
|
||||
g_evt_udn_info = TREALLOC(Evt_Udn_Info_t *, g_evt_udn_info, utypes);
|
||||
for (i = 0; i < n; i++) {
|
||||
#ifdef TRACE
|
||||
printf("Added udn: %s\n",udns[i]->name);
|
||||
printf("Added udn: %s\n", udns[i]->name);
|
||||
#endif
|
||||
g_evt_udn_info[g_evt_num_udn_types+i] = udns[i];
|
||||
g_evt_udn_info[g_evt_num_udn_types + i] = udns[i];
|
||||
}
|
||||
g_evt_num_udn_types += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_opus(const char *name) {
|
||||
void *lib;
|
||||
char *msg;
|
||||
int num;
|
||||
SPICEdev **devs;
|
||||
Evt_Udn_Info_t **udns;
|
||||
funptr_t fetch;
|
||||
|
||||
int load_opus(const char *name)
|
||||
{
|
||||
void *lib;
|
||||
char *msg;
|
||||
int num;
|
||||
SPICEdev **devs;
|
||||
Evt_Udn_Info_t **udns;
|
||||
funptr_t fetch;
|
||||
lib = dlopen(name, RTLD_NOW);
|
||||
if (!lib) {
|
||||
msg = dlerror();
|
||||
printf("Error opening code model \"%s\": %s\n", name, msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lib = dlopen(name, RTLD_NOW);
|
||||
if (!lib) {
|
||||
msg = dlerror();
|
||||
printf("Error opening code model \"%s\": %s\n", name, msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
/* Get code models defined by the library */
|
||||
if ((fetch = dlsym(lib, "CMdevNum")) != (funptr_t)NULL) {
|
||||
num = *(*(int *(*)(void))fetch)();
|
||||
fetch = dlsym(lib, "CMdevs");
|
||||
if (fetch != (funptr_t)NULL) {
|
||||
devs = (*(SPICEdev * *(*)(void)) fetch)();
|
||||
} else {
|
||||
msg = dlerror();
|
||||
printf("Error getting the list of devices: %s\n", msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
msg = dlerror();
|
||||
printf("Error finding the number of devices: %s\n", msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Get code models defined by the library */
|
||||
if ((fetch = dlsym(lib, "CMdevNum")) != (funptr_t) NULL) {
|
||||
num = *(*(int * (*)(void)) fetch)();
|
||||
fetch = dlsym(lib, "CMdevs");
|
||||
if (fetch != (funptr_t) NULL) {
|
||||
devs = (*(SPICEdev ** (*)(void)) fetch)();
|
||||
}
|
||||
else {
|
||||
msg = dlerror();
|
||||
printf("Error getting the list of devices: %s\n",
|
||||
msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg = dlerror();
|
||||
printf("Error finding the number of devices: %s\n", msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
add_device(num, devs, 1);
|
||||
add_device(num, devs, 1);
|
||||
|
||||
#ifdef TRACE
|
||||
printf("Got %d devices.\n", num);
|
||||
printf("Got %d devices.\n", num);
|
||||
#endif
|
||||
|
||||
|
||||
/* Get user-defined ndes defined by the library */
|
||||
if ((fetch = dlsym(lib, "CMudnNum")) != (funptr_t) NULL) {
|
||||
num = *(*(int * (*)(void)) fetch)();
|
||||
fetch = dlsym(lib, "CMudns");
|
||||
if (fetch != (funptr_t) NULL) {
|
||||
udns = (*(Evt_Udn_Info_t ** (*)(void)) fetch)();
|
||||
}
|
||||
else {
|
||||
msg = dlerror();
|
||||
printf("Error getting the list of user-defined types: %s\n",
|
||||
msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg = dlerror();
|
||||
printf("Error finding the number of user-defined types: %s\n", msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
/* Get user-defined ndes defined by the library */
|
||||
if ((fetch = dlsym(lib, "CMudnNum")) != (funptr_t)NULL) {
|
||||
num = *(*(int *(*)(void))fetch)();
|
||||
fetch = dlsym(lib, "CMudns");
|
||||
if (fetch != (funptr_t)NULL) {
|
||||
udns = (*(Evt_Udn_Info_t * *(*)(void)) fetch)();
|
||||
} else {
|
||||
msg = dlerror();
|
||||
printf("Error getting the list of user-defined types: %s\n", msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
msg = dlerror();
|
||||
printf("Error finding the number of user-defined types: %s\n", msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
add_udn(num, udns);
|
||||
add_udn(num, udns);
|
||||
#ifdef TRACE
|
||||
printf("Got %d udns.\n", num);
|
||||
printf("Got %d udns.\n", num);
|
||||
#endif
|
||||
|
||||
/* Give the code model access to facilities provided by ngspice. */
|
||||
if ((fetch = dlsym(lib,"CMgetCoreItfPtr")) != (funptr_t) NULL) {
|
||||
const struct coreInfo_t ** const core =
|
||||
(const struct coreInfo_t **const)
|
||||
(*(struct coreInfo_t ** (*)(void)) fetch)();
|
||||
*core = &coreInfo;
|
||||
}
|
||||
else {
|
||||
msg = dlerror();
|
||||
printf("Error getting interface pointer: %s\n", msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
/* Give the code model access to facilities provided by ngspice. */
|
||||
if ((fetch = dlsym(lib, "CMgetCoreItfPtr")) != (funptr_t)NULL) {
|
||||
const struct coreInfo_t **const core = (const struct coreInfo_t **const)(*(
|
||||
struct coreInfo_t * *(*)(void)) fetch)();
|
||||
*core = &coreInfo;
|
||||
} else {
|
||||
msg = dlerror();
|
||||
printf("Error getting interface pointer: %s\n", msg);
|
||||
FREE_DLERR_MSG(msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
} /* end of function load_opus */
|
||||
|
||||
|
||||
|
||||
#if defined(__MINGW32__) || defined(HAS_WINGUI) || defined(_MSC_VER)
|
||||
|
||||
/* For reporting error message if formatting fails */
|
||||
static const char errstr_fmt[] =
|
||||
"Unable to find message in dlerr(). System code = %lu";
|
||||
"Unable to find message in dlerr(). System code = %lu";
|
||||
static char errstr[sizeof errstr_fmt - 3 + 3 * sizeof(unsigned long)];
|
||||
|
||||
/* Emulations of POSIX dlopen(), dlsym(), and dlerror(). */
|
||||
void *dlopen(const char *name, int type)
|
||||
{
|
||||
NG_IGNORE(type);
|
||||
return LoadLibrary(name);
|
||||
void *dlopen(const char *name, int type) {
|
||||
NG_IGNORE(type);
|
||||
return LoadLibrary(name);
|
||||
}
|
||||
|
||||
funptr_t dlsym(void *hDll, const char *funcname)
|
||||
{
|
||||
return GetProcAddress(hDll, funcname);
|
||||
funptr_t dlsym(void *hDll, const char *funcname) {
|
||||
return GetProcAddress(hDll, funcname);
|
||||
}
|
||||
|
||||
char *dlerror(void)
|
||||
{
|
||||
LPVOID lpMsgBuf;
|
||||
char *dlerror(void) {
|
||||
LPVOID lpMsgBuf;
|
||||
|
||||
DWORD rc = FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
DWORD rc = FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf, 0, NULL);
|
||||
|
||||
if (rc == 0) { /* FormatMessage failed */
|
||||
(void) sprintf(errstr, errstr_fmt, (unsigned long) GetLastError());
|
||||
return errstr;
|
||||
}
|
||||
if (rc == 0) { /* FormatMessage failed */
|
||||
(void)sprintf(errstr, errstr_fmt, (unsigned long)GetLastError());
|
||||
return errstr;
|
||||
}
|
||||
|
||||
return lpMsgBuf; /* Return the formatted message */
|
||||
return lpMsgBuf; /* Return the formatted message */
|
||||
} /* end of function dlerror */
|
||||
|
||||
|
||||
|
||||
/* Free message related to dynamic loading */
|
||||
static void free_dlerr_msg(char *msg)
|
||||
{
|
||||
if (msg != errstr) { /* msg is an allocation */
|
||||
LocalFree(msg);
|
||||
}
|
||||
static void free_dlerr_msg(char *msg) {
|
||||
if (msg != errstr) { /* msg is an allocation */
|
||||
LocalFree(msg);
|
||||
}
|
||||
} /* end of function free_dlerr_msg */
|
||||
|
||||
|
||||
|
||||
#endif /* Windows emulation of dlopen, dlsym, and dlerr */
|
||||
#endif
|
||||
/*-------------------- end of XSPICE additions ----------------------*/
|
||||
|
||||
#ifdef OSDI
|
||||
|
||||
#include "ngspice/osdiitf.h"
|
||||
|
||||
static int add_device(int n, OsdiRegistryEntry *devs) {
|
||||
int i;
|
||||
int dnum = DEVNUM + n;
|
||||
DEVices = TREALLOC(SPICEdev *, DEVices, dnum);
|
||||
#ifdef XSPICE
|
||||
DEVicesfl = TREALLOC(int, DEVicesfl, dnum);
|
||||
#endif
|
||||
for (i = 0; i < n; i++) {
|
||||
#ifdef TRACE
|
||||
printf("Added device: %s\n", devs[i]->DEVpublic.name);
|
||||
#endif
|
||||
DEVices[DEVNUM + i] = osdi_create_spicedev(&devs[i]);
|
||||
}
|
||||
DEVNUM += n;
|
||||
relink();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_osdi(const char *path) {
|
||||
OsdiObjectFile file = load_object_file(path);
|
||||
if (file.num_entries < 0) {
|
||||
return file.num_entries;
|
||||
}
|
||||
|
||||
add_device(file.num_entries, file.entrys);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -15,5 +15,9 @@ int DEVflag(int type);
|
|||
void load_alldevs(void);
|
||||
int load_dev(char *name);
|
||||
#endif
|
||||
|
||||
#ifdef OSDI
|
||||
int load_osdi(const char *);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Copyright© 2022 SemiMod UG. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "ngspice/complex.h"
|
||||
#include "ngspice/gendefs.h"
|
||||
#include "ngspice/ifsim.h"
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/noisedef.h"
|
||||
#include "ngspice/typedefs.h"
|
||||
|
||||
#include "osdi.h"
|
||||
#include "osdiext.h"
|
||||
|
||||
#include "stddef.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct OsdiModelData {
|
||||
GENmodel gen;
|
||||
max_align_t data;
|
||||
} OsdiModelData;
|
||||
|
||||
typedef struct OsdiExtraInstData {
|
||||
double dt;
|
||||
double temp;
|
||||
bool temp_given;
|
||||
bool dt_given;
|
||||
bool lim;
|
||||
bool finish;
|
||||
|
||||
} __attribute__((aligned(sizeof(max_align_t)))) OsdiExtraInstData;
|
||||
|
||||
typedef struct OsdiRegistryEntry {
|
||||
const OsdiDescriptor *descriptor;
|
||||
uint32_t inst_offset;
|
||||
uint32_t dt;
|
||||
uint32_t temp;
|
||||
} OsdiRegistryEntry;
|
||||
|
||||
extern OsdiRegistryEntry *registry;
|
||||
extern uint32_t registry_off;
|
||||
|
||||
inline size_t osdi_instance_data_off(OsdiRegistryEntry entry) {
|
||||
return entry.inst_offset;
|
||||
}
|
||||
inline void *osdi_instance_data(OsdiRegistryEntry entry, GENinstance *inst) {
|
||||
return (void *)(((char *)inst) + osdi_instance_data_off(entry));
|
||||
}
|
||||
inline OsdiExtraInstData *osdi_extra_instance_data(OsdiRegistryEntry entry,
|
||||
GENinstance *inst) {
|
||||
return (OsdiExtraInstData *)(((char *)inst) + entry.inst_offset +
|
||||
entry.descriptor->instance_size);
|
||||
}
|
||||
|
||||
inline size_t osdi_model_data_off() { return offsetof(OsdiModelData, data); }
|
||||
|
||||
inline void *osdi_model_data(GENmodel *model) {
|
||||
return (void *)&((OsdiModelData *)model)->data;
|
||||
}
|
||||
|
||||
inline void *osdi_model_data_from_inst(GENinstance *inst) {
|
||||
return osdi_model_data(inst->GENmodPtr);
|
||||
}
|
||||
|
||||
inline OsdiRegistryEntry osdi_reg_entry_model(GENmodel *model) {
|
||||
return registry[(uint32_t)model->GENmodType - registry_off];
|
||||
}
|
||||
|
||||
inline OsdiRegistryEntry osdi_reg_entry_inst(GENinstance *inst) {
|
||||
return osdi_reg_entry_model(inst->GENmodPtr);
|
||||
}
|
||||
|
||||
typedef struct OsdiNgspiceHandle {
|
||||
uint32_t kind;
|
||||
char *name;
|
||||
} OsdiNgspiceHandle;
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright© 2022 SemiMod UG. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Loads a list of object files into the global OSDI registry.
|
||||
* This function must only be called once at program startup.
|
||||
*
|
||||
* @param PATH *object_files The paths of the object files
|
||||
* @param uint32_t num_files The number of object files to load
|
||||
* @returns The number of loaded descriptors
|
||||
*/
|
||||
extern int osdi_load_devices(void);
|
||||
extern void osdi_get_info(uint32_t off, uint32_t num_descriptors);
|
||||
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* Copyright© 2022 SemiMod UG. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ngspice/memory.h"
|
||||
#include "ngspice/stringutil.h"
|
||||
#include "osdidefs.h"
|
||||
|
||||
#include "ngspice/iferrmsg.h"
|
||||
#include "osdi.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <direct.h>
|
||||
#define getcwd() _getcwd
|
||||
#elif defined(__GNUC__)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// TODO: platform portability
|
||||
|
||||
#include "dirent.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
char *OSDI_Path = NULL;
|
||||
OsdiRegistryEntry *registry = NULL;
|
||||
uint32_t registry_off = 0;
|
||||
|
||||
/**
|
||||
* Calculates the offset that the OSDI instance data has from the beginning of
|
||||
* the instance data allocated by ngspice. This offset is non trivial because
|
||||
* ngspice must store the terminal pointers before the remaining instance data.
|
||||
* As a result the offset is not constant and a variable amount of padding must
|
||||
* be inserted to ensure correct alginment.
|
||||
*/
|
||||
static size_t calc_osdi_instance_data_off(const OsdiDescriptor *descr) {
|
||||
size_t res = sizeof(GENinstance) /* generic data */
|
||||
+ descr->num_terminals * sizeof(int);
|
||||
size_t padding = sizeof(max_align_t) - res % sizeof(max_align_t);
|
||||
if (padding == sizeof(max_align_t)) {
|
||||
padding = 0;
|
||||
}
|
||||
return res + padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads an object file from the hard drive with the platform equivalent of
|
||||
* dlopen. This function checks that the OSDI version of the object file is
|
||||
* valid and then writes all data into the `registry`.
|
||||
* If any errors occur an appropriate message is written to errMsg
|
||||
*
|
||||
* @param PATH path A path to the shared object file
|
||||
* @param uint32_t* len The amount of entries already written into `registry`
|
||||
* @param uint32_t* capacity The amount of space available in `registry` before
|
||||
* reallocation is required
|
||||
* @returns -1 on error, 0 otherwise
|
||||
*/
|
||||
static int load_object_file(char *path, uint32_t *len, uint32_t *capacity) {
|
||||
void *handle;
|
||||
char *error;
|
||||
handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!handle) {
|
||||
errMsg = dlerror();
|
||||
return -1;
|
||||
}
|
||||
dlerror(); /* Clear any existing error */
|
||||
|
||||
const uint32_t *OSDI_VERSION_MAJOR = dlsym(handle, "OSDI_VERSION_MAJOR");
|
||||
if ((error = dlerror()) != NULL) {
|
||||
errMsg = dlerror();
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t *OSDI_VERSION_MINOR = dlsym(handle, "OSDI_VERSION_MINOR");
|
||||
if ((error = dlerror()) != NULL) {
|
||||
errMsg =
|
||||
tprintf("Failed to load OSDI object file \"%s\": %s", path, dlerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*OSDI_VERSION_MAJOR != OSDI_VERSION_MAJOR_CURR ||
|
||||
*OSDI_VERSION_MINOR != OSDI_VERSION_MINOR_CURR) {
|
||||
errMsg =
|
||||
tprintf("NGSPICE only supports OSDI v%d.%d but \"%s\" targets v%d.%d!",
|
||||
OSDI_VERSION_MAJOR_CURR, OSDI_VERSION_MINOR_CURR, path,
|
||||
*OSDI_VERSION_MAJOR, *OSDI_VERSION_MINOR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const uint32_t *OSDI_NUM_DESCRIPTORS = dlsym(handle, "OSDI_NUM_DESCRIPTORS");
|
||||
if ((error = dlerror()) != NULL) {
|
||||
errMsg = dlerror();
|
||||
return -1;
|
||||
}
|
||||
|
||||
const OsdiDescriptor *OSDI_DESCRIPTORS = dlsym(handle, "OSDI_DESCRIPTORS");
|
||||
if ((error = dlerror()) != NULL) {
|
||||
errMsg = dlerror();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*len + *OSDI_NUM_DESCRIPTORS) > *capacity) {
|
||||
*capacity *= 2;
|
||||
registry = realloc(registry, *capacity);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < *OSDI_NUM_DESCRIPTORS; i++) {
|
||||
const OsdiDescriptor *descr = &OSDI_DESCRIPTORS[i];
|
||||
|
||||
uint32_t dt = descr->num_params + descr->num_opvars;
|
||||
uint32_t temp = descr->num_params + descr->num_opvars + 1;
|
||||
for (uint32_t param_id = 0; param_id < descr->num_params; param_id++) {
|
||||
OsdiParamOpvar *param = &descr->param_opvar[param_id];
|
||||
for (uint32_t j = 0; j < 1 + param->num_alias; j++) {
|
||||
char *name = param->name[j];
|
||||
if (!strcmp(name, "dt")) {
|
||||
dt = UINT32_MAX;
|
||||
} else if (!strcasecmp(name, "dtemp") || !strcasecmp(name, "dt")) {
|
||||
dt = param_id;
|
||||
} else if (!strcmp(name, "temp")) {
|
||||
temp = UINT32_MAX;
|
||||
} else if (!strcasecmp(name, "temp") ||
|
||||
!strcasecmp(name, "temperature")) {
|
||||
temp = param_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t inst_off = calc_osdi_instance_data_off(descr);
|
||||
registry[i + *len] = (OsdiRegistryEntry){
|
||||
.descriptor = descr,
|
||||
.inst_offset = (uint32_t)inst_off,
|
||||
.dt = dt,
|
||||
.temp = temp,
|
||||
};
|
||||
}
|
||||
|
||||
*len += *OSDI_NUM_DESCRIPTORS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char **osdi_search_dir(char *dir, char **dst, uint32_t *len,
|
||||
uint32_t *cap) {
|
||||
DIR *wdir = opendir(dir);
|
||||
if (wdir == NULL) {
|
||||
return dst;
|
||||
}
|
||||
struct direct *de;
|
||||
while ((de = readdir(wdir)) != NULL) {
|
||||
if (!(de->d_ino & (DT_REG | DT_LNK))) {
|
||||
continue;
|
||||
}
|
||||
const char *filename = de->d_name;
|
||||
const char *ext = strrchr(filename, '.');
|
||||
|
||||
if (!ext || ext == filename) {
|
||||
continue;
|
||||
} else {
|
||||
ext += 1;
|
||||
}
|
||||
if (strcmp(ext, "so") != 0) {
|
||||
continue;
|
||||
}
|
||||
if (*len >= *cap) {
|
||||
*cap *= 2;
|
||||
dst = realloc(dst, *cap * sizeof(char *));
|
||||
}
|
||||
char *path = tprintf("%s%s%s", dir, DIR_PATHSEP, filename);
|
||||
|
||||
if (de->d_ino & DT_LNK) {
|
||||
char *full_path = realpath(path, NULL);
|
||||
tfree(path);
|
||||
path = full_path;
|
||||
}
|
||||
|
||||
dst[*len] = path;
|
||||
*len += 1;
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static char **osdi_search_devices(uint32_t *len) {
|
||||
uint32_t cap = 8;
|
||||
*len = 0;
|
||||
char **dst = TMALLOC(char *, cap);
|
||||
dst = osdi_search_dir(OSDI_Path, dst, len, &cap);
|
||||
char *cwd = getcwd(NULL, 0);
|
||||
if (cwd) {
|
||||
char *local_osdi_dir = tprintf("%s%s%s", cwd, DIR_PATHSEP, "osdi");
|
||||
dst = osdi_search_dir(local_osdi_dir, dst, len, &cap);
|
||||
tfree(cwd);
|
||||
tfree(local_osdi_dir);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a list of object files into the global OSDI registry.
|
||||
* This function must only be called once at program startup.
|
||||
*
|
||||
* @param PATH *object_files The paths of the object files
|
||||
* @param uint32_t num_files The number of object files to load
|
||||
* @returns The number of loaded descriptors
|
||||
*/
|
||||
static int osdi_load_devices_from_files(char **object_files,
|
||||
uint32_t num_files) {
|
||||
uint32_t len = 0;
|
||||
uint32_t capacity = num_files + 8;
|
||||
registry = TMALLOC(OsdiRegistryEntry, capacity);
|
||||
for (uint32_t i = 0; i < num_files; i++) {
|
||||
int res = load_object_file(object_files[i], &len, &capacity);
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
registry = realloc(registry, len);
|
||||
return (int)len;
|
||||
}
|
||||
|
||||
extern int osdi_load_devices(void) {
|
||||
uint32_t len = 0;
|
||||
char **files = osdi_search_devices(&len);
|
||||
int res = osdi_load_devices_from_files(files, len);
|
||||
// free paths
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
tfree(files[i]);
|
||||
}
|
||||
tfree(files);
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t osdi_instance_data_off(OsdiRegistryEntry entry);
|
||||
void *osdi_instance_data(OsdiRegistryEntry entry, GENinstance *inst);
|
||||
OsdiExtraInstData *osdi_extra_instance_data(OsdiRegistryEntry entry,
|
||||
GENinstance *inst);
|
||||
size_t osdi_model_data_off(void);
|
||||
void *osdi_model_data(GENmodel *model);
|
||||
void *osdi_model_data_from_inst(GENinstance *inst);
|
||||
OsdiRegistryEntry osdi_reg_entry_model(GENmodel *model);
|
||||
OsdiRegistryEntry osdi_reg_entry_inst(GENinstance *inst);
|
||||
|
|
@ -8,7 +8,6 @@ EXTRA_DIST = inpptree-parser-y.h
|
|||
libinp_la_SOURCES = \
|
||||
ifeval.c \
|
||||
ifnewuid.c \
|
||||
inp2a.c \
|
||||
inp2b.c \
|
||||
inp2c.c \
|
||||
inp2d.c \
|
||||
|
|
@ -72,6 +71,11 @@ libinp_la_SOURCES = \
|
|||
sperror.c \
|
||||
inpxx.h
|
||||
|
||||
|
||||
if OSDI_WANTED
|
||||
libinp_la_SOURCES += inp2a.c
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/frontend
|
||||
AM_CFLAGS = $(STATIC)
|
||||
AM_YFLAGS = -d
|
||||
|
|
|
|||
|
|
@ -4,16 +4,21 @@ Author: 1988 Thomas L. Quarles
|
|||
Modified: 2001 Paolo Nenzi (Cider Integration)
|
||||
**********/
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
|
||||
#include "ngspice/devdefs.h"
|
||||
#include "ngspice/fteext.h"
|
||||
#include "ngspice/ifsim.h"
|
||||
#include "ngspice/inpdefs.h"
|
||||
#include "ngspice/inpmacs.h"
|
||||
#include "ngspice/ngspice.h"
|
||||
|
||||
#include "inpxx.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef XSPICE
|
||||
#include "ngspice/mifproto.h"
|
||||
#endif
|
||||
|
||||
void INP2A(CKTcircuit *ckt, INPtables *tab, struct card *current) {
|
||||
/* Mname <node> <node> <node> <node> <model> [L=<val>]
|
||||
* [W=<val>] [AD=<val>] [AS=<val>] [PD=<val>]
|
||||
|
|
@ -68,8 +73,13 @@ void INP2A(CKTcircuit *ckt, INPtables *tab, struct card *current) {
|
|||
mdfast = thismodel->INPmodfast;
|
||||
IFdevice *dev = ft_sim->devices[type];
|
||||
|
||||
if (!(dev->flags & DEV_OSDI)) {
|
||||
if (!dev->registry_entry) {
|
||||
|
||||
#ifdef XSPICE
|
||||
MIF_INP2A(ckt, tab, current);
|
||||
#else
|
||||
LITERR("incorrect model type! Expected OSDI device");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,10 @@ Copyright 1990 Regents of the University of California. All rights reserved.
|
|||
Author: 1985 Thomas L. Quarles
|
||||
**********/
|
||||
|
||||
#include "ngspice/fteext.h"
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/iferrmsg.h"
|
||||
#include "ngspice/inpdefs.h"
|
||||
#include "ngspice/devdefs.h"
|
||||
#include "inpxx.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
* This fcn takes the model card & examines it. Depending upon
|
||||
|
|
@ -45,22 +42,6 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
|
|||
INPinsert(&modname, tab); /* stick model name into table */
|
||||
INPgetTok(&line, &type_name, 1); /* get model type */
|
||||
|
||||
if (!strcmp(type_name, "osdi") || !strcmp(type_name, "veriloga") ||
|
||||
!strcmp(type_name, "va")) {
|
||||
char *module;
|
||||
INPgetTok(&line, &module, 1); /* get model type */
|
||||
if (module) {
|
||||
type = INPtypelook_flag(module, DEV_OSDI);
|
||||
if (type < 0) {
|
||||
err = tprintf(
|
||||
"%s module %s was not found in any of the loaded libraries\n",
|
||||
type_name, module);
|
||||
}
|
||||
} else {
|
||||
err = tprintf("Device type %s requires a module\n", type_name);
|
||||
}
|
||||
INPmakeMod(modname, type, image);
|
||||
} else
|
||||
/* ----- Check if model is a BJT --------- */
|
||||
if (strcmp(type_name, "npn") == 0 || strcmp(type_name, "pnp") == 0) {
|
||||
err = INPfindLev(line,&lev);
|
||||
|
|
@ -698,7 +679,7 @@ char *INPdomodel(CKTcircuit *ckt, struct card *image, INPtables * tab)
|
|||
|
||||
/* -------- Default action --------- */
|
||||
else {
|
||||
#ifndef XSPICE
|
||||
#if !defined(XSPICE) && !defined(OSDI)
|
||||
type = -1;
|
||||
err = tprintf("unknown model type %s - ignored\n", type_name);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ Modified: 1999 Paolo Nenzi - Now we can use a two digits level code -
|
|||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/inpdefs.h"
|
||||
#include "inpxx.h"
|
||||
#include <stdio.h>
|
||||
|
||||
char *INPfindLev(char *line, int *level)
|
||||
{
|
||||
|
|
@ -69,41 +68,3 @@ char *INPfindLev(char *line, int *level)
|
|||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *INPfindModule(char *line) {
|
||||
char *where;
|
||||
|
||||
/*
|
||||
*where = line;
|
||||
*/
|
||||
|
||||
where = strstr(line, "module");
|
||||
|
||||
if (where != NULL) { /* found a level keyword on the line */
|
||||
|
||||
where += 6; /* skip the module keyword */
|
||||
while ((*where == ' ') || (*where == '\t') ||
|
||||
(*where == '=')) { /* legal white space - ignore */
|
||||
where++;
|
||||
}
|
||||
char *end = where;
|
||||
while (isalpha(*end) || isdigit(*end) || *end == '_' ||
|
||||
*end == '$') { /* find end of word */
|
||||
end++;
|
||||
}
|
||||
|
||||
|
||||
return dup_string(where, (size_t)end - (size_t)where);
|
||||
}
|
||||
|
||||
else { /* no module on the line => default */
|
||||
#ifdef TRACE
|
||||
fprintf(stderr,
|
||||
"Warning -- Module not specified on line \"%s\"\nUsing level 1.\n",
|
||||
line);
|
||||
#endif
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,13 +114,15 @@ create_model(CKTcircuit *ckt, INPmodel *modtmp, INPtables *tab)
|
|||
INPgetNetTok(&line, &parm, 1); /* throw away 'modname' */
|
||||
tfree(parm);
|
||||
|
||||
#ifdef OSDI
|
||||
/* osdi models don't accept their device type as an argument */
|
||||
if (device->flags & DEV_OSDI){
|
||||
if (device->registry_entry){
|
||||
INPgetNetTok(&line, &parm, 1); /* throw away osdi */
|
||||
tfree(parm);
|
||||
INPgetNetTok(&line, &parm, 1); /* throw away module name */
|
||||
tfree(parm);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (*line) {
|
||||
INPgetTok(&line, &parm, 1);
|
||||
|
|
|
|||
|
|
@ -99,7 +99,12 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task)
|
|||
/* blank line (tab leading) */
|
||||
break;
|
||||
|
||||
#ifdef XSPICE
|
||||
#ifdef OSDI
|
||||
case 'A': /* Aname <cm connections> <mname> */
|
||||
// OSDI handles xspice
|
||||
INP2A(ckt, tab, current);
|
||||
break;
|
||||
#elif XSPICE
|
||||
/* gtri - add - wbk - 10/23/90 - add case for 'A' devices */
|
||||
|
||||
case 'A': /* Aname <cm connections> <mname> */
|
||||
|
|
@ -245,13 +250,6 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task)
|
|||
case 'B':
|
||||
/* Bname <node> <node> [V=expr] [I=expr] */
|
||||
/* Arbitrary source. */
|
||||
INP2B(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
/* Bname <node> <node> [V=expr] [I=expr] */
|
||||
/* Arbitrary source. */
|
||||
INP2A(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case '.': /* .<something> Many possibilities */
|
||||
|
|
|
|||
|
|
@ -12,10 +12,9 @@ Author: 1985 Thomas L. Quarles
|
|||
#include "ngspice/cpdefs.h"
|
||||
#include "ngspice/fteext.h"
|
||||
#include "ngspice/ifsim.h"
|
||||
#include "ngspice/devdefs.h"
|
||||
#include "inpxx.h"
|
||||
|
||||
int INPtypelook_flag(char *type, int flag)
|
||||
int INPtypelook(char *type)
|
||||
{
|
||||
|
||||
int i;
|
||||
|
|
@ -35,7 +34,7 @@ int INPtypelook_flag(char *type, int flag)
|
|||
printf("In INPtypelook, checking model type = %s against existing model = %s, . . .\n", type, ft_sim->devices[i]->name);
|
||||
#endif
|
||||
|
||||
if (ft_sim->devices[i] && strcasecmp(type, ft_sim->devices[i]->name) == 0 && ft_sim->devices[i]->flags & flag) {
|
||||
if (ft_sim->devices[i] && strcasecmp(type, ft_sim->devices[i]->name) == 0) {
|
||||
/* found the device - return it */
|
||||
|
||||
#ifdef TRACE
|
||||
|
|
@ -54,13 +53,3 @@ int INPtypelook_flag(char *type, int flag)
|
|||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// backwards compatability: only look for static devices
|
||||
int INPtypelook(char *type)
|
||||
{
|
||||
return INPtypelook_flag(type, DEV_STATIC);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
/* inp2xx.c */
|
||||
|
||||
#ifdef OSDI
|
||||
void INP2A(CKTcircuit *ckt, INPtables *tab, struct card *current);
|
||||
#endif
|
||||
void INP2B(CKTcircuit *ckt, INPtables *tab, struct card *current);
|
||||
void INP2C(CKTcircuit *ckt, INPtables *tab, struct card *current);
|
||||
void INP2D(CKTcircuit *ckt, INPtables *tab, struct card *current);
|
||||
|
|
|
|||
Loading…
Reference in New Issue