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:
DSPOM 2022-05-06 23:24:09 +02:00
parent 4036e4ec26
commit 469dc127bf
37 changed files with 844 additions and 732 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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 {

View File

@ -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;
}

View File

@ -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

View File

@ -299,6 +299,10 @@ struct IFdevice {
#endif
int flags; /* DEV_ */
#ifdef OSDI
const void *registry_entry;
#endif
};

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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) {

51
src/osdi/osdidefs.h Normal file
View File

@ -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;

View File

@ -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*); */

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);

372
src/osdi/osdiregistry.c Normal file
View File

@ -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 */

View File

@ -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++) {

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);