Compare commits

...

51 Commits

Author SHA1 Message Date
Brian Taylor 87925e4e87 Fix some compiler warnings when -Wextra is added to CFLAGS. 2025-05-11 15:54:18 -07:00
Brian Taylor 91f20af48f Merge branch 'pre-master-45' into bt_dev 2025-05-11 14:17:40 -07:00
Holger Vogt 4b3de8e3bb Enable a pulse width (widths of its top) of 0
to obtain true triangular waveforms
2025-05-05 15:11:05 +02:00
Holger Vogt 8b778c56f0 beautify the code 2025-04-29 20:29:14 +02:00
Holger Vogt 5d4bb23e3c Re-enable compilation with MS Visual Studio, as "ngspice/config.h"
is not available.
Add-on to commit
4881b2973 ("Fix Bug #772 - "ngspice + icarus verilog cosim: searches for ivlng.so                 in /usr/local/lib/ngspice ...". Use the configured library directory, NGSPICELIBDIR.", 2025-04-11)
2025-04-29 11:50:09 +02:00
Giles Atkinson 0a224fa704 Fix typo in vlnggen error message. 2025-04-29 11:37:48 +02:00
Giles Atkinson 4881b29730 Fix Bug #772 - "ngspice + icarus verilog cosim: searches for ivlng.so
in /usr/local/lib/ngspice ...".
Use the configured library directory, NGSPICELIBDIR.
2025-04-29 11:37:34 +02:00
Giles Atkinson 78908b8543 Add an error message for a .model line that includes a default value
for a read-only instance parameter.  Before that caused a fatal error
in parsing the first device to use the model.
2025-04-29 11:37:28 +02:00
Giles Atkinson db92688f54 Fix Bug #750 - "VDMOS Model Naming Rules in NGSPICE Cause Confusion."
Recognise VDMOS as a special keyword only as the third token in a
.model line.  A new function, skip_token(), included in the change
allows simplification of some existing code.
2025-04-29 11:37:20 +02:00
Holger Vogt ad6635210a Merge branch 'pre-master-45' of ssh://git.code.sf.net/p/ngspice/ngspice into pre-master-45 2025-04-29 11:33:48 +02:00
Holger Vogt 33f18b485a Improve error messages when reading (and discarding) binned models,
e.g. for Skywater PDK with up to 160 bins per model parameter set.
2025-04-29 11:32:46 +02:00
b'Dietmar Warning bb90e83f3d Merge /u/arpadbuermen/ngspice/ branch vadng-pre-45 into pre-master-45
https://sourceforge.net/p/ngspice/ngspice/merge-requests/31/
2025-04-23 12:51:11 +00:00
Árpád Bűrmen 8da323b502 Fixed MOS9 scaling. 2025-04-23 14:04:06 +02:00
Brian Taylor fdf1a7d791 Merge branch 'pre-master-45' into bt_dev 2025-04-18 08:55:47 -07:00
Árpád Bűrmen 86467457ed Fixed MOS3 scaling. 2025-04-18 13:22:06 +02:00
Árpád Bűrmen 1a175dde2f Fixed MOS2 scaling. 2025-04-18 12:46:33 +02:00
Giles Atkinson 78581e3ad4 Re-make pll-xspice.cir as a wrapper around shared-pll-xspice.cir,
behaviour as before.  Add similar pll-digital-iplot.cir as a
demonstration of iplot with analogue and digital nodes.
2025-04-12 18:20:20 +02:00
Giles Atkinson a91cd8292c Rename pll-xspice.cir to shared-pll-xspice.cir to prepare for split. 2025-04-12 18:20:20 +02:00
Giles Atkinson 46c5a8d375 Fix for an error message seen when testing the shx shared-library
program: do not allow a negative timestep.
2025-04-12 18:20:20 +02:00
Giles Atkinson b8b83b1601 Add an extended shared library test program with additional
local commands to exercise the API.
2025-04-12 18:20:19 +02:00
Giles Atkinson 31e0c8e6cf Add two new functions to the shared library API.
ngSpice_Raw_Evt() requests a callback that returns all the
XSPICE events for a specific node that occurred during the last timestep.
ngSpice_Decode_Evt() provides numeric and string versions of
the event data.  Also fix some warnings in sharedspice.c.
2025-04-12 18:20:19 +02:00
Giles Atkinson cd6784a079 Event nodes can be plotted with offset by "iplot", like the
digitop option for "plot".  Offsets may be explicit or automatic with "-o".
A variable to set the offset is shared with "plot".  In plotcurv.c
suppress some warnings that should not apply to event nodes and do
not falsely claim that some vectors have only one x-value.
2025-04-12 18:20:19 +02:00
Giles Atkinson 1d435daed7 Support use of XSPICE event nodes with iplot.
In graf.c, local function set() is renamed setflag() to avoid conflict
with a newly-visible global function with the same name.
2025-04-12 18:20:19 +02:00
Giles Atkinson db39671ae2 Do not strip event value member names (like "digital_node(strength")
from the name when creating a vector from event node history.
2025-04-12 18:20:19 +02:00
Giles Atkinson 33f206b916 Add two new XSPICE functions: EVTnew_value_call() and
EVTcancel_value_call().  EVTnew_value_call() specifies a function
to be called for each confirmed new value produced on an XSPICE
event node.  To be used to add event node support for iplot.
2025-04-12 18:20:19 +02:00
Holger Vogt f4963b1ada MS Windows: Get a canonical paths name: Important if
path length exceeds MAX_PATH, might happen when using  PDKs

Patch provided by  kreijstal
2025-04-12 18:12:54 +02:00
Holger Vogt c264b71e22 re-enable adding variables (path names) to list variable "sourcepath" 2025-04-10 23:59:22 +02:00
Holger Vogt 3bf94321e6 Improved error message, not using internal 'circbyline' 2025-04-10 23:51:34 +02:00
Holger Vogt 13bbe47020 Debug printout of start-up command line 2025-04-04 15:33:43 +02:00
Árpád Bűrmen 7b1ecb261b Fixed MOS1 noise scaling. 2025-04-02 07:54:21 +02:00
Holger Vogt 1445a51a2e New command 'save nointernals' to suppress outputting and
saving of internal device nodes, espicially needed for PSP
OSDI model. Output file size reduction is e.g. from 20GB to 200MB.
2025-03-28 14:20:32 +01:00
Brian Taylor 9b430ae6e4 Merge branch 'pre-master-45' into bt_dev 2025-03-27 16:20:11 -07:00
Holger Vogt cac885401c AC noise: Update opertating point, if variable 'hertz' is given 2025-03-10 12:56:41 +01:00
Holger Vogt c0775705e5 PS compatibility: MOS level 5 and Bip level 2
will create an error. ngspice then bails out, as no
such models are available. Hint to use OpenVAF, OSDI.
2025-03-10 12:55:29 +01:00
Holger Vogt 16fbe0fb8b Create a vector thdnm from THD calculation, e.g. thd11
New vector fournosave: if set, suppress creation of
vectors thd11 and fourier, usefull when writing a raw file.
2025-03-10 12:53:40 +01:00
Brian Taylor e7a7e8c64c Merge branch 'pre-master-45' into bt_dev 2025-03-01 17:35:38 -08:00
Giles Atkinson 83d3890490 Fix a bug where a node name is mis-identified as the model for
an OSDI device and remove a limit on node count.
Problem was reported by user Sam in ngspice-users.
2025-03-01 13:45:01 +01:00
Giles Atkinson 317378085b Tidy code in get_number_terminals(), removing unneeded copying. 2025-03-01 13:44:50 +01:00
Giles Atkinson fc76d4d63b Always check for GUI events during simulation, if any graphs exist.
Previously this check was only made if an iplot window existed.
The 100W.sp example displayed frozen windows with X11-based plotting.
2025-03-01 13:44:43 +01:00
Holger Vogt 312ef68614 Enhance the search path for .spiceinit (spice.rc):
- in the directory from where the netlist has been loaded
- in a user provided path read from environmental variable SPICE_USERINIT_DIR,
- in the current directory,
- in the the HOME directory,
- in the USERPROFILE directory. */
In shared ngspice the first line shall read
- in the directory Infile_Path received from the caller (sent before initialization)
2025-03-01 13:42:01 +01:00
dwarning 2988b2e279 Involve optional d-s shunt in ac and pz analysis 2025-02-28 16:52:00 +01:00
dwarning 2ae162d779 Correct matrix entries for VDMOS pz analysis 2025-02-28 16:41:46 +01:00
dwarning dae27b5135 ReleaseOMP x64 needs fftw-3.3-dll64 include directory 2025-02-27 19:58:30 +01:00
Holger Vogt 8694ce2649 Reformat spoutput.c
Replace tabs by spaces
2025-02-24 17:00:44 +01:00
Holger Vogt 77131a2a33 Some cosmetics for readability:
replace tabs by spaces
2025-02-21 10:23:09 +01:00
Holger Vogt 7fc4c6b5bd Fixes bug by patch 124 offered by kreijstal 2025-02-20 23:40:55 +01:00
Brian Taylor 4bc4f7a0d0 Fix memory leak of parm when there is a closing ). 2025-02-20 23:33:39 +01:00
dwarning 82fc5e3806 VDMOS: use Vdsat in mobility reduction formula 2025-02-20 19:25:00 +01:00
Brian Taylor 2ce35885ff Merge branch 'pre-master-45' into bt_dev 2025-02-18 21:44:39 -08:00
Holger Vogt dd916b1d0e Formatting: tabs to spaces 2025-02-18 13:38:26 +01:00
Holger Vogt 0e032f30b1 Add a descriptive comment 2025-02-17 10:28:12 +01:00
59 changed files with 2854 additions and 957 deletions

93
examples/shared/README Normal file
View File

@ -0,0 +1,93 @@
This directory contains the source code (shx.c) for a simple utility
for exercising the Ngspice shared library API. The path to the ngspice
include file directory must be specified when compiling. When compiling
in a complete source tree:
cc -I../../src/include/ngspice -o shx shx.c
or for Windows with VisualC++:
CL.EXE /O2 /I..\..\src\include\ngspice shx.c
If a shared library binary package is installed, the inclusion option
may be unnecessary.
When run, the program dynamically loads the shared library. It is assumed to
be located in the current directory (./libngspice.so or libngspice.DLL).
The full path to the library may be specified by the "-l" option, so if the
library was built by the usual method:
./shx -l ../../releasesh/src/.libs/libngspice.so
or
shx -l ..\..\visualc\sharedspice\Release.x64\ngspice.dll
If the '-a" option is given, the program exercises some example circuits
and exits. That assumes that the current directory is the one containing this
file. Otherwise the program is interactive and prompts for a command.
If the input line starts with "/" an internal command for exercising the API
will be executed. Other lines are passed to the shared library's command
interpreter.
These internal commands are available:
/avec <plot_name>
Lists the vectors in the named plot, using ngSpice_AllVecs().
/aevt
Lists all XSPICE event nodes, using ngSpice_AllEvtNodes().
/aplot
Lists all plot names, using ngSpice_AllPlots().
/bgr
Shows the state of the background thread, using ngSpice_running().
/cplot
Show the name of the current plot, using ngSpice_CurPlot().
/dlim <limit>
To reduce repetitive output, this command sets a limit for the number
of SendData callbacks that will be reported. The parameter should be
a positive integer, 0 to report all, or -1 for unlimited output.
The initial value is 10.
/elim <limit>
Like /dlim but for XSPICE event data callbacks.
/help
Shows a summary of minternal commands.
/lvals
Toggles a flag that causes all node values to be listed for
SendData callbacks.
/reset
Resets Ngspice (call to ngSpice_Reset()) and internal variables.
/sask
Toggles a flag that control interactive prompting for
EXTERNAL source values. As a special case, the /sask command
is accepted at the prompt.
/slim <limit>
Like /dlim, but sets an independent limit for reporting callbacks that
request an new value for EXTERNAL sources.
/sramp [new_val] [interval end_val]
Stores data used to genarate an automatic response to EXTERNAL queries.
A single parameter sets a new value for the future (step change),
two values define a ramp to a specified value at a future time,
three values do both. If there is more than one such source, the same
value is used for all.
/vec <vector>
Query a spacific data vector, using ngSpice_GVI().
/xnode <node ...>
Requests raw event callbacks for an event node. That reports all node
events, not just the value when a timestep ends. Uses ngSpice_Raw_Evt().
Also found here are an example circuit, t.cir, with analog and event nodes
and an EXTERNAL voltage source. File t.shx contains inputs to shx that
run the circuit and use most of the internal commands. Run as:
./shx < t.shx
or for Windows
shx < t.txt
To view the results, run Ngspice as a program and enter:
load t.raw
plot v(ctl) v(div)

829
examples/shared/shx.c Normal file
View File

@ -0,0 +1,829 @@
/*
Test file for shared ngspice
Copyright Holger Vogt 2017-2024
Local commands: Giles Atkinson 2025
New BSD license
ngspice library loaded dynamically
simple manual input
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#ifndef _MSC_VER
#include <stdbool.h>
#include <pthread.h>
#else
#define bool int
#define true 1
#define false 0
#define strdup _strdup
#endif
#define XSPICE
#include "sharedspice.h"
typedef void *funptr_t;
#if defined(__MINGW32__) || defined(__CYGWIN__) || defined(_MSC_VER)
#undef BOOLEAN
#define LOAD_STRING "libngspice.DLL"
#include <windows.h>
void *dlopen (const char *, int);
funptr_t dlsym (void *, const char *);
int dlclose (void *);
char *dlerror (void);
#define RTLD_LAZY 1 /* lazy function call binding */
#define RTLD_NOW 2 /* immediate function call binding */
#define RTLD_GLOBAL 4 /* Symbols are externally visible. */
static char errstr[128];
#else
#if defined(__APPLE__)
#define LOAD_STRING "./libngspice.dylib"
#else
#define LOAD_STRING "./libngspice.so"
#endif
#include <dlfcn.h> /* to load libraries*/
#include <unistd.h>
#endif /* not Windows */
#include <ctype.h>
/* pointers to functions exported by ngspice */
char ** (*ngSpice_AllEvtNodes_handle)(void);
char ** (*ngSpice_AllPlots_handle)(void);
char ** (*ngSpice_AllVecs_handle)(char*);
int (*ngSpice_Command_handle)(char*);
int (*ngSpice_Circ_handle)(char**);
char * (*ngSpice_CurPlot_handle)(void);
int (*ngSpice_Decode_Evt_handle)(void *, int,
double *, const char **);
pvector_info (*ngSpice_GVI_handle)(char*);
int (*ngSpice_Init_handle)(SendChar*, SendStat*, ControlledExit*,
SendData*, SendInitData*, BGThreadRunning*,
void*);
int (*ngSpice_Init_Evt_handle)(SendEvtData*, SendInitEvtData*, void*);
int (*ngSpice_Init_Sync_handle)(GetVSRCData*, GetISRCData*,
GetSyncData*, int*, void*);
int (*ngSpice_Raw_Evt_handle)(char *, SendRawEvtData *, void *);
int (*ngSpice_Reset_handle)(void);
bool (*ngSpice_running_handle)(void);
bool no_bg = true;
bool not_yet = true;
/* Limit output from SendData, SendEvtData and VSRCData callbacks. */
static unsigned int sd_limit = 10, sd_count, sd_list;
static unsigned int se_limit = 10, se_count;
static unsigned int sq_limit = 10, sq_count, sq_ask;
/* Automatic ramp of source query replies. */
double sr_last_time = -1, sr_target_time = -1;
double sr_last_val, sr_target_val, sim_time;
static int cieq(register char *p, register char *s);
static int ciprefix(const char *p, const char *s);
static int getLine(char *prmpt, char *buff, size_t sz);
/* Callback functions used by ngspice and defined below. */
static int
ng_getchar(char* outputreturn, int ident, void* userdata);
static int
ng_getstat(char* outputreturn, int ident, void* userdata);
static int
ng_thread_runs(bool noruns, int ident, void* userdata);
static int ng_rawevt(double, void *, void *, int);
static ControlledExit ng_exit;
static SendData ng_data;
static SendInitData ng_initdata;
static SendInitEvtData ng_initevtdata;
static SendEvtData ng_evtdata;
static GetVSRCData ng_srcdata;
static GetSyncData ng_syncdata;
char comd[1024];
void * ngdllhandle = NULL;
/* Register call-back functions. */
static void register_cbs(void) {
static int z = 0;
char *bad;
int ret;
ret = ngSpice_Init_handle(ng_getchar, ng_getstat,
ng_exit, ng_data, ng_initdata, ng_thread_runs,
NULL);
if (ret) {
bad = "ngSpice_Init";
goto fail;
}
ret = ngSpice_Init_Evt_handle(ng_evtdata, ng_initevtdata, NULL);
if (!ret) {
bad = "ngSpice_Init_Evt";
goto fail;
}
ret = ngSpice_Init_Sync_handle(ng_srcdata, ng_srcdata, ng_syncdata,
&z, NULL);
if (ret == 0)
return;
bad = "ngSpice_Init_Sync";
fail:
fprintf(stderr, "Init call %s() failed: %d\n", bad, ret);
exit(2);
}
/* Non-interactive test: run a selection of circuits. */
static int auto_test(void)
{
#define SRC_FMT "source ../%s" /* Assume cd is examples/shared. */
static const char * const tests[] = {
"transient-noise/shot_ng.cir",
"soi/inv_tr.sp",
"p-to-n-examples/op-test-adi.cir",
"digital/compare/adder_Xspice.cir",
NULL
};
int ret, i;
char msgbuf[128];
for (i = 0; tests[i]; ++i) {
register_cbs();
snprintf(msgbuf, sizeof msgbuf, "echo run no. %d", i + 1);
ret = ngSpice_Command_handle(msgbuf);
if (ret)
return ret;
snprintf(msgbuf, sizeof msgbuf, SRC_FMT, tests[i]);
ret = ngSpice_Command_handle(msgbuf);
if (ret)
return ret;
ret = ngSpice_Reset_handle();
if (ret)
return ret;
}
return 0;
}
static funptr_t getsym(const char *sym)
{
funptr_t value;
value = dlsym(ngdllhandle, sym);
if (!value) {
fprintf(stderr, "Ngspice symbol %s was not found: %s\n",
sym, dlerror());
exit(1);
}
return value;
}
/* String utilities. */
char *skip(char *cp)
{
while (isspace(*cp))
++cp;
return cp;
}
char *tail(char *cp)
{
while (*cp && !isspace(*cp))
++cp;
return cp;
}
/* Execute a local command, identified by a leading '/'. */
static void help(char *cmd) {
puts("Local commands are:\n"
" /aevt\t\t\tList event nodes.\n"
" /aplot\t\tList plot names.\n"
" /avec <plot_name>\tList vectors in plot.\n"
" /bgr\t\t\tQuery background thread.\n"
" /cplot\t\tShow name of current plot.\n"
" /dlim <limit>\t\tSet output limit for SendData CB.\n"
" /elim <limit>\t\tSet output limit for SendEvtData CB.\n"
" /help\t\t\tPrint this message.\n"
" /lvals\t\tList node values on data callback (toggle).\n"
" /reset\t\tReset Ngspice.\n"
" /sask\t\t\tAsk for V/ISRC values (toggles).\n"
" /slim <limit>\t\tSet output limit for SendxSRCData CB.\n"
" /sramp [new_val] [interval end_val]\n"
"\t\t\tAuto-ramp sources\n"
" /vec <vector>\t\tQuery vector.\n"
" /xnode <node ...>\tRequest raw event callbacks for event node.\n"
"All other input is passed to Ngspice.\n");
}
static void aevt(char *cmd) {
char **cpp;
cpp = ngSpice_AllEvtNodes_handle();
if (!cpp)
return;
printf("Event nodes:\n");
while (*cpp)
printf(" %s\n", *cpp++);
}
static void aplot(char *cmd) {
char **cpp;
cpp = ngSpice_AllPlots_handle();
if (!cpp)
return;
printf("Plots:\n");
while (*cpp)
printf(" %s\n", *cpp++);
}
static void avec(char *cmd) {
char **cpp;
cpp = ngSpice_AllVecs_handle(cmd);
if (!cpp)
return;
printf("Vectors in plot %s:\n", cmd);
while (*cpp)
printf(" %s\n", *cpp++);
}
static void bgr(char *cmd) {
printf("Background thread is %srunning\n",
ngSpice_running_handle() ? "": "not ");
}
static void cplot(char *cmd) {
printf("Current plot: %s\n", ngSpice_CurPlot_handle());
}
static void dlim(char *cmd) {
sd_limit = atoi(cmd);
sd_count = 0;
}
static void elim(char *cmd) {
se_limit = atoi(cmd);
se_count = 0;
}
static void lvals(char *cmd) {
sd_list ^= 1;
printf("Listing node values is now %s.\n",
sd_list ? "on" : "off");
}
static void reset(char *cmd) {
int ret;
ret = ngSpice_Reset_handle();
if (ret) {
fprintf(stderr, "Reset error %d\n", ret);
return;
}
register_cbs();
sd_count = se_count = sq_count = 10;
sr_last_time = -1;
sr_target_time = -1;
sim_time = 0;
}
static void sask(char *cmd) {
pvector_info vp;
sq_ask ^= 1;
printf("Prompting for V/ISRC values is now %s.\n",
sq_ask ? "on" : "off");
}
static void slim(char *cmd) {
sq_limit = atoi(cmd);
sq_count = 0;
}
static void sramp(char *cmd) {
double v[3];
int i;
for (i = 0; i < 3; ++i) {
if (!*cmd)
break;
v[i] = strtod(cmd, NULL);
cmd = skip(tail(cmd));
}
if (sr_last_time < 0.0)
sr_last_time = sim_time;
switch (i) {
case 0:
break;
case 1:
sr_last_val = sr_target_val = v[0];
break;
case 2:
sr_target_time = sr_last_time + v[0];
sr_target_val = v[1];
break;
default:
sr_last_val = sr_target_val = v[0];
sr_target_time = sr_last_time + v[1];
sr_target_val = v[2];
break;
}
if (sr_target_time < 0.0)
sr_target_time = sim_time + 1.0;
}
static void vec(char *cmd) {
pvector_info vp;
vp = ngSpice_GVI_handle(cmd);
if (!vp)
return;
printf("Vector %s: length %d type %d flags %0hx\n",
vp->v_name, vp->v_length, vp->v_type, vp->v_flags);
}
struct raw_cb_ctx {
int type;
char name[1];
};
static void xnode(char *cmd) {
struct raw_cb_ctx *ctx;
char *end, c;
int ret;
while (*cmd) {
/* Memory leak here. */
end = tail(cmd);
ctx = (struct raw_cb_ctx *)malloc(sizeof *ctx + (end - cmd));
c = *end;
*end = '\0';
strcpy(ctx->name, cmd);
ret = ngSpice_Raw_Evt_handle(cmd, ng_rawevt, ctx);
if (ret >= 0) {
ctx->type = ret;
} else {
free(ctx);
fprintf(stderr, "Node name not recognised\n");
}
*end = c;
cmd = skip(end);
}
}
#define E(name) { #name, name }
static void local(char *cmd)
{
static const struct {
const char *cmd;
void (*fn)(char *);
} table[] = { E(help), // First, so that just "/" works.
E(aevt), E(avec), E(aplot), E(bgr), E(cplot),
E(dlim), E(elim), E(lvals), E(reset), E(sask), E(slim),
E(sramp), E(vec), E(xnode),
{ NULL, NULL }};
char *end;
int i, len;
end = tail(cmd);
len = end - cmd;
for (i = 0; table[i].cmd; ++i) {
if (!strncmp(cmd, table[i].cmd, len)) {
table[i].fn(skip(end));
return;
}
}
fprintf(stderr, "No such local command\n");
}
int main(int argc, char **argv)
{
char *libpath = NULL;
int ret, i, do_auto = 0;;
for (i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'a':
do_auto = 1;
break;
case 'l':
libpath = argv[i + 1];
break;
default:
fprintf(stderr, "Unknown option: %s\n", argv[i]);
return 2;
}
}
}
if (!libpath)
libpath = LOAD_STRING;
ngdllhandle = dlopen(libpath, RTLD_GLOBAL | RTLD_NOW);
if (ngdllhandle) {
printf("Ngspice library loaded.\n");
} else {
fprintf(stderr, "Ngspice library not loaded!\n %s\n", dlerror());
return 1;
}
ngSpice_AllEvtNodes_handle = getsym("ngSpice_AllEvtNodes");
ngSpice_Command_handle = getsym("ngSpice_Command");
ngSpice_CurPlot_handle = getsym("ngSpice_CurPlot");
ngSpice_AllPlots_handle = getsym("ngSpice_AllPlots");
ngSpice_AllVecs_handle = getsym("ngSpice_AllVecs");
ngSpice_Decode_Evt_handle = getsym("ngSpice_Decode_Evt");
ngSpice_GVI_handle = getsym("ngGet_Vec_Info");
ngSpice_Init_handle = getsym("ngSpice_Init");
ngSpice_Init_Evt_handle = getsym("ngSpice_Init_Evt");
ngSpice_Init_Sync_handle = getsym("ngSpice_Init_Sync");
ngSpice_Raw_Evt_handle = getsym("ngSpice_Raw_Evt");
ngSpice_Reset_handle = getsym("ngSpice_Reset");
ngSpice_running_handle = getsym("ngSpice_running");
register_cbs();
if (do_auto)
return auto_test();
/* Interactive. */
printf("Enter \"/h\" for local command descriptions.\n\n");
for (;;) {
/* get command from stdin */
if (getLine("Command: ", comd, sizeof(comd)))
return 0; // EOF
/* Check for a locally-executed command. */
if (comd[0] == '/') {
local(comd + 1);
continue;
}
/* return upon 'exit' */
if (cieq("exit", comd))
break;
/* If command 'bg_run' is given, ngSpice_Command_handle() will return immediately.
To guarantee that the primary thread here waits until the run is finished, we
may set no_bg to 0 already here. Risk: if starting the simulation fails, we never
may leave the waiting loop. As an alternative callback function ng_thread_runs()
will set no_bg to 0. This has to happen within the first 200ms waiting time. */
if (cieq("bg_run", comd))
no_bg = false;
ret = ngSpice_Command_handle(comd);
if (ret)
fprintf(stderr, "Ngspice command execution error %d\n", ret);
/* wait until simulation finishes */
for (;;) {
#if defined(__MINGW32__) || defined(__CYGWIN__) || defined(_MSC_VER)
Sleep(200);
#else
usleep(200000);
#endif
/* after 200ms the callback function ng_thread_runs() should have
set no_bg to 0, otherwise we would not wait for the end of the
background thread.*/
if (no_bg)
break;
}
}
ret = ngSpice_Reset_handle();
return 0;
}
/* Callback function called from bg thread in ngspice to transfer
any string created by printf or puts. Output to stdout in ngspice is
preceded by token stdout, same with stderr.*/
static int
ng_getchar(char* outputreturn, int ident, void* userdata)
{
printf("%s\n", outputreturn);
return 0;
}
/* Callback function called from bg thread in ngspice to transfer
simulation status (type and progress in percent). */
static int
ng_getstat(char* outputreturn, int ident, void* userdata)
{
printf("Getstat callback: %s\n", outputreturn);
return 0;
}
/* Callback function called from ngspice upon starting (returns true) or
leaving (returns false) the bg thread. */
static int
ng_thread_runs(bool noruns, int ident, void* userdata)
{
no_bg = noruns;
if (noruns)
printf("\nbg not running\n");
else
printf("bg running\n\n");
return 0;
}
/* Callback function called from bg thread in ngspice if fcn controlled_exit()
is hit. Do not exit, but unload ngspice. */
static int
ng_exit(int exitstatus, bool immediate, bool quitexit, int ident, void* userdata)
{
printf("Exit callback status %d immediate %d quit %d\n",
exitstatus, immediate, quitexit);
return exitstatus;
}
/* Callback function called from bg thread in ngspice once per
* accepted data point: Sendata callbick.
*/
static int
ng_data(pvecvaluesall vdata, int numvecs, int ident, void* userdata)
{
if (sd_limit > sd_count) {
++sd_count;
if (numvecs > 0) {
printf("New data %d (%d) vectors, first is %s\n",
numvecs, vdata->veccount, vdata->vecsa[0]->name);
if (sd_list) {
int i;
for (i = 0; i < vdata->veccount; ++i) {
if (vdata->vecsa[i]->is_complex) {
printf("%s: (%g, %g)\n", vdata->vecsa[i]->name,
vdata->vecsa[i]->creal, vdata->vecsa[i]->cimag);
} else {
printf("%s: %g\n",
vdata->vecsa[i]->name, vdata->vecsa[i]->creal);
}
}
}
} else {
printf("New data callback, no data!\n");
}
}
return 0;
}
/* Callback function called from bg thread in ngspice once upon intialization
* of the simulation vectors.
*/
static int
ng_initdata(pvecinfoall intdata, int ident, void* userdata)
{
int i;
int vn = intdata->veccount;
printf("Init data callback:\n");
for (i = 0; i < vn; i++)
printf(" Vector: %s\n", intdata->vecs[i]->vecname);
return 0;
}
static int ng_initevtdata(int idx, int max_idx, char *node, char *type,
int ident, void* userdata)
{
printf("Evt init: node %s type %s\n", node, type);
return 0;
}
static int ng_evtdata(int idx, double time, double pval, char *sval,
void *sp, int sz, int sim_node,
int ident, void* userdata)
{
if (se_limit > se_count) {
++se_count;
printf("Evt val: node %d val %s/%g at time %g\n",
idx, sval, pval, time);
}
return 0;
}
static int ng_rawevt(double time, void *valp, void *userData, int last)
{
struct raw_cb_ctx *ctx = (struct raw_cb_ctx *)userData;
const char *printstr, *typestr;
double plotval;
if (se_limit > se_count) {
++se_count;
ngSpice_Decode_Evt_handle(valp, ctx->type, &plotval, &printstr);
ngSpice_Decode_Evt_handle(NULL, ctx->type, NULL, &typestr);
printf("Raw event: node %s type %s val %s/%g at time %g%s\n",
ctx->name, typestr, printstr, plotval, time,
last ? " is last." : "");
return 0;
} else {
free(ctx);
return 1;
}
}
/* EXTERNAL source callback. */
static int ng_srcdata(double *vp, double time, char *source, int id, void *udp)
{
if (sq_limit > sq_count) {
++sq_count;
printf("V or ISRC request: source %s at time %g\n", source, time);
if (sq_ask) {
getLine("Value: ", comd, sizeof(comd));
if (!strncmp("/s", comd, 2)) {
/* Allow "/sask" as respone. */
sq_ask = 0;
} else {
sr_last_val = *vp = strtod(comd, NULL);
sr_last_time = time;
}
return 0;
}
}
if (sr_last_time >= 0.0) {
/* Provide a value. */
if (sr_target_time >= 0.0) {
if (time < sr_target_time) {
sr_last_val += (sr_target_val - sr_last_val) *
(time - sr_last_time) / (sr_target_time - sr_last_time);
} else {
sr_last_val = sr_target_val;
}
}
*vp = sr_last_val;
sr_last_time = time;
}
return 0;
}
static int ng_syncdata(double time, double *deltap, double old_delta,
int redo, int loc, int id, void *udp)
{
if (sd_limit > sd_count) {
++sd_count;
printf("Sync data redo %d delta %g (old %g) location %d at %g\n",
redo, *deltap, old_delta, loc, time);
}
sim_time = time;
return 0;
}
/* Unify LINUX and Windows dynamic library handling:
Add functions dlopen, dlsym, dlerror, dlclose to Windows by
tranlating to Windows API functions.
*/
#if defined(__MINGW32__) || defined(__CYGWIN__) || defined(_MSC_VER)
void *dlopen(const char *name,int type)
{
return LoadLibrary((LPCSTR)name);
}
funptr_t dlsym(void *hDll, const char *funcname)
{
return GetProcAddress(hDll, funcname);
}
char *dlerror(void)
{
LPVOID lpMsgBuf;
char * testerr;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0,
NULL
);
testerr = (char*)lpMsgBuf;
strcpy(errstr,lpMsgBuf);
LocalFree(lpMsgBuf);
if (ciprefix("Der Vorgang wurde erfolgreich beendet.", errstr))
return NULL;
else
return errstr;
}
int dlclose (void *lhandle)
{
return (int)FreeLibrary(lhandle);
}
#endif
/* Case insensitive str eq.
Like strcasecmp( ) XXX */
static int
cieq(register char *p, register char *s)
{
while (*p) {
if ((isupper(*p) ? tolower(*p) : *p) !=
(isupper(*s) ? tolower(*s) : *s))
return(false);
p++;
s++;
}
return (*s ? false : true);
}
/* Case insensitive prefix. */
static int
ciprefix(const char *p, const char *s)
{
while (*p) {
if ((isupper(*p) ? tolower(*p) : *p) !=
(isupper(*s) ? tolower(*s) : *s))
return(false);
p++;
s++;
}
return (true);
}
/* read a line from console input
source:
https://stackoverflow.com/questions/4023895/how-to-read-string-entered-by-user-in-c
*/
#define OK 0
#define NO_INPUT 1
static int
getLine(char *prmpt, char *buff, size_t sz)
{
int ch, len, extra;
// Get line with buffer overrun protection.
for (;;) {
if (prmpt != NULL) {
printf("%s", prmpt);
fflush(stdout);
}
if (fgets(buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
len = strlen(buff);
if (buff[len - 1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
if (extra) {
fprintf(stderr,
"Line longer than %zd characters was ignored.\n",
sz - 1);
continue;
}
}
// Otherwise remove newline and give string back to caller.
buff[len - 1] = '\0';
return OK;
}
}

34
examples/shared/t.cir Normal file
View File

@ -0,0 +1,34 @@
Simple test circuit for shx program.
* A typical command sequence in shx:
* t1.cir
* /lvals
* /aevt
* /elim 20
* /dlim 20
* /slim 20
* /xnode clk div
* run
* d_osc controlled by EXTERNAL source
vext ctl 0 0 external
aosc ctl clk osc
.model osc d_osc cntl_array = [0 20] freq_array = [ 100k 1meg ]
# Divide by three so there will be multiple transitions, reported by /aevt
# within each time-step.
adiv clk div div
.model div d_fdiv div_factor = 3
* Add a resistor to convert to analogue and force breakpoints.
r div 0 100
* Use .tran so that /xnode commands can be given after loading.
* Set maximum time step above div cycle time, so breakpoints control
* time steps. Long run time to overcome the 50 steps minimum.
.tran 4u 201u
.end

23
examples/shared/t.shx Executable file
View File

@ -0,0 +1,23 @@
# Input file running shx with t.cir
# An externally controlled source is set to 0.5V from prompted input,
# then prompting is disabled and the source value is ramped after a stop
#
# The result may be plotted with
# load t.raw
# plot v(ctl) v(div)
#
t.cir
/lvals
/aevt
/elim 20
/dlim 20
/slim 20
/xnode clk div
/sask
stop when time = 50u
run
0.5
/sask
/sram 1 0.0001 20
resume
write t.raw

View File

@ -0,0 +1,20 @@
* pll circuit using xspice code models: version with iplot including
* digital nodes.
.include shared-pll-xspice.cir
* An additional node to scale the analog signal.
bdisplay controlX4 0 v=v(cont)*4
.control
save cont controlX4 s1 s2 u1n d1 v.xlf.vdd#branch; to save memory
iplot -o controlx4 d_d+4.5 d_u
tran 0.1n $&simtime uic
rusage
plot cont s1 s2+1.2 u1n+2.4 d1+3.6 xlimit 4u 5u
plot v.xlf.vdd#branch xlimit 4u 5u ylimit -8m 2m
*plot cont
.endc
.end

View File

@ -1,66 +1,8 @@
* pll circuit using xspice code models
* pll circuit using xspice code models: version with analog-only iplot
* output frequency 400 MHz
* locked to a 1 or 10 MHz reference
.param vcc=3.3
.param divisor=40
.param fref=10e6
.csparam simtime=25u
.global d_d0 d_d1
vdd dd 0 dc 'vcc'
*vco cont 0 dc 1.9
*PULSE(V1 V2 TD TR TF PW PER)
* reference frequency selected by param fref
* PULSE(V1 V2 TD TR TF PW PER)
vref ref 0 dc 0 pulse(0 'vcc' 10n 1n 1n '1/fref/2' '1/fref')
abridgeref [ref] [d_ref] adc_vbuf
.model adc_vbuf adc_bridge(in_low = 0.5 in_high = 0.5)
*digital zero
vzero z 0 dc 0
abridgev3 [z] [d_d0] adc_vbuf
.model adc_vbuf adc_bridge(in_low = 'vcc*0.5' in_high = 'vcc*0.5')
*digital one
ainv1 d_d0 d_d1 invd1
.model invd1 d_inverter(rise_delay = 1e-10 fall_delay = 1e-10)
* vco
* buf: analog out
* d_digout: digital out
* cont: analog control voltage
* dd: analog supply voltage
*.include vco_sub.cir
*xvco buf d_digout cont dd ro_vco
.include vco_sub_new.cir
xvco buf d_digout cont dd d_osc_vco
* digital divider
adiv1 d_digout d_divout divider
.model divider d_fdiv(div_factor = 'divisor' high_cycles = 'divisor/2'
+ i_count = 4 rise_delay = 1e-10
+ fall_delay = 1e-10)
* frequency phase detector
.include f-p-det-d-sub.cir
Xfpdet d_divout d_ref d_U d_Un d_D d_Dn f-p-det
* loop filters
*2nd or 3rd order, transistors as switches
.include loop-filter-2.cir
Xlf d_Un d_D cont loopf
* 2nd order, Exxxx voltage controlled current sources as 'switches'
* loop filter current sources as charge pump
*.include loop-filter.cir
*Xlf d_U d_D cont loopfe
* d to a for plotting
abridge-w1 [d_divout d_ref d_Un d_D] [s1 s2 u1n d1] dac1 ; change to d_u or d_Un
.model dac1 dac_bridge(out_low = 0 out_high = 1 out_undef = 0.5
+ input_load = 5.0e-12 t_rise = 1e-10
+ t_fall = 1e-10)
.include shared-pll-xspice.cir
.control
save cont s1 s2 u1n d1 v.xlf.vdd#branch; to save memory
@ -69,76 +11,5 @@ tran 0.1n $&simtime uic
rusage
plot cont s1 s2+1.2 u1n+2.4 d1+3.6 xlimit 4u 5u
plot v.xlf.vdd#branch xlimit 4u 5u ylimit -8m 2m
*plot cont
.endc
*model = bsim3v3
*Berkeley Spice Compatibility
* Lmin= .35 Lmax= 20 Wmin= .6 Wmax= 20
.model N1 NMOS
*+version = 3.2.4
+version = 3.3.0
+Level= 8
+Tnom=27.0
+Nch= 2.498E+17 Tox=9E-09 Xj=1.00000E-07
+Lint=9.36e-8 Wint=1.47e-7
+Vth0= .6322 K1= .756 K2= -3.83e-2 K3= -2.612
+Dvt0= 2.812 Dvt1= 0.462 Dvt2=-9.17e-2
+Nlx= 3.52291E-08 W0= 1.163e-6
+K3b= 2.233
+Vsat= 86301.58 Ua= 6.47e-9 Ub= 4.23e-18 Uc=-4.706281E-11
+Rdsw= 650 U0= 388.3203 wr=1
+A0= .3496967 Ags=.1 B0=0.546 B1= 1
+ Dwg = -6.0E-09 Dwb = -3.56E-09 Prwb = -.213
+Keta=-3.605872E-02 A1= 2.778747E-02 A2= .9
+Voff=-6.735529E-02 NFactor= 1.139926 Cit= 1.622527E-04
+Cdsc=-2.147181E-05
+Cdscb= 0 Dvt0w = 0 Dvt1w = 0 Dvt2w = 0
+ Cdscd = 0 Prwg = 0
+Eta0= 1.0281729E-02 Etab=-5.042203E-03
+Dsub= .31871233
+Pclm= 1.114846 Pdiblc1= 2.45357E-03 Pdiblc2= 6.406289E-03
+Drout= .31871233 Pscbe1= 5000000 Pscbe2= 5E-09 Pdiblcb = -.234
+Pvag= 0 delta=0.01
+ Wl = 0 Ww = -1.420242E-09 Wwl = 0
+ Wln = 0 Wwn = .2613948 Ll = 1.300902E-10
+ Lw = 0 Lwl = 0 Lln = .316394
+ Lwn = 0
+kt1=-.3 kt2=-.051
+At= 22400
+Ute=-1.48
+Ua1= 3.31E-10 Ub1= 2.61E-19 Uc1= -3.42e-10
+Kt1l=0 Prt=764.3
.model P1 PMOS
*+version = 3.2.4
+version = 3.3.0
+Level= 8
+Tnom=27.0
+Nch= 3.533024E+17 Tox=9E-09 Xj=1.00000E-07
+Lint=6.23e-8 Wint=1.22e-7
+Vth0=-.6732829 K1= .8362093 K2=-8.606622E-02 K3= 1.82
+Dvt0= 1.903801 Dvt1= .5333922 Dvt2=-.1862677
+Nlx= 1.28e-8 W0= 2.1e-6
+K3b= -0.24 Prwg=-0.001 Prwb=-0.323
+Vsat= 103503.2 Ua= 1.39995E-09 Ub= 1.e-19 Uc=-2.73e-11
+ Rdsw= 460 U0= 138.7609
+A0= .4716551 Ags=0.12
+Keta=-1.871516E-03 A1= .3417965 A2= 0.83
+Voff=-.074182 NFactor= 1.54389 Cit=-1.015667E-03
+Cdsc= 8.937517E-04
+Cdscb= 1.45e-4 Cdscd=1.04e-4
+ Dvt0w=0.232 Dvt1w=4.5e6 Dvt2w=-0.0023
+Eta0= 6.024776E-02 Etab=-4.64593E-03
+Dsub= .23222404
+Pclm= .989 Pdiblc1= 2.07418E-02 Pdiblc2= 1.33813E-3
+Drout= .3222404 Pscbe1= 118000 Pscbe2= 1E-09
+Pvag= 0
+kt1= -0.25 kt2= -0.032 prt=64.5
+At= 33000
+Ute= -1.5
+Ua1= 4.312e-9 Ub1= 6.65e-19 Uc1= 0
+Kt1l=0
.end

View File

@ -0,0 +1,133 @@
* pll circuit using xspice code models: shared by pll_xspice.cir and
* pll_digital_iplot.cir
* output frequency 400 MHz
* locked to a 1 or 10 MHz reference
.param vcc=3.3
.param divisor=40
.param fref=10e6
.csparam simtime=25u
.global d_d0 d_d1
vdd dd 0 dc 'vcc'
*vco cont 0 dc 1.9
*PULSE(V1 V2 TD TR TF PW PER)
* reference frequency selected by param fref
* PULSE(V1 V2 TD TR TF PW PER)
vref ref 0 dc 0 pulse(0 'vcc' 10n 1n 1n '1/fref/2' '1/fref')
abridgeref [ref] [d_ref] adc_vbuf
.model adc_vbuf adc_bridge(in_low = 0.5 in_high = 0.5)
*digital zero
vzero z 0 dc 0
abridgev3 [z] [d_d0] adc_vbuf
.model adc_vbuf adc_bridge(in_low = 'vcc*0.5' in_high = 'vcc*0.5')
*digital one
ainv1 d_d0 d_d1 invd1
.model invd1 d_inverter(rise_delay = 1e-10 fall_delay = 1e-10)
* vco
* buf: analog out
* d_digout: digital out
* cont: analog control voltage
* dd: analog supply voltage
*.include vco_sub.cir
*xvco buf d_digout cont dd ro_vco
.include vco_sub_new.cir
xvco buf d_digout cont dd d_osc_vco
* digital divider
adiv1 d_digout d_divout divider
.model divider d_fdiv(div_factor = 'divisor' high_cycles = 'divisor/2'
+ i_count = 4 rise_delay = 1e-10
+ fall_delay = 1e-10)
* frequency phase detector
.include f-p-det-d-sub.cir
Xfpdet d_divout d_ref d_U d_Un d_D d_Dn f-p-det
* loop filters
*2nd or 3rd order, transistors as switches
.include loop-filter-2.cir
Xlf d_Un d_D cont loopf
* 2nd order, Exxxx voltage controlled current sources as 'switches'
* loop filter current sources as charge pump
*.include loop-filter.cir
*Xlf d_U d_D cont loopfe
* d to a for plotting
abridge-w1 [d_divout d_ref d_Un d_D] [s1 s2 u1n d1] dac1 ; change to d_u or d_Un
.model dac1 dac_bridge(out_low = 0 out_high = 1 out_undef = 0.5
+ input_load = 5.0e-12 t_rise = 1e-10
+ t_fall = 1e-10)
*model = bsim3v3
*Berkeley Spice Compatibility
* Lmin= .35 Lmax= 20 Wmin= .6 Wmax= 20
.model N1 NMOS
*+version = 3.2.4
+version = 3.3.0
+Level= 8
+Tnom=27.0
+Nch= 2.498E+17 Tox=9E-09 Xj=1.00000E-07
+Lint=9.36e-8 Wint=1.47e-7
+Vth0= .6322 K1= .756 K2= -3.83e-2 K3= -2.612
+Dvt0= 2.812 Dvt1= 0.462 Dvt2=-9.17e-2
+Nlx= 3.52291E-08 W0= 1.163e-6
+K3b= 2.233
+Vsat= 86301.58 Ua= 6.47e-9 Ub= 4.23e-18 Uc=-4.706281E-11
+Rdsw= 650 U0= 388.3203 wr=1
+A0= .3496967 Ags=.1 B0=0.546 B1= 1
+ Dwg = -6.0E-09 Dwb = -3.56E-09 Prwb = -.213
+Keta=-3.605872E-02 A1= 2.778747E-02 A2= .9
+Voff=-6.735529E-02 NFactor= 1.139926 Cit= 1.622527E-04
+Cdsc=-2.147181E-05
+Cdscb= 0 Dvt0w = 0 Dvt1w = 0 Dvt2w = 0
+ Cdscd = 0 Prwg = 0
+Eta0= 1.0281729E-02 Etab=-5.042203E-03
+Dsub= .31871233
+Pclm= 1.114846 Pdiblc1= 2.45357E-03 Pdiblc2= 6.406289E-03
+Drout= .31871233 Pscbe1= 5000000 Pscbe2= 5E-09 Pdiblcb = -.234
+Pvag= 0 delta=0.01
+ Wl = 0 Ww = -1.420242E-09 Wwl = 0
+ Wln = 0 Wwn = .2613948 Ll = 1.300902E-10
+ Lw = 0 Lwl = 0 Lln = .316394
+ Lwn = 0
+kt1=-.3 kt2=-.051
+At= 22400
+Ute=-1.48
+Ua1= 3.31E-10 Ub1= 2.61E-19 Uc1= -3.42e-10
+Kt1l=0 Prt=764.3
.model P1 PMOS
*+version = 3.2.4
+version = 3.3.0
+Level= 8
+Tnom=27.0
+Nch= 3.533024E+17 Tox=9E-09 Xj=1.00000E-07
+Lint=6.23e-8 Wint=1.22e-7
+Vth0=-.6732829 K1= .8362093 K2=-8.606622E-02 K3= 1.82
+Dvt0= 1.903801 Dvt1= .5333922 Dvt2=-.1862677
+Nlx= 1.28e-8 W0= 2.1e-6
+K3b= -0.24 Prwg=-0.001 Prwb=-0.323
+Vsat= 103503.2 Ua= 1.39995E-09 Ub= 1.e-19 Uc=-2.73e-11
+ Rdsw= 460 U0= 138.7609
+A0= .4716551 Ags=0.12
+Keta=-1.871516E-03 A1= .3417965 A2= 0.83
+Voff=-.074182 NFactor= 1.54389 Cit=-1.015667E-03
+Cdsc= 8.937517E-04
+Cdscb= 1.45e-4 Cdscd=1.04e-4
+ Dvt0w=0.232 Dvt1w=4.5e6 Dvt2w=-0.0023
+Eta0= 6.024776E-02 Etab=-4.64593E-03
+Dsub= .23222404
+Pclm= .989 Pdiblc1= 2.07418E-02 Pdiblc2= 1.33813E-3
+Drout= .3222404 Pscbe1= 118000 Pscbe2= 1E-09
+Pvag= 0
+kt1= -0.25 kt2= -0.032 prt=64.5
+At= 33000
+Ute= -1.5
+Ua1= 4.312e-9 Ub1= 6.65e-19 Uc1= 0
+Kt1l=0

View File

@ -10,6 +10,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
#include "ngspice/ngspice.h"
#include "ngspice/cpdefs.h"
#include "ngspice/ftedefs.h"
#include "ngspice/cktdefs.h"
#include "ngspice/dvec.h"
#include "ngspice/ftedebug.h"
#include "breakp.h"
@ -209,7 +210,10 @@ com_trce(wordlist *wl)
}
/* Incrementally plot a value. This is just like trace. */
/* Incrementally plot values. This is just like trace.
* Nodes may be specified with an offset, as name+number, as that is useful
* for separating the graphs of digital nodes. It will be ignored for analogue.
*/
void
com_iplot(wordlist *wl)
@ -224,12 +228,13 @@ com_iplot(wordlist *wl)
return;
}
/* settrace(wl, VF_PLOT); */
struct dbcomm *d, *td, *currentdb = NULL;
double window = 0.0;
int initial_steps = IPOINTMIN;
#ifdef XSPICE
int event_auto_incr = 0;
#endif
char *s;
int initial_steps = IPOINTMIN;
/* Look for "-w window-size" at the front, indicating a windowed iplot
* or "-d steps" to set the initial delay before the window appears.
@ -254,6 +259,12 @@ com_iplot(wordlist *wl)
wl = wl->wl_next;
if (wl)
initial_steps = atoi(wl->wl_word);
#ifdef XSPICE
} else if (wl->wl_word[1] == 'o' && !wl->wl_word[2]) {
/* Automatically offset traces for event nodes. */
event_auto_incr = 1;
#endif
} else {
break;
}
@ -269,8 +280,10 @@ com_iplot(wordlist *wl)
d = TMALLOC(struct dbcomm, 1);
d->db_analysis = NULL;
d->db_number = debugnumber++;
d->db_op = initial_steps; // Field re-use
d->db_value1 = window; // Field re-use
d->db_iteration = event_auto_incr ? DB_AUTO_OFFSET : DB_NORMAL;
d->db_op = initial_steps; // Field re-use
d->db_value1 = window; // Field re-use
if (eq(s, "all")) {
d->db_type = DB_IPLOTALL;
} else {
@ -278,8 +291,14 @@ com_iplot(wordlist *wl)
d->db_nodename1 = copy(s);
}
tfree(s);/*DG: avoid memory leak */
d->db_also = currentdb;
currentdb = d;
/* Chain in expected order. */
if (currentdb)
td->db_also = d;
else
currentdb = d;
td = d;
wl = wl->wl_next;
}
@ -388,7 +407,10 @@ void
dbfree1(struct dbcomm *d)
{
tfree(d->db_nodename1);
tfree(d->db_nodename2);
if (d->db_type != DB_IPLOT && d->db_type != DB_IPLOTALL &&
d->db_type != DB_DEADIPLOT) {
tfree(d->db_nodename2);
}
if (d->db_also)
dbfree(d->db_also);
tfree(d);

View File

@ -399,6 +399,7 @@ static void set_static_system_info(void)
/* Get memory information */
static int get_sysmem(struct sys_memory *memall)
{
NG_IGNORE(memall);
fprintf(stderr, "System memory info is not available\n");
return -1;
}

View File

@ -428,7 +428,7 @@ struct comm spcp_coms[] = {
{ "iplot", com_iplot, TRUE, TRUE,
{ 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS,
NULL,
"[-w width] [-s initial_steps] [all] [node ...] : Incrementally plot nodes." } ,
"[-w width] [-d initial_steps] [-o] [all] [node ...] : Incrementally plot nodes." } ,
{ "status", com_sttus, TRUE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 0, 0,
NULL,
@ -897,10 +897,6 @@ struct comm nutcp_coms[] = {
{ 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS,
NULL,
"[all] [node ...] : Save a spice output." } ,
{ "iplot", NULL, TRUE, TRUE,
{ 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS,
NULL,
"[all] [node ...] : Incrementally plot a node." } ,
{ "status", NULL, TRUE, FALSE,
{ 0, 0, 0, 0 }, E_DEFHMASK, 0, 0,
NULL,

View File

@ -1641,11 +1641,13 @@ check_ifparm_compare(const void *a, const void *b)
}
#ifdef HAVE_TDESTROY
static void
check_ifparm_freenode(void *node)
{
NG_IGNORE(node);
}
#endif
static void

View File

@ -50,6 +50,7 @@ fourier(wordlist *wl, struct plot *current_plot)
char xbuf[20];
int shift;
int rv = 1;
bool foursave = TRUE;
struct dvec *n;
int newveccount = 1;
@ -71,6 +72,8 @@ fourier(wordlist *wl, struct plot *current_plot)
polydegree = 1;
if (!cp_getvar("fourgridsize", CP_NUM, &fourgridsize, 0) || fourgridsize < 1)
fourgridsize = DEF_FOURGRIDSIZE;
if (cp_getvar("fournosave", CP_BOOL, NULL, 0))
foursave = FALSE;
time = current_plot->pl_scale;
if (!isreal(time)) {
@ -188,34 +191,48 @@ fourier(wordlist *wl, struct plot *current_plot)
}
fputs("\n", cp_out);
/* create and assign a new vector n */
/* with size 3 * nfreqs in current plot */
/* generate name for new vector, using vec->name */
n = dvec_alloc(tprintf("fourier%d%d", callstof, newveccount),
SV_NOTYPE,
VF_REAL | VF_PERMANENT,
3 * nfreqs, NULL);
if (foursave) {
/* create a vector for THD */
n = dvec_alloc(tprintf("thd%d%d", callstof, newveccount),
SV_NOTYPE,
VF_REAL | VF_PERMANENT,
1, NULL);
n->v_numdims = 2;
n->v_dims[0] = 3;
n->v_dims[1] = nfreqs;
n->v_numdims = 1;
vec_new(n);
vec_new(n);
/* store data in vector: freq, mag, phase */
for (i = 0; i < nfreqs; i++) {
n->v_realdata[i] = freq[i];
n->v_realdata[i + nfreqs] = mag[i];
n->v_realdata[i + 2 * nfreqs] = phase[i];
n->v_realdata[0] = thd;
/* create and assign a new vector n */
/* with size 3 * nfreqs in current plot */
/* generate name for new vector, using vec->name */
n = dvec_alloc(tprintf("fourier%d%d", callstof, newveccount),
SV_NOTYPE,
VF_REAL | VF_PERMANENT,
3 * nfreqs, NULL);
n->v_numdims = 2;
n->v_dims[0] = 3;
n->v_dims[1] = nfreqs;
vec_new(n);
/* store data in vector: freq, mag, phase */
for (i = 0; i < nfreqs; i++) {
n->v_realdata[i] = freq[i];
n->v_realdata[i + nfreqs] = mag[i];
n->v_realdata[i + 2 * nfreqs] = phase[i];
}
newveccount++;
if (polydegree) {
tfree(timescale);
tfree(data);
}
timescale = NULL;
data = NULL;
}
newveccount++;
if (polydegree) {
tfree(timescale);
tfree(data);
}
timescale = NULL;
data = NULL;
}
}

View File

@ -198,6 +198,10 @@ static void utf8_syntax_check(struct card *deck);
int add_to_sourcepath(const char* filepath, const char* path);
#if defined(_WIN32)
static char* get_windows_canonical_path(const char* input_path);
#endif
struct inp_read_t {
struct card *cc;
int line_number;
@ -1279,6 +1283,13 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name,
return cc;
}
static char *skip_token(char *s)
{
s = skip_ws(s); /* Advance past space chars. */
s = skip_non_ws(s); /* Skip over token. */
return skip_ws(s);
}
static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name,
const char* file_name, bool comfile, bool intfile)
@ -1416,8 +1427,8 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name
/* now handle .title statement */
if (ciprefix(".title", buffer)) {
char* s;
s = skip_non_ws(buffer); /* skip over .title */
s = skip_ws(s); /* advance past space chars */
s = skip_token(buffer);
/* only the last title line remains valid */
tfree(new_title);
@ -1969,19 +1980,20 @@ FILE *inp_pathopen(const char *name, const char *mode)
if the file isn't in . and it isn't an abs path name.
*-------------------------------------------------------------------------*/
char *inp_pathresolve(const char *name)
char *inp_pathresolve(const char *cname)
{
struct variable *v;
struct stat st;
char* name;
#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) {
cname[0] == DIR_TERM_LINUX && isalpha_c(cname[1]) &&
cname[2] == DIR_TERM_LINUX) {
DS_CREATE(ds, 100);
if (ds_cat_str(&ds, name) != 0) {
if (ds_cat_str(&ds, cname) != 0) {
fprintf(stderr, "Error: Unable to copy string while resolving path");
controlled_exit(EXIT_FAILURE);
}
@ -1993,27 +2005,33 @@ char *inp_pathresolve(const char *name)
return resolved_path;
}
/* Try to overcome MAX_PATH path length limit by removing '/..' */
name = get_windows_canonical_path(cname);
#else
name = copy(cname);
#endif
/* just try it */
if (stat(name, &st) == 0)
return copy(name);
return 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);
tfree(name);
return NULL;
}
if (_waccess(wname, 0) == 0)
return copy(name);
#endif
return name;
#endif
/* fail if this was an absolute filename or if there is no sourcepath var
*/
if (is_absolute_pathname(name) ||
!cp_getvar("sourcepath", CP_LIST, &v, 0)) {
tfree(name);
return (char *) NULL;
}
@ -2040,12 +2058,14 @@ char *inp_pathresolve(const char *name)
fprintf(stderr,
"ERROR: enumeration value `CP_BOOL' or `CP_LIST' "
"not handled in inp_pathresolve\nAborting...\n");
tfree(name);
controlled_exit(EXIT_FAILURE);
}
if (rc_ds != 0) { /* unable to build string */
(void) fprintf(cp_err,
"Error: Unable to build path name in inp_pathresolve");
tfree(name);
controlled_exit(EXIT_FAILURE);
}
@ -2056,6 +2076,7 @@ char *inp_pathresolve(const char *name)
char * const buf_cpy = dup_string(
buf, ds_get_length(&ds));
ds_free(&ds);
tfree(name);
return buf_cpy;
}
/* Else contiue with next attempt */
@ -2063,7 +2084,7 @@ char *inp_pathresolve(const char *name)
} /* end of loop over linked variables */
ds_free(&ds);
} /* end of block trying to find a valid name */
tfree(name);
return (char *) NULL;
} /* end of function inp_pathresolve */
@ -2552,7 +2573,7 @@ static void replace_freq(struct card *c, int *line_number)
++keywd;
cp = key;
while (*keywd && !isspace_c(*keywd) && *keywd != '}' &&
cp - key < sizeof key - 1) {
cp - key < (long)(sizeof key - 1)) {
*cp++ = *keywd++;
}
*cp = 0;
@ -2786,13 +2807,11 @@ static void inp_fix_macro_param_func_paren_io(struct card *card)
if (ciprefix(".subckt", card->line) || ciprefix("x", card->line)) {
/* remove () */
str_ptr = skip_non_ws(card->line);
// skip over .subckt, instance name
str_ptr = skip_ws(str_ptr);
if (ciprefix(".subckt", card->line)) {
str_ptr = skip_non_ws(str_ptr); // skip over subckt name
str_ptr = skip_ws(str_ptr);
}
str_ptr = skip_token(card->line); // Skip over .subckt.
if (ciprefix(".subckt", card->line))
str_ptr = skip_token(str_ptr); // Skip over subckt name.
if (*str_ptr == '(') {
*str_ptr = ' ';
while (*str_ptr != '\0') {
@ -2810,8 +2829,8 @@ static void inp_fix_macro_param_func_paren_io(struct card *card)
if (ciprefix(".para", card->line)) {
bool is_func = FALSE;
str_ptr = skip_non_ws(card->line); // skip over .param
str_ptr = skip_ws(str_ptr);
str_ptr = skip_token(card->line); // skip over .param
while (!isspace_c(*str_ptr) && *str_ptr != '=') {
if (*str_ptr == '(')
is_func = TRUE;
@ -2860,13 +2879,8 @@ static char *get_subckt_model_name(char *line)
{
char *name, *end_ptr;
name = skip_non_ws(line); // eat .subckt|.model
name = skip_ws(name);
name = skip_token(line); // Eat .subckt or .model
end_ptr = skip_non_ws(name);
return copy_substring(name, end_ptr);
}
@ -2876,23 +2890,16 @@ static char *get_model_name(char *line, int num_terminals)
char *beg_ptr, *end_ptr;
int i = 0;
beg_ptr = skip_non_ws(line); /* eat device name */
beg_ptr = skip_ws(beg_ptr);
for (i = 0; i < num_terminals; i++) { /* skip the terminals */
beg_ptr = skip_non_ws(beg_ptr);
beg_ptr = skip_ws(beg_ptr);
}
beg_ptr = skip_token(line); // Eat device name.
for (i = 0; i < num_terminals; i++)
beg_ptr = skip_token(beg_ptr); // Eat terminal.
if (*line == 'r') /* special dealing for r models */
if ((*beg_ptr == '+') || (*beg_ptr == '-') ||
isdigit_c(*beg_ptr)) { /* looking for a value before model */
beg_ptr = skip_non_ws(beg_ptr); /* skip the value */
beg_ptr = skip_ws(beg_ptr);
beg_ptr = skip_token(beg_ptr); /* Skip the value, */
}
end_ptr = skip_non_ws(beg_ptr);
return copy_substring(beg_ptr, end_ptr);
}
@ -2904,12 +2911,8 @@ static char *get_model_type(char *line)
if (!ciprefix(".model", line))
return NULL;
beg_ptr = skip_non_ws(line); /* eat .model */
beg_ptr = skip_ws(beg_ptr);
beg_ptr = skip_non_ws(beg_ptr); /* eat model name */
beg_ptr = skip_ws(beg_ptr);
beg_ptr = skip_token(line); /* Eat .model */
beg_ptr = skip_token(beg_ptr); /* Eat model name. */
return gettok_noparens(&beg_ptr);
}
@ -3641,8 +3644,8 @@ static char *inp_fix_subckt(struct names *subckt_w_params, char *s)
if (equal &&
(!strstr(s, "params:") || !isspace_c(s[-1]))) {
/* get subckt name (ptr1 will point to name) */
ptr1 = skip_non_ws(s);
ptr1 = skip_ws(ptr1);
ptr1 = skip_token(s);
for (ptr2 = ptr1; *ptr2 && !isspace_c(*ptr2) && !isquote(*ptr2);
ptr2++)
;
@ -4261,8 +4264,8 @@ static void inp_fix_inst_calls_for_numparam(
continue;
if (d) {
char *subckt_line = d->line;
subckt_line = skip_non_ws(subckt_line);
subckt_line = skip_ws(subckt_line);
subckt_line = skip_token(subckt_line);
int num_subckt_params = inp_get_params(subckt_line,
subckt_param_names, subckt_param_values);
@ -4371,8 +4374,7 @@ static void inp_get_func_from_line(struct function_env *env, char *line)
struct function *function;
/* skip `.func' */
line = skip_non_ws(line);
line = skip_ws(line);
line = skip_token(line);
/* get function name */
end = line;
@ -5156,10 +5158,10 @@ static int inp_get_param_level(
the first letter of its instance line. Returns 0 upon error. */
int get_number_terminals(char *c)
{
int i, j, k;
int i, j, k;
char *inst;
char *name[12];
char nam_buf[128];
bool area_found = FALSE;
bool area_found = FALSE;
if (!c)
return 0;
@ -5181,28 +5183,31 @@ int get_number_terminals(char *c)
but still allow self heating diode with ngspice syntax. */
if (newcompat.ps && !search_plain_identifier(c, "thermal"))
return 2;
i = 0;
/* find the first token with "off" or "=" in the line*/
while ((i < 10) && (*c != '\0')) {
char *inst = gettok_instance(&c);
strncpy(nam_buf, inst, sizeof(nam_buf) - 1);
txfree(inst);
if ( i > 3 && (search_plain_identifier(nam_buf, "off") || search_plain_identifier(nam_buf, "thermal") || strchr(nam_buf, '=')))
for (i = 0; (i < 10) && (*c != '\0'); ++i) {
inst = gettok_instance(&c);
if (i > 3 && (search_plain_identifier(inst, "off") ||
search_plain_identifier(inst, "thermal") ||
strchr(inst, '='))) {
txfree(inst);
break;
i++;
}
txfree(inst);
}
return i - 2;
break;
case 'x':
i = 0;
/* find the first token with "params:" or "=" in the line*/
while ((i < 100) && (*c != '\0')) {
char *inst = gettok_instance(&c);
strncpy(nam_buf, inst, sizeof(nam_buf) - 1);
txfree(inst);
if (search_plain_identifier(nam_buf, "params:") || strchr(nam_buf, '='))
for (i = 0; (i < 100) && (*c != '\0'); ++i) {
inst = gettok_instance(&c);
if (search_plain_identifier(inst, "params:") ||
strchr(inst, '=')) {
txfree(inst);
break;
i++;
}
txfree(inst);
}
return i - 2;
break;
@ -5223,34 +5228,34 @@ int get_number_terminals(char *c)
case 'm': /* recognition of 4, 5, 6, or 7 nodes for SOI devices needed
*/
{
i = 0;
char* cc, * ccfree;
cc = copy(c);
/* required to make m= 1 a single token m=1 */
ccfree = cc = inp_remove_ws(cc);
/* find the first token with "off", "tnodeout", "thermal" or "=" in the line*/
while ((i < 20) && (*cc != '\0')) {
char* inst = gettok_instance(&cc);
strncpy(nam_buf, inst, sizeof(nam_buf) - 1);
txfree(inst);
if ( i > 4 && (search_plain_identifier(nam_buf, "off") || strchr(nam_buf, '=') ||
search_plain_identifier(nam_buf, "tnodeout") || search_plain_identifier(nam_buf, "thermal")))
for (i = 0; (i < 20) && (*cc != '\0'); ++i) {
inst = gettok_instance(&cc);
if ( i > 4 &&
(search_plain_identifier(inst, "off") ||
strchr(inst, '=') ||
search_plain_identifier(inst, "tnodeout") ||
search_plain_identifier(inst, "thermal"))) {
txfree(inst);
break;
i++;
}
txfree(inst);
}
tfree(ccfree);
return i - 2;
break;
}
case 'p': /* recognition of up to 100 cpl nodes */
i = j = 0;
/* find the last token in the line*/
while ((i < 100) && (*c != '\0')) {
char *tmp_inst = gettok_instance(&c);
strncpy(nam_buf, tmp_inst, 32);
tfree(tmp_inst);
if (strchr(nam_buf, '='))
case 'p': /* Recognition of up to 100 cpl nodes */
for (i = j = 0; (i < 100) && (*c != '\0'); ++i) {
inst = gettok_instance(&c);
if (strchr(inst, '='))
j++;
tfree(inst);
i++;
}
if (i == 100)
@ -5263,21 +5268,27 @@ int get_number_terminals(char *c)
/* 12 tokens maximum */
{
char* cc, * ccfree;
i = j = 0;
cc = copy(c);
/* required to make m= 1 a single token m=1 */
ccfree = cc = inp_remove_ws(cc);
while ((i < 12) && (*cc != '\0')) {
for (i = j = 0; (i < 12) && (*cc != '\0'); ++i) {
char* comma;
name[i] = gettok_instance(&cc);
if (search_plain_identifier(name[i], "off") || strchr(name[i], '='))
if (search_plain_identifier(name[i], "off") ||
strchr(name[i], '=')) {
j++;
}
#ifdef CIDER
if (search_plain_identifier(name[i], "save") || search_plain_identifier(name[i], "print"))
if (search_plain_identifier(name[i], "save") ||
search_plain_identifier(name[i], "print")) {
j++;
}
#endif
/* If we have IC=VBE, VCE instead of IC=VBE,VCE we need to inc
* j */
/* If we have IC=VBE, VCE instead of IC=VBE,VCE
* we need to increment j.
*/
if ((comma = strchr(name[i], ',')) != NULL &&
(*(++comma) == '\0'))
j++;
@ -5285,14 +5296,14 @@ int get_number_terminals(char *c)
*/
if (eq(name[i], ","))
j++;
i++;
}
tfree(ccfree);
i--;
tfree(ccfree);
area_found = FALSE;
for (k = i; k > i - j - 1; k--) {
bool only_digits = TRUE;
char* nametmp = name[k];
/* MNAME has to contain at least one alpha character. AREA may
be assumed if we have a token with only digits, and where
the previous token does not end with a ',' */
@ -5315,26 +5326,21 @@ int get_number_terminals(char *c)
break;
}
#ifdef OSDI
case 'n': /* Recognize an unknown number of nodes by stopping at tokens with '=' */
{
i = 0;
char* cc, * ccfree;
cc = copy(c);
/* required to make m= 1 a single token m=1 */
ccfree = cc = inp_remove_ws(cc);
/* find the first token with "off", "tnodeout", "thermal" or "=" in the line*/
while ((i < 20) && (*cc != '\0')) {
char* inst = gettok_instance(&cc);
strncpy(nam_buf, inst, sizeof(nam_buf) - 1);
txfree(inst);
if (i > 2 && (strchr(nam_buf, '=')))
case 'n':
/* Find the last non-parameter token in the line. */
for (i = 0; *c != '\0' && *c != '='; ++i) {
inst = gettok_instance(&c);
if (strchr(inst, '=')) {
tfree(inst);
break;
i++;
}
tfree(inst);
}
tfree(ccfree);
if (*c == '=')
--i; // Counted a parameter name.
return i - 2;
break;
}
#endif
default:
return 0;
@ -5483,8 +5489,7 @@ static void inp_add_params_to_subckt(
if (!strstr(subckt_line, "params:")) {
new_line = tprintf("%s params: %s", subckt_line, param_ptr);
subckt_name = skip_non_ws(subckt_line);
subckt_name = skip_ws(subckt_name);
subckt_name = skip_token(subckt_line);
end_ptr = skip_non_ws(subckt_name);
add_name(subckt_w_params, copy_substring(subckt_name, end_ptr));
}
@ -6821,7 +6826,7 @@ static void inp_compat(struct card *card)
K13 L2 L3 1
*/
else if (*curr_line == 'k') {
int tokcount = 0;
int tokcount = 0, idx1, idx2;
char* kinst, **ltok, *couple;
cut_line = curr_line;
/* get number of tokens */
@ -6836,20 +6841,20 @@ static void inp_compat(struct card *card)
cut_line = curr_line;
kinst = gettok(&cut_line);
ltok = TMALLOC(char*, tokcount);
for (i = 0; i < tokcount; i++) {
ltok[i] = gettok(&cut_line);
for (idx1 = 0; idx1 < tokcount; idx1++) {
ltok[idx1] = gettok(&cut_line);
}
couple = gettok(&cut_line);
*curr_line = '*';
for (i = 0; i < tokcount - 1; i++)
for (ii = i + 1; ii < tokcount; ii++) {
char* newline = tprintf("%s_%d_%d %s %s %s", kinst, (int)i + 1, (int)ii + 1, ltok[i], ltok[ii], couple);
card = insert_new_line(card, newline, (int)i + 1, currlinenumber, card->linesource);
for (idx1 = 0; idx1 < tokcount - 1; idx1++)
for (idx2 = idx1 + 1; idx2 < tokcount; idx2++) {
char* newline = tprintf("%s_%d_%d %s %s %s", kinst, idx1 + 1, idx2 + 1, ltok[idx1], ltok[idx2], couple);
card = insert_new_line(card, newline, idx1 + 1, currlinenumber, card->linesource);
}
tfree(kinst);
tfree(couple);
for (i = 0; i < tokcount; i++) {
tfree(ltok[i]);
for (idx1 = 0; idx1 < tokcount; idx1++) {
tfree(ltok[idx1]);
}
}
}
@ -7849,9 +7854,7 @@ static void inp_fix_temper_in_param(struct card *deck)
controlled_exit(EXIT_FAILURE);
}
lhs_b = skip_non_ws(curr_line); // eat .param
lhs_b = skip_ws(lhs_b);
lhs_b = skip_token(curr_line); // Eat .param.
lhs_e = skip_back_ws(equal_ptr, curr_line);
/* skip if this is a function already */
@ -8076,9 +8079,7 @@ static void inp_fix_agauss_in_param(struct card *deck, char *fcn)
controlled_exit(EXIT_FAILURE);
}
lhs_b = skip_non_ws(curr_line); // eat .param
lhs_b = skip_ws(lhs_b);
lhs_b = skip_token(curr_line); // Eat .param.
lhs_e = skip_back_ws(equal_ptr, curr_line);
/* skip if this is a function already */
@ -8314,10 +8315,8 @@ static void inp_quote_params(struct card *c, struct card *end_c,
char *s = curr_line;
for (j = 0; j < num_terminals + 1; j++) {
s = skip_non_ws(s);
s = skip_ws(s);
}
for (j = 0; j < num_terminals + 1; j++)
s = skip_token(s);
while ((s = ya_search_identifier(
s, deps[i].param_name, curr_line)) != NULL) {
@ -8385,7 +8384,6 @@ static void inp_quote_params(struct card *c, struct card *end_c,
}
}
/* VDMOS special:
Check for 'vdmos' in .model line.
check if 'pchan', then add p to vdmos and ignore 'pchan'.
@ -8411,16 +8409,17 @@ static int inp_vdmos_model(struct card *deck)
curr_line = card->line;
if (ciprefix(".model", curr_line)) {
cut_line = search_plain_identifier(curr_line, "vdmos");
if (cut_line) {
cut_line = skip_token(curr_line);
cut_line = skip_token(cut_line);
if (!strncmp(cut_line, "vdmos", 5)) {
/* A VDMOS model line, may be vdmosn or vdmosp if re-input. */
wl_append_word(&wl, &wl, copy_substring(curr_line, cut_line));
wlb = wl;
if (search_plain_identifier(cut_line, "pchan")) {
if (search_plain_identifier(cut_line, "pchan") ||
cut_line[5] == 'p') {
wl_append_word(NULL, &wl, copy("vdmosp ("));
}
else if (search_plain_identifier(cut_line, "nchan")) {
wl_append_word(NULL, &wl, copy("vdmosn ("));
}
else {
wl_append_word(NULL, &wl, copy("vdmosn ("));
}
@ -8984,7 +8983,10 @@ static void inp_check_syntax(struct card *deck)
if (check_subs != 0) {
fprintf(cp_err,
"\nError: Mismatch of .subckt ... .ends statements!\n");
fprintf(stderr, " in file %s\n", bugcard->linesource);
if (eq("circbyline", bugcard->linesource))
fprintf(stderr, "in the netlist received from the calling program\n");
else
fprintf(stderr, " in file %s\n", bugcard->linesource);
fprintf(cp_err, " This will cause subsequent errors.\n\n");
if (ends > 0)
fprintf(cp_err, "Check .ends in line number %d\n", ends);
@ -9178,9 +9180,10 @@ static struct modellist *inp_find_model_1(
struct nscope *scope, const char *name)
{
struct modellist *p = scope->models;
for (; p; p = p->next)
for (; p; p = p->next) {
if (model_name_match(name, p->modelname))
break;
}
return p;
}
@ -9715,8 +9718,8 @@ int add_to_sourcepath(const char* filepath, const char* path)
else
return 1;
startwl = newwl = wl_from_string("sourcepath = ( ");
endwl = wl_from_string(" )");
startwl = newwl = wl_from_string("sourcepath=(");
endwl = wl_from_string(")");
/* add fpath to 'sourcepath' list variable */
if (cp_getvar("sourcepath", CP_LIST, NULL, 0)) {
@ -9742,3 +9745,134 @@ int add_to_sourcepath(const char* filepath, const char* path)
tfree(fpath);
return 0;
}
#if defined(_WIN32)
/**
* @brief Resolves a Windows path to its canonical, absolute form using GetFullPathNameW.
*
* This function takes a path string (assumed to be UTF-8), converts it to
* UTF-16, calls the Windows API GetFullPathNameW to resolve '..' and '.'
* components and make the path absolute, and then converts the result back
* to a newly allocated UTF-8 string.
*
* It handles potential failures during conversion or path resolution.
* It does NOT automatically add the '\\?\' prefix for long paths, but
* GetFullPathNameW can produce paths longer than MAX_PATH. The caller
* might need to add the prefix separately if using the result in APIs
* that require it for long path support.
*
* @param input_path The input path string (UTF-8 encoded). Can be relative or
* absolute, may contain '.' or '..'.
* @return char* A newly allocated UTF-8 string containing the canonical absolute
* path, or NULL on failure. The caller is responsible for
* calling free() on the returned string. On failure, errno is
* set to indicate the error (e.g., ENOMEM, EINVAL, ENOENT).
*/
char* get_windows_canonical_path(const char* input_path) {
wchar_t* wPathInput = NULL;
wchar_t* wPathOutput = NULL;
char* utf8PathOutput = NULL;
DWORD inputLenW = 0;
DWORD outputLenW = 0;
DWORD resultLenW = 0;
int inputLenMB = 0;
int outputLenMB = 0;
int original_errno = errno;
if (input_path == NULL) {
errno = EINVAL;
return NULL;
}
inputLenMB = (int)strlen(input_path);
if (inputLenMB == 0) {
inputLenW = 1;
}
else {
inputLenW = MultiByteToWideChar(CP_UTF8, 0, input_path, inputLenMB, NULL, 0);
if (inputLenW == 0) {
errno = EINVAL;
return NULL;
}
inputLenW++;
}
wPathInput = TMALLOC(wchar_t, inputLenW * sizeof(wchar_t));
if (!wPathInput) {
errno = ENOMEM;
return NULL;
}
if (MultiByteToWideChar(CP_UTF8, 0, input_path, inputLenMB + 1, wPathInput, inputLenW) == 0) {
tfree(wPathInput);
errno = EINVAL;
return NULL;
}
errno = original_errno;
outputLenW = GetFullPathNameW(wPathInput, 0, NULL, NULL);
if (outputLenW == 0) {
DWORD dwError = GetLastError();
if (dwError == ERROR_FILE_NOT_FOUND || dwError == ERROR_PATH_NOT_FOUND)
errno = ENOENT;
else if (dwError == ERROR_ACCESS_DENIED)
errno = EACCES;
else
errno = EINVAL;
tfree(wPathInput);
return NULL;
}
wPathOutput = (wchar_t*)malloc(outputLenW * sizeof(wchar_t));
if (!wPathOutput) {
tfree(wPathInput);
errno = ENOMEM;
return NULL;
}
errno = original_errno;
resultLenW = GetFullPathNameW(wPathInput, outputLenW, wPathOutput, NULL);
free(wPathInput);
if (resultLenW == 0 || resultLenW >= outputLenW) {
DWORD dwError = GetLastError();
if (dwError == ERROR_FILE_NOT_FOUND || dwError == ERROR_PATH_NOT_FOUND)
errno = ENOENT;
else if (dwError == ERROR_ACCESS_DENIED)
errno = EACCES;
else
errno = EINVAL;
tfree(wPathOutput);
return NULL;
}
outputLenMB = WideCharToMultiByte(CP_UTF8, 0, wPathOutput, -1, NULL, 0, NULL, NULL);
if (outputLenMB == 0) {
tfree(wPathOutput);
errno = EINVAL;
return NULL;
}
utf8PathOutput = (char*)malloc(outputLenMB);
if (!utf8PathOutput) {
tfree(wPathOutput);
errno = ENOMEM;
return NULL;
}
if (WideCharToMultiByte(CP_UTF8, 0, wPathOutput, -1, utf8PathOutput, outputLenMB, NULL, NULL) == 0) {
tfree(wPathOutput);
tfree(utf8PathOutput);
errno = EINVAL;
return NULL;
}
tfree(wPathOutput);
errno = original_errno;
return utf8PathOutput;
}
#endif

View File

@ -751,9 +751,9 @@ struct card *pspice_compat(struct card *oldcard)
/* .model xxx NMOS/PMOS level=6 --> level = 8, version=3.2.4
.model xxx NMOS/PMOS level=7 --> level = 8, version=3.2.4
.model xxx NMOS/PMOS level=5 --> level = 44
.model xxx NMOS/PMOS level=5 --> only available per Veriloga, OpenVAF and OSDI
.model xxx NMOS/PMOS level=8 --> level = 14, version=4.5.0
.model xxx NPN/PNP level=2 --> level = 6
.model xxx NPN/PNP level=2 --> only available per Veriloga, OpenVAF and OSDI
.model xxx LPNP level=n --> level = 1 subs=-1
Remove any Monte - Carlo variation parameters from .model cards.*/
for (card = newcard; card; card = card->nextcard) {
@ -783,10 +783,11 @@ struct card *pspice_compat(struct card *oldcard)
switch (ll) {
case 5:
{
/* EKV 2.6 in the adms branch */
char* newline = tprintf(".model %s %s level=44 %s", modname, modtype, lv);
tfree(card->line);
card->line = curr_line = newline;
/* EKV 2.6 only per OSDI and OpenVAF */
fprintf(stderr, "Error: MOS model level 5, EKV 2.6, is not available as an intrinsic model.\n");
fprintf(stderr, " Please consider using a Verilog-A model, OpenVAF compilation,\n");
fprintf(stderr, " and the ngspice OSDI interface (see ngspice manual chapter 9).\n");
controlled_exit(EXIT_BAD);
}
break;
case 6:
@ -822,10 +823,11 @@ struct card *pspice_compat(struct card *oldcard)
switch (ll) {
case 2:
{
/* MEXTRAM 504.12.1 in the adms branch */
char* newline = tprintf(".model %s %s level=6 %s", modname, modtype, lv);
tfree(card->line);
card->line = curr_line = newline;
/* MEXTRAM 504.12.1 only per OSDI and OpenVAF */
fprintf(stderr, "Error: Bipolar model level 2, MEXTRAM 504.12.1, is not available as an intrinsic model.\n");
fprintf(stderr, " Please consider using a Verilog-A model, OpenVAF compilation,\n");
fprintf(stderr, " and the ngspice OSDI interface (see ngspice manual chapter 9).\n");
controlled_exit(EXIT_BAD);
}
break;
default:

View File

@ -146,6 +146,7 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam
bool saveall = TRUE;
bool savealli = FALSE;
bool savenosub = FALSE;
bool savenointernals = FALSE;
char *an_name;
int initmem;
/*to resume a run saj
@ -223,6 +224,13 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam
saves[i].used = 1;
continue;
}
if (cieq(saves[i].name, "nointernals")) {
savenointernals = TRUE;
savesused[i] = TRUE;
saves[i].used = 1;
continue;
}
#ifdef SHARED_MODULE
/* this may happen if shared ngspice*/
if (cieq(saves[i].name, "none")) {
@ -255,7 +263,7 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam
/* Pass 1. */
if (numsaves && !saveall && !savenosub) {
if (numsaves && !saveall && !savenosub && !savenointernals) {
for (i = 0; i < numsaves; i++) {
if (!savesused[i]) {
for (j = 0; j < numNames; j++) {
@ -278,15 +286,20 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam
} else {
for (i = 0; i < numNames; i++)
if (!refName || !name_eq(dataNames[i], refName))
/* Save the node as long as it's not an internal device node */
if (!(savenosub && strchr(dataNames[i], '.')) && /* don't save subckt nodes */
/* Save the node (with restrictions) */
/* don't save subckt nodes */
if (!(savenosub && strchr(dataNames[i], '.')) &&
/* no internals at all, but still #branch */
(!(savenointernals && strstr(dataNames[i], "#")) || strstr(dataNames[i], "#branch")) &&
/* created by .probe */
!strstr(dataNames[i], "probe_int_") &&
/* don't save internal device nodes */
!strstr(dataNames[i], "#internal") &&
!strstr(dataNames[i], "#source") &&
!strstr(dataNames[i], "#drain") &&
!strstr(dataNames[i], "#collector") &&
!strstr(dataNames[i], "#collCX") &&
!strstr(dataNames[i], "#emitter") &&
!strstr(dataNames[i], "probe_int_") && /* created by .probe */
!strstr(dataNames[i], "#base"))
{
addDataDesc(run, dataNames[i], dataType, i, initmem);
@ -610,6 +623,8 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr)
#endif
/* interpolated batch mode output to file/plot in transient analysis */
if (interpolated && run->circuit->CKTcurJob->JOBtype == 4) {
/* JOBtype == 4 means Transient Analysis. FIX ME */
if (run->writeOut) { /* To file */
InterpFileAdd(run, refValue, valuePtr);
}
@ -617,10 +632,9 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr)
InterpPlotAdd(run, refValue, valuePtr);
}
return OK;
}
} else if (run->writeOut) {
/* standard batch mode output to file */
/* standard batch mode output to file */
else if (run->writeOut) {
if (run->pointCount == 1) {
fileInit_pass2(run);
}
@ -724,7 +738,6 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr)
#ifdef TCL_MODULE
blt_add(i, valuePtr->v.vec.rVec [run->data[i].outIndex]);
#endif
}
fileEndPoint(run->fp, run->binary);
@ -1218,12 +1231,9 @@ vlength2delta(int len)
return 1024;
}
static void
plotAddRealValue(dataDesc *desc, double value)
void
AddRealValueToVector(struct dvec *v, double value)
{
struct dvec *v = desc->vec;
#ifdef SHARED_MODULE
if (savenone)
/* always save new data to same location */
@ -1245,6 +1255,11 @@ plotAddRealValue(dataDesc *desc, double value)
v->v_dims[0] = v->v_length; /* va, must be updated */
}
static void
plotAddRealValue(dataDesc *desc, double value)
{
AddRealValueToVector(desc->vec, value);
}
static void
plotAddComplexValue(dataDesc *desc, IFcomplex value)

View File

@ -71,5 +71,5 @@ void OUTerrorf(int, const char *fmt, ...) __attribute__ ((format (__printf__, 2
void OUTerrorf(int, const char *fmt, ...);
#endif
void AddRealValueToVector(struct dvec *v, double value);
#endif

View File

@ -23,16 +23,19 @@ Author: 1988 Jeffrey M. Hsu
#include "ngspice/grid.h"
#include "ngspice/sim.h"
#include "ngspice/stringskip.h"
#include "ngspice/evtproto.h"
#include "breakp2.h"
#include "display.h"
#include "graf.h"
#include "graphdb.h"
#include "runcoms.h"
#include "terminal.h"
#include "outitf.h"
static void gr_start_internal(struct dvec *dv, bool copyvec);
static void set(struct plot *plot, struct dbcomm *db, bool value, short mode);
static void setflag(struct plot *plot, struct dbcomm *db,
bool value, short mode);
static char *getitright(char *buf, double num);
/* for legends, set in gr_start, reset in gr_iplot and gr_init */
@ -81,7 +84,7 @@ int gr_init(double *xlims, double *ylims, /* The size of the screen. */
const char *commandline, /* For xi_zoomdata() */
int prevgraph) /* plot id, if started from a previous plot*/
{
GRAPH *graph, *pgraph;
GRAPH *graph, *pgraph;
wordlist *wl;
NG_IGNORE(nplots);
@ -309,7 +312,8 @@ static void drawLine(int x1, int y1, int x2, int y2, struct dvec *dv)
{
if (LC.dv) {
if (LC.dv != dv) {
fprintf(cp_err, "LC: DV changed!\n");
fprintf(cp_err, "LC: DV changed from %s to %s!\n",
LC.dv->v_name, dv->v_name);
LC_flush();
LC.dv = dv;
}
@ -540,11 +544,11 @@ static void gr_start_internal(struct dvec *dv, bool copyvec)
/* Do something special with poles and zeros. Poles are 'x's, and
* zeros are 'o's. */
if (dv->v_type == SV_POLE) {
dv->v_linestyle = 'x';
return;
}
else if (dv->v_type == SV_ZERO) {
} else if (dv->v_type == SV_ZERO) {
dv->v_linestyle = 'o';
return;
}
@ -553,35 +557,34 @@ static void gr_start_internal(struct dvec *dv, bool copyvec)
if (currentgraph->plottype == PLOT_POINT) {
if (pointchars[cur.linestyle - 1]) {
cur.linestyle++;
}
else {
} else {
cur.linestyle = 2;
}
}
else if ((cur.linestyle > 0) &&
(++cur.linestyle == dispdev->numlinestyles)) {
} else if ((cur.linestyle > 0) &&
(++cur.linestyle == dispdev->numlinestyles)) {
cur.linestyle = 2;
}
if ((cur.color > 0) && (++cur.color == dispdev->numcolors))
cur.color = (((currentgraph->grid.gridtype == GRID_SMITH ||
currentgraph->grid.gridtype == GRID_SMITHGRID) &&
(dispdev->numcolors > 3)) ? 4 : 2);
currentgraph->grid.gridtype == GRID_SMITHGRID) &&
(dispdev->numcolors > 3)) ? 4 : 2);
if (currentgraph->plottype == PLOT_POINT) {
dv->v_linestyle = pointchars[cur.linestyle - 2];
}
else {
} else {
dv->v_linestyle = cur.linestyle;
}
dv->v_color = cur.color;
/* Save the data so we can refresh */
link = TMALLOC(struct dveclist, 1);
link->next = currentgraph->plotdata;
/* Either reuse input vector or copy depnding on copyvec */
if (copyvec) {
link->vector = vec_copy(dv);
/* vec_copy doesn't set v_color or v_linestyle */
@ -589,8 +592,7 @@ static void gr_start_internal(struct dvec *dv, bool copyvec)
link->vector->v_linestyle = dv->v_linestyle;
link->vector->v_flags |= VF_PERMANENT;
link->f_own_vector = TRUE;
}
else {
} else {
link->vector = dv;
link->f_own_vector = FALSE;
}
@ -610,6 +612,7 @@ static void gr_start_internal(struct dvec *dv, bool copyvec)
}
/* Put the legend entry on the screen. */
if (!currentgraph->nolegend)
drawlegend(currentgraph, cur.plotno++, dv);
}
@ -846,6 +849,7 @@ void gr_restoretext(GRAPH *graph)
* XXX Or maybe even something more drastic ??
* It would be better to associate a color with an instance using a
* vector than the vector itself, for which color is something artificial. */
static int iplot(struct plot *pl, struct dbcomm *db)
{
double window;
@ -868,7 +872,6 @@ static int iplot(struct plot *pl, struct dbcomm *db)
bool changed = FALSE;
int id, yt;
double xlims[2], ylims[2];
static REQUEST reqst = { checkup_option, NULL };
int inited = 0;
int n_vec_plot = 0;
@ -891,7 +894,9 @@ static int iplot(struct plot *pl, struct dbcomm *db)
strcpy(commandline, "plot ");
index = 5;
resumption = FALSE;
/* Draw the grid for the first time, and plot everything. */
lims = ft_minmax(xs, TRUE);
xlims[0] = lims[0];
xlims[1] = lims[1];
@ -952,22 +957,17 @@ static int iplot(struct plot *pl, struct dbcomm *db)
for (v = pl->pl_dvecs; v; v = v->v_next) {
if (v->v_flags & VF_PLOT) {
gr_start_internal(v, FALSE);
ft_graf(v, xs, TRUE);
ft_graf(v, v->v_scale ? v->v_scale : xs, TRUE);
}
}
inited = 1;
} else {
/* plot the last points and resize if needed */
Input(&reqst, NULL);
/* Window was closed? */
if (!currentgraph)
if (!currentgraph) /* Window was closed? */
return 0;
/* First see if we have to make the screen bigger */
/* Plot the latest points and resize if needed.
* First see if we have to make the screen bigger.
*/
dy = (isreal(xs) ? xs->v_realdata[len - 1] :
realpart(xs->v_compdata[len - 1]));
@ -1039,11 +1039,14 @@ static int iplot(struct plot *pl, struct dbcomm *db)
/* checking for all y values */
for (v = pl->pl_dvecs; v; v = v->v_next) {
int l;
if (!(v->v_flags & VF_PLOT)) {
continue;
}
dy = (isreal(v) ? v->v_realdata[len - 1] :
realpart(v->v_compdata[len - 1]));
l = v->v_length - 1;
dy = (isreal(v) ? v->v_realdata[l] :
realpart(v->v_compdata[l]));
if (ft_grdb) {
fprintf(cp_err, "y = %G\n", dy);
}
@ -1099,12 +1102,65 @@ static int iplot(struct plot *pl, struct dbcomm *db)
#ifndef X_DISPLAY_MISSING
gr_redraw(currentgraph);
#endif
} else {
/* Draw latest point for each vector. */
for (v = pl->pl_dvecs; v; v = v->v_next) {
if (v->v_flags & VF_PLOT) {
if (v->v_flags & VF_EVENT_NODE) {
int last;
if (xs->v_type != SV_TIME) {
/* There will be only one value, ignore. */
continue;
}
last = v->v_length - 1;
if (len > 2 &&
v->v_scale->v_realdata[last] <=
xs->v_realdata[len - 1]) {
/* No recent additions to this vector:
* draw/extend horizontal line showing last value.
* The rest is drawn in callback new_event().
*/
gr_point(v,
xs->v_realdata[len - 1],
v->v_realdata[last],
v->v_scale->v_realdata[last],
v->v_realdata[last],
len - 1);
}
} else {
/* Just connect the last two points.
* This won't be done with curve interpolation,
* so it might look funny. */
gr_point(v,
(isreal(xs) ? xs->v_realdata[len - 1] :
realpart(xs->v_compdata[len - 1])),
(isreal(v) ? v->v_realdata[len - 1] :
realpart(v->v_compdata[len - 1])),
(isreal(xs) ? xs->v_realdata[len - 2] :
realpart(xs->v_compdata[len - 2])),
(isreal(v) ? v->v_realdata[len - 2] :
realpart(v->v_compdata[len - 2])),
len - 1);
}
LC_flush(); // Disable line compression here ..
#ifdef LINE_COMPRESSION_CHECKS
LC.dv = NULL; // ... and suppress warnings.
#endif
}
}
#if BAD
}
else {
/* Just connect the last two points. This won't be done
* with curve interpolation, so it might look funny. */
for (v = pl->pl_dvecs; v; v = v->v_next) {
if (v->v_flags & VF_PLOT) {
if ((v->v_flags & VF_PLOT) && !(v->v_flags & VF_EVENT_NODE)) {
gr_point(v,
(isreal(xs) ? xs->v_realdata[len - 1] :
realpart(xs->v_compdata[len - 1])),
@ -1121,6 +1177,7 @@ static int iplot(struct plot *pl, struct dbcomm *db)
#endif
}
}
#endif // BAD
}
}
DevUpdate();
@ -1128,7 +1185,8 @@ static int iplot(struct plot *pl, struct dbcomm *db)
}
static void set(struct plot *plot, struct dbcomm *db, bool value, short mode)
static void setflag(struct plot *plot, struct dbcomm *db,
bool value, short mode)
{
struct dvec *v;
struct dbcomm *dc;
@ -1143,16 +1201,22 @@ static void set(struct plot *plot, struct dbcomm *db, bool value, short mode)
}
for (dc = db; dc; dc = dc->db_also) {
if (dc->db_nodename1 == NULL)
continue;
v = vec_fromplot(dc->db_nodename1, plot);
if (!v || v->v_plot != plot) {
if (!eq(dc->db_nodename1, "0") && value) {
fprintf(cp_err, "Warning: node %s non-existent in %s.\n",
dc->db_nodename1, plot->pl_name);
/* note: XXX remove it from dbs, so won't get further errors */
if (db->db_type == DB_IPLOT) { /* Vector cached in db_nodename2. */
v = (struct dvec *)dc->db_nodename2;
if (!v)
continue;
} else {
if (dc->db_nodename1 == NULL)
continue;
v = vec_fromplot(dc->db_nodename1, plot);
if (!v || v->v_plot != plot) {
if (!eq(dc->db_nodename1, "0") && value) {
fprintf(cp_err, "Warning: node %s non-existent in %s.\n",
dc->db_nodename1, plot->pl_name);
/* note: XXX remove it from dbs, so no further errors. */
}
continue;
}
continue;
}
if (value)
v->v_flags |= mode;
@ -1181,26 +1245,208 @@ static char *getitright(char *buf, double num)
}
}
static int hit, hit2;
void reset_trace(void)
{
hit = -1;
hit2 = -1;
}
/* This function is called from XSPICE whan an event node that is
* being i-plotted has a confirmed new value.
*/
#ifdef XSPICE
static Mif_Boolean_t new_event(double when, Mif_Value_t *val,
void *ctx, int is_last)
{
struct dbcomm *db = (struct dbcomm *)ctx;
struct dvec *v;
double value;
int last;
if (db->db_type == DB_DEADIPLOT)
return MIF_TRUE;
v = (struct dvec *)db->db_nodename2; // Struct member re-use.
/* Extend vectors. */
last = v->v_length - 1;
AddRealValueToVector(v->v_scale, when);
AddRealValueToVector(v->v_scale, when);
AddRealValueToVector(v, v->v_realdata[last]);
value = val->rvalue + db->db_value2; // Apply any plotting offset.
AddRealValueToVector(v, value);
if (db->db_graphid) {
GRAPH *gr;
gr = FindGraph(db->db_graphid);
if (gr) {
PushGraphContext(gr);
/* Draw horizontal and vertical lines. */
gr_point(v, when, v->v_realdata[last],
v->v_scale->v_realdata[last], v->v_realdata[last],
last > 0);
gr_point(v, when, value, when, v->v_realdata[last], 1);
if (is_last) {
struct dvec *xs;
/* Extend horizontally to the end of the time-step. */
xs = v->v_plot->pl_scale;
gr_point(v, xs->v_realdata[xs->v_length - 1], value,
when, value, 1);
}
LC_flush();
#ifdef LINE_COMPRESSION_CHECKS
LC.dv = NULL; // ... and suppress warnings.
#endif
DevUpdate();
PopGraphContext();
}
}
return MIF_FALSE;
}
#endif
void gr_iplot(struct plot *plot)
{
struct dbcomm *db;
int dontpop; /* So we don't pop w/o push. */
char buf[30];
static REQUEST reqst = { checkup_option, NULL };
struct dbcomm *db, *dc;
int dontpop; /* So we don't pop w/o push. */
char buf[30];
if (Have_graph) {
/* There is at least one graph. Process input on graph windows. */
Input(&reqst, NULL);
}
hit = 0;
for (db = dbs; db; db = db->db_next) {
if (db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL) {
#ifdef XSPICE
if (db->db_iteration > 0) {
double event_node_offset = 0, event_node_spacing;
struct dvec *v;
/* First call: set up event nodes spacing. */
if (db->db_iteration == DB_AUTO_OFFSET) {
/* Magic value: automatically offset traces for
*event nodes.
*/
if (!cp_getvar("event_node_spacing", CP_REAL,
&event_node_spacing, 0)) {
event_node_spacing = 1.5;
}
} else {
event_node_spacing = 0;
}
/* Find any XSPICE event nodes in the node
* list and set up plotting. There is a parallel path
* for pushing new event values into their corresponding
* vectors and plotting them.
*/
for (dc = db; dc; dc = dc->db_also) {
struct dbcomm *dd;
char *offp, save_sign;
int dup = 0;
if (dc->db_nodename1 == NULL)
continue;
/* Duplicated names will corrupt the plot. */
for (dd = db; dd != dc; dd = dd->db_also) {
if (!strcmp(dc->db_nodename1, dd->db_nodename1)) {
dup = 1;
break;
}
}
if (dup)
continue;
/* Check for a nodename that is an expression. */
offp = strchr(dc->db_nodename1, '+');
if (!offp)
offp = strchr(dc->db_nodename1, '-');
if (offp > dc->db_nodename1) {
save_sign = *offp;
*offp = '\0'; // Trim to bare name.
}
v = vec_fromplot(dc->db_nodename1, plot);
if (v) {
dc->db_nodename2 = (char *)v; // Save link to vector.
} else {
fprintf(cp_err,
"Warning: node %s non-existent in %s.\n",
dc->db_nodename1, plot->pl_name);
}
if (v && (v->v_flags & VF_EVENT_NODE)) {
/* Ask event simulator to call back with new values. */
EVTnew_value_call(dc->db_nodename1, new_event,
Evt_Cbt_Plot, dc);
if (offp > dc->db_nodename1) {
*offp = save_sign;
dc->db_value2 = atof(offp); // Offset to value.
event_node_offset = // New auto-offset.
dc->db_value2 + event_node_spacing;
} else if (event_node_spacing) {
char new_name[256];
/* Add offset to vector names.
* Ugly, but only here can event nodes
* be identified.
*/
snprintf(new_name, sizeof new_name, "%s+%g",
dc->db_nodename1, event_node_offset);
tfree(v->v_name);
v->v_name = copy(new_name);
dc->db_value2 = event_node_offset;
event_node_offset += event_node_spacing;
}
if (dc->db_value2) {
int i;
/* Adjust existing values. */
for (i = 0; i < v->v_length; ++i)
v->v_realdata[i] += dc->db_value2;
}
if ((v->v_flags & VF_PERMANENT) == 0) {
vec_new(v);
v->v_flags |= VF_PERMANENT; // Make it findable.
if (v->v_scale) {
v->v_scale->v_flags |= VF_PERMANENT;
vec_new(v->v_scale);
}
}
} else if (offp) {
fprintf(stderr,
"Offset (%s) ignored for analog node %s\n",
offp, dc->db_nodename1);
}
}
db->db_iteration = 0;
}
#endif
if (db->db_graphid) {
GRAPH *gr;
@ -1212,16 +1458,20 @@ void gr_iplot(struct plot *plot)
/* Temporarily set plot flag on matching vector. */
set(plot, db, TRUE, VF_PLOT);
setflag(plot, db, TRUE, VF_PLOT);
dontpop = 0;
if (iplot(plot, db)) {
/* graph just assigned */
db->db_graphid = currentgraph->graphid;
/* Graph just assigned, place id into every struct dbcomm
* as event nodes need that.
*/
for (dc = db; dc; dc = dc->db_also)
dc->db_graphid = currentgraph->graphid;
dontpop = 1;
}
set(plot, db, FALSE, VF_PLOT);
setflag(plot, db, FALSE, VF_PLOT);
if (!dontpop && db->db_graphid)
PopGraphContext();
@ -1231,7 +1481,7 @@ void gr_iplot(struct plot *plot)
struct dvec *v, *u;
int len;
set(plot, db, TRUE, VF_PRINT);
setflag(plot, db, TRUE, VF_PRINT);
len = plot->pl_scale->v_length;
@ -1287,7 +1537,7 @@ void gr_iplot(struct plot *plot)
printf("\n");
}
}
set(plot, db, FALSE, VF_PRINT);
setflag(plot, db, FALSE, VF_PRINT);
}
}
}
@ -1309,6 +1559,7 @@ void gr_end_iplot(void)
prev = NULL;
for (db = dbs; db; prev = db, db = next) {
db->db_nodename2 = NULL; // Forget link.
next = db->db_next;
if (db->db_type == DB_DEADIPLOT) {
if (db->db_graphid) {
@ -1321,6 +1572,7 @@ void gr_end_iplot(void)
}
}
else if (db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL) {
db->db_iteration = DB_NORMAL; // Reset XSPICE event plotting
if (db->db_graphid) {
/* get private copy of dvecs */

View File

@ -41,6 +41,10 @@ typedef struct gbucket {
static GBUCKET GBucket[NUMGBUCKETS];
/* Global variable to indicate that at least one graph exits. Ugly but fast. */
bool Have_graph;
/* note: Zero is not a valid id. This is used in plot() in graf.c. */
static int RunningId = 1;
@ -81,7 +85,7 @@ GRAPH *NewGraph(void)
}
RunningId++;
Have_graph = TRUE;
return pgraph;
} /* end of function NewGraph */
@ -108,7 +112,6 @@ GRAPH *FindGraph(int id)
} /* end of function FindGraph */
GRAPH *CopyGraph(GRAPH *graph)
{
GRAPH *ret;
@ -225,8 +228,15 @@ int DestroyGraph(int id)
if (db && (db->db_type == DB_IPLOT ||
db->db_type == DB_IPLOTALL)) {
db->db_type = DB_DEADIPLOT;
/* Delete this later */
/* Delete this later, after marking as dead.
* Entries on the node mlist are marked to terminate
* any XSPICE callbacks for event nodes.
*/
do {
db->db_type = DB_DEADIPLOT;
db = db->db_also;
} while (db);
return 0;
}
@ -235,7 +245,15 @@ int DestroyGraph(int id)
lastlist->next = list->next;
}
else { /* at front */
int i;
GBucket[index].list = list->next;
for (i = 0; i < NUMGBUCKETS; ++i) {
if (GBucket[i].list)
break;
}
if (i >= NUMGBUCKETS)
Have_graph = FALSE;
}
/* Run through and de-allocate dynamically allocated keyed list */
@ -307,6 +325,7 @@ void FreeGraphs(void)
txfree(deadl);
}
}
Have_graph = FALSE;
} /* end of functdion FreeGraphs */
@ -358,6 +377,3 @@ void PopGraphContext(void)
gcstacktop = gcstacktop->next;
txfree(dead); /* free allocation */
} /* end of function PopGraphContext */

View File

@ -12,4 +12,7 @@ void SetGraphContext(int graphid);
void PushGraphContext(GRAPH *graph);
void PopGraphContext(void);
/* Global variable to indicate that at least one graph exits. Ugly but fast. */
extern bool Have_graph;
#endif

View File

@ -20,7 +20,7 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
static void plotinterval(struct dvec *v, double lo, double hi, register double *coeffs,
int degree, bool rotated);
static int get_xdirection(struct dvec *xs, int len, bool mn);
static int get_xdirection(struct dvec *xs, int len, bool mn, bool analog);
/* Plot the vector v, with scale xs. If we are doing curve-fitting, then
* do some tricky stuff.
@ -90,11 +90,11 @@ ft_graf(struct dvec *v, struct dvec *xs, bool nostart)
if (xs) {
/* Check vector lengths. */
if (v->v_length != xs->v_length) {
if (v->v_length != xs->v_length && !v->v_scale) {
fprintf(stderr,
"Warning: length of vector %s and its scale %s do "
"not match, plot may be truncated!\n",
v->v_name, xs->v_name);
"Warning: length of vector %s (%d) and its scale %s (%d) "
"do not match, plot may be truncated!\n",
v->v_name, v->v_length, xs->v_name, xs->v_length);
}
length = MIN(v->v_length, xs->v_length);
} else {
@ -146,7 +146,8 @@ ft_graf(struct dvec *v, struct dvec *xs, bool nostart)
Then everything is plotted. */
bool mono = (currentgraph->plottype != PLOT_RETLIN);
int dir = get_xdirection(xs, length, mono);
int dir = get_xdirection(xs, length, mono,
!(v->v_flags & VF_EVENT_NODE));
for (i = 0; i < length; i++) {
dx = isreal(xs) ? xs->v_realdata[i] :
realpart(xs->v_compdata[i]);
@ -361,7 +362,7 @@ plotinterval(struct dvec *v, double lo, double hi, register double *coeffs, int
If more than 10% of the data points deviate from the majority direction, issue a warning,
if 'retraceplot' is not set.
*/
static int get_xdirection(struct dvec* xs, int len, bool mn) {
static int get_xdirection(struct dvec* xs, int len, bool mn, bool analog) {
int i, dir = 1, inc = 0, dec = 0;
double dx, lx;
static bool msgsent = FALSE;
@ -379,17 +380,32 @@ static int get_xdirection(struct dvec* xs, int len, bool mn) {
lx = dx;
}
if (inc < 2 && dec < 2)
fprintf(stderr, "Warning, (new) x axis seems to have one data point only\n");
/* Event nodes may never change, so no advance is OK. Similarly, vertical
* edges may falsely suggest that "retrace" is needed.
*/
if (mn && !msgsent && (((double)inc / len > 0.1 && inc < dec) || ((double)dec / len > 0.1 && inc > dec))) {
fprintf(stderr, "Warning, more than 10%% of scale vector %s data points are not monotonic.\n", xs->v_name);
fprintf(stderr, " Please consider using the 'retraceplot' flag to the plot command to plot all data.\n");
msgsent = TRUE;
if (analog) {
if ((inc + dec) == 0) {
fprintf(stderr,
"Warning, (new) x axis (%s) seems to have only one "
"data point: %d points %d increasing %d decreasing.\n",
xs->v_name, xs->v_length, inc, dec);
}
if (mn && !msgsent && (((double)inc / len > 0.1 && inc < dec) ||
((double)dec / len > 0.1 && inc > dec))) {
fprintf(stderr,
"Warning, more than 10%% of scale vector %s data points "
"are not monotonic.\n",
xs->v_name);
fprintf(stderr,
" Please consider using the 'retraceplot' "
"flag to the plot command to plot all data.\n");
msgsent = TRUE;
}
}
if (inc < dec)
dir = -1;
return dir;
}

View File

@ -860,11 +860,15 @@ bool plotit(wordlist *wl, const char *hcopy, const char *devname)
/* Add n * spacing (e.g. 1.5) to digital event node based vectors */
if (digitop) {
double spacing = 1.5;
double spacing;
double nn = 0.;
int ii = 0, jj = 0;
for (d = vecs; d; d = d->v_link2) {
if (!cp_getvar("plot_auto_spacing", CP_REAL, &spacing, 0) ||
spacing < 0.0) {
spacing = 1.5;
}
for (d = vecs; d; d = d->v_link2) {
if ((d->v_flags & VF_EVENT_NODE) &&
!(d->v_flags & VF_PERMANENT) &&
d->v_scale && (d->v_scale->v_flags & VF_EVENT_NODE) &&
@ -884,11 +888,11 @@ bool plotit(wordlist *wl, const char *hcopy, const char *devname)
if (!ylim) {
ylim = TMALLOC(double, 2);
ylim[0] = 0;
/* make ylim[1] a multiple of 2*1.5 */
/* make ylim[1] a multiple of 2 * spacing. */
if (jj % 2 == 0)
ylim[1] = nn;
else
ylim[1] = nn + 1.5;
ylim[1] = nn + spacing;
}
/* re-scaled plot */
else {

View File

@ -164,6 +164,7 @@ if_inpdeck(struct card *deck, INPtables **tab)
/* Parse the .model lines. Enter the model into the global model table modtab. */
modtab = NULL;
modtabhash = NULL;
/* Parse .model lines, put them into 'tab' */
INPpas1(ckt, deck->nextcard, *tab);
/* store the new model table in the current circuit */
ft_curckt->ci_modtab = modtab;

View File

@ -583,11 +583,18 @@ doit(struct card *deck, wordlist *modnames) {
scale = 1;
error = 0;
/* Second pass: do the replacements. */
/* Second pass: do the replacements.
Check if binning is used for .model inside of the subcircuit.
Reduce .model lines to the one with appropriate w and l.
(Inspired by Skywater PDK with excessive use of binning (161 bins)
in the subcircuit referencing a MOS device) */
do { /* while (!error && numpasses-- && gotone) */
struct card *c = deck;
struct card *prev_of_c = NULL;
bool foundmodel = FALSE;
gotone = FALSE;
for (; c; prev_of_c = c, c = c->nextcard) {
if (ciprefix(invoke, c->line)) { /* found reference to .subckt (i.e. component with refdes X) */
@ -597,16 +604,13 @@ doit(struct card *deck, wordlist *modnames) {
gotone = TRUE;
t = tofree = s = copy(c->line); /* s & t hold copy of component line */
/* make scname point to first non-whitepace chars after refdes invocation
* e.g. if invocation is Xreference, *scname = reference
*/
/* scname contains the refdes Xname */
tofree2 = scname = gettok(&s);
/*scname += strlen(invoke); */
while ((*scname == ' ') || (*scname == '\t') || (*scname == ':'))
scname++;
/* Now set s to point to last non-space chars in line (i.e.
* the name of the model invoked
/* Now set s to point to last non-space chars in the x line (i.e.
* the name of the model invoked)
*/
while (*s)
s++;
@ -617,38 +621,47 @@ doit(struct card *deck, wordlist *modnames) {
s--;
s++;
/* iterate through .subckt list and look for .subckt name invoked */
/* Iterate through .subckt list and look for .subckt name
corresponding to the subckt name extracted from the x line */
for (sss = subs; sss; sss = sss->su_next)
if (eq(sss->su_name, s))
break;
/* At this point, sss points to the .subckt invoked,
* and scname points to the netnames
* involved.
/* At this point,
* c is the card with the x line.
* scname points to the netname of the x line involved.
* s is the subckt name extracted from the x line.
* sss points to the subcircuit referenced by the x line
* sss->su_def is the contents of the subcircuit.
*/
/* If no .subckt is found, don't complain -- this might be an
* instance of a subckt that is defined above at higher level.
*/
if (sss) {
// tprint(sss->su_def);
/* copy of the contents between .subckt and .ends */
struct card *su_deck = inp_deckcopy(sss->su_def);
/* If we have modern PDKs, we have to reduce the amount of memory required.
We try to reduce the models to the one really used.
Otherwise su_deck is full of unused binning models.*/
Otherwise su_deck is full of unused binning models.
c->w > 0 and c->l > 0 point to an x line with given w and l
(typically a call to a MOS device). */
if ((newcompat.hs || newcompat.spe) && c->w > 0 && c->l > 0) {
/* extract wmin, wmax, lmin, lmax */
struct card* new_deck = su_deck;
struct card* enter_su_deck = su_deck;
struct card* prev = NULL;
while (su_deck) {
/* find a .model line */
if (!ciprefix(".model", su_deck->line)) {
prev = su_deck;
su_deck = su_deck->nextcard;
continue;
}
/* check if line contains wmin, wmax, lmin, lmax
if available, extract its values,
if not, go to next line */
char* curr_line = su_deck->line;
float fwmin, fwmax, flmin, flmax;
char *wmin = strstr(curr_line, " wmin=");
@ -716,32 +729,39 @@ doit(struct card *deck, wordlist *modnames) {
su_deck = su_deck->nextcard;
continue;
}
/* check if x line's w and l are withing the limites of wmin, wmax, lmin, lmax */
float csl = (float)scale * c->l;
/* scale by nf */
float csw = (float)scale * c->w / c->nf;
/*fprintf(stdout, "Debug: nf = %f\n", c->nf);*/
if (csl >= flmin && csl < flmax && csw >= fwmin && csw < fwmax) {
/* use the current .model card */
/* if within the limits, use the current .model card */
prev = su_deck;
su_deck = su_deck->nextcard;
foundmodel = TRUE;
continue;
}
else {
/* if not within the limits,
delete the .model line not fitting the device */
struct card* tmpcard = su_deck->nextcard;
line_free_x(prev->nextcard, FALSE);
su_deck = prev->nextcard = tmpcard;
}
}
su_deck = new_deck;
/* go back to the first card of su_deck */
su_deck = enter_su_deck;
}
if (!su_deck) {
fprintf(stderr, "\nError: Could not find a model for device %s in subcircuit %s\n",
scname, sss->su_name);
if (!foundmodel && (newcompat.hs || newcompat.spe) && c->w > 0 && c->l > 0) {
fprintf(stderr, "\nError: Could not find a model\n"
" for device %s in transistor subcircuit %s\n", scname, sss->su_name);
fprintf(stderr, " with w = %.3g and l = %.3g\n\n", c->w, c->l);
controlled_exit(1);
}
foundmodel = FALSE;
struct card *rest_of_c = c->nextcard;
/* Now we have to replace this line with the
@ -782,8 +802,8 @@ doit(struct card *deck, wordlist *modnames) {
tfree(tofree);
tfree(tofree2);
}
}
} /* if (ciprefix(invoke, c->line)) */
} /* for (; c; prev_of_c = c, c = c->nextcard) */
} while (!error && numpasses-- && gotone);

View File

@ -78,6 +78,14 @@ struct Evt_Inst_Index {
int index; /* the value of the index */
};
struct Evt_Node_Cb {
struct Evt_Node_Cb *next;
Evt_New_Value_Cb_t fn; /* Function to be called. */
Evt_Node_Cb_Type_t type; /* Data type to pass to fn. */
const char *member; /* For event data type's plot fn. */
void *ctx;
};
struct Evt_Node_Info {
Evt_Node_Info_t *next; /* the next in the linked list */
char *name; /* Name of node in deck */
@ -88,6 +96,7 @@ struct Evt_Node_Info {
int num_outputs; /* Number of outputs connected to this node */
int num_insts; /* The number of insts receiving node as input */
Evt_Inst_Index_t *inst_list; /* Linked list of indexes of these instances */
Evt_Node_Cb_t *cbs; /* New value callbacks. */
};
struct Evt_Inst_Info {
@ -195,8 +204,6 @@ struct Evt_Queue {
/* ************** */
struct Evt_Node {
Evt_Node_t *next; /* pointer to next in linked list */
Mif_Boolean_t op; /* true if computed from op analysis */
@ -204,6 +211,7 @@ struct Evt_Node {
void **output_value; /* Array of outputs posted to this node */
void *node_value; /* Resultant computed from output values */
void *inverted_value; /* Inverted copy of node_value */
};
struct Evt_Node_Data {
@ -362,6 +370,4 @@ struct Evt_Ckt_Data {
Evt_Option_t options; /* Data input on .options cards */
};
#endif

View File

@ -136,6 +136,30 @@ bool Evtcheck_nodes(
struct INPtables *stab); /* Symbol table. */
struct dvec *EVTfindvec(char *node);
/* Set and remove call-backs on new node values. */
Mif_Boolean_t EVTnew_value_call(const char *node,
Evt_New_Value_Cb_t fn,
Evt_Node_Cb_Type_t type,
void *ctx);
void EVTcancel_value_call(const char *node,
Evt_New_Value_Cb_t fn,
void *ctx);
/* Parse a node name with member and return the node index and type. */
struct node_parse {
char *node;
char *member;
int udn_index;
};
int Evt_Parse_Node(const char *node, struct node_parse *result);
/* Internal utility functions. */
void Evt_purge_free_outputs(void);
#endif

View File

@ -1,6 +1,6 @@
#ifndef ngspice_EVTTYPES_H
#define ngspice_EVTTYPES_H
#include "miftypes.h"
typedef struct Evt_Output_Info Evt_Output_Info_t;
typedef struct Evt_Port_Info Evt_Port_Info_t;
@ -28,6 +28,11 @@ typedef struct Evt_Limit Evt_Limit_t;
typedef struct Evt_Job Evt_Job_t;
typedef struct Evt_Option Evt_Option_t;
typedef struct Evt_Ckt_Data Evt_Ckt_Data_t;
typedef struct Evt_Node_Cb Evt_Node_Cb_t;
typedef Mif_Boolean_t (*Evt_New_Value_Cb_t)(double when, Mif_Value_t *val_p,
void *ctx, int is_last);
typedef enum Evt_Node_Cb_Type { Evt_Cbt_Raw, Evt_Cbt_Plot} Evt_Node_Cb_Type_t;
#endif

View File

@ -34,7 +34,13 @@ Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group
#define DBC_GTE 5 /* >= (ge) */
#define DBC_LTE 6 /* <= (le) */
/* Below, members db_op and db_value1 are re-purposed by iplot options. */
/* Below, members db_nodename2, db_op, db_iteration and db_value1/2
* are re-purposed by iplot optionsf.
* These definitions are used for db_iteration:
*/
#define DB_NORMAL 1
#define DB_AUTO_OFFSET 2
struct dbcomm {
int db_number; /* The number of this debugging command. */

View File

@ -357,6 +357,18 @@ typedef int (SendInitEvtData)(int, int, char*, char*, int, void*);
int identification number of calling ngspice shared lib
void* return pointer received from caller
*/
/* Upon time step finished, all events that occurred on a node.
* A non-zero return value cancels further reports for tis node.
*/
typedef int (SendRawEvtData)(double, void *, void *, int);
/*
double event time
void* pointer to the node's value (a Digital_t for digital nodes)
void* return pointer received from caller
int zero if another event report for the same node follows
*/
#endif
/* ngspice initialization,
@ -415,6 +427,32 @@ userData: pointer to user-defined data, will not be modified, but
handed over back to caller during Callback, e.g. address of calling object */
IMPEXP
int ngSpice_Init_Evt(SendEvtData* sevtdata, SendInitEvtData* sinitevtdata, void* userData);
/* Request callback for every event on a specific XSPICE event node.
* A single callback function pointer is stored, with all calls directed
* to the function specified last.
* The return value identifies the node data type or is -1 on error.
*
* node name of an event node.
* srawevt pointer to callback function.
* userData pointer to user-defined data.
*/
IMPEXP
int ngSpice_Raw_Evt(const char* node, SendRawEvtData* srawevt, void* userData);
/* Decode raw event node data. Return 0 on success.
* evt pointer to event data (a reported node value).
* type node type index, return value from ngSpice_Raw_Evt().
* pplotval pointer to a double, the "plotting value" is returned. NULL OK.
* printval pointer to a char pointer that is updated to point to a
* readonly string describing the value. If evt is NULL, a string
* identifying the node data type is returned. NULL is OK.
*/
IMPEXP
int ngSpice_Decode_Evt(void* evt, int type,
double *pplotval, const char **pprintval);
#endif

View File

@ -1252,11 +1252,30 @@ int main(int argc, char **argv)
else {
if (readinit) {
/* load user's initialisation file
try accessing the initialisation file .spiceinit in a user provided
path read from environmental variable SPICE_USERINIT_DIR,
if that fails try the alternate name spice.rc, then look into
the current directory, then the HOME directory, then into USERPROFILE */
try accessing the initialisation file .spiceinit
(If it fails, try the alternate name spice.rc):
- in the directory from where the netlist has been loaded
- in a user provided path read from environmental variable SPICE_USERINIT_DIR,
- in the current directory,
- in the the HOME directory,
- in the USERPROFILE directory. */
do {
{
if (optind <= argc) {
char* inpath = ngdirname(argv[optind]);
if (inpath) {
if (read_initialisation_file(inpath, INITSTR) != FALSE) {
FREE(inpath);
break;
}
if (read_initialisation_file(inpath, ALT_INITSTR) != FALSE) {
FREE(inpath);
break;
}
FREE(inpath);
}
}
}
{
const char* const userinit = getenv("SPICE_USERINIT_DIR");
if (userinit) {
@ -1340,6 +1359,16 @@ int main(int argc, char **argv)
#elif defined(WaGauss)
initw();
#endif
/* write out the ngspice start command */
if (ft_ngdebug)
{
int ni;
fprintf(stdout, "\nNote: ngspice start command line:\n");
for (ni = 0; ni < argc; ni++) {
fprintf(stdout, " %s", argv[ni]);
}
fprintf(stdout, "\n\n");
}
if (!ft_servermode) {
@ -1539,8 +1568,9 @@ int main(int argc, char **argv)
}
else {
fprintf(stderr,
"Note: No \".plot\", \".print\", or \".fourier\" lines; "
"no simulations run\n");
"Error: incomplete or empty netlist\n"
" or no \".plot\", \".print\", or \".fourier\" lines in batch mode;\n"
"no simulations run!\n");
sp_shutdown(EXIT_BAD);
}

View File

@ -129,7 +129,7 @@ spCreate(int Size, int Complex, int *pError)
/* Test for valid size. */
#if EXPANDABLE
if (Size < 0) {
*pError = spPANIC;
*pError = spPANIC;
return NULL;
}
#else
@ -153,8 +153,8 @@ spCreate(int Size, int Complex, int *pError)
SizePlusOne = (unsigned)(AllocatedSize + 1);
if ((Matrix = SP_MALLOC(struct MatrixFrame, 1)) == NULL) {
*pError = spNO_MEMORY;
return NULL;
*pError = spNO_MEMORY;
return NULL;
}
/* Initialize matrix */
@ -237,7 +237,7 @@ spCreate(int Size, int Complex, int *pError)
/* Initialize MapIntToExt vectors. */
for (I = 1; I <= AllocatedSize; I++)
{
Matrix->IntToExtRowMap[I] = I;
Matrix->IntToExtRowMap[I] = I;
Matrix->IntToExtColMap[I] = I;
}
@ -252,8 +252,8 @@ spCreate(int Size, int Complex, int *pError)
/* Initialize MapExtToInt vectors. */
for (I = 1; I <= AllocatedSize; I++) {
Matrix->ExtToIntColMap[I] = -1;
Matrix->ExtToIntRowMap[I] = -1;
Matrix->ExtToIntColMap[I] = -1;
Matrix->ExtToIntRowMap[I] = -1;
}
Matrix->ExtToIntColMap[0] = 0;
Matrix->ExtToIntRowMap[0] = 0;
@ -317,7 +317,7 @@ spcGetElement(MatrixPtr Matrix)
#if !COMBINE || STRIP || LINT
/* Allocate block of MatrixElements if necessary. */
if (Matrix->ElementsRemaining == 0) {
pElements = SP_MALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION);
pElements = SP_MALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION);
RecordAllocation( Matrix, pElements );
if (Matrix->Error == spNO_MEMORY) return NULL;
Matrix->ElementsRemaining = ELEMENTS_PER_ALLOCATION;
@ -422,7 +422,7 @@ InitializeElementBlocks(MatrixPtr Matrix, int InitialNumberOfElements,
Matrix->FirstElementListNode->pElementList = pElement;
Matrix->FirstElementListNode->NumberOfElementsInList =
InitialNumberOfElements;
InitialNumberOfElements;
Matrix->FirstElementListNode->Next = NULL;
/* Allocate block of MatrixElements for fill-ins. */
@ -548,15 +548,15 @@ RecordAllocation(MatrixPtr Matrix, void *AllocatedPtr )
/* If Allocated pointer is NULL, assume that tmalloc returned a
* NULL pointer, which indicates a spNO_MEMORY error. */
if (AllocatedPtr == NULL) {
Matrix->Error = spNO_MEMORY;
Matrix->Error = spNO_MEMORY;
return;
}
/* Allocate block of MatrixElements if necessary. */
if (Matrix->RecordsRemaining == 0) {
AllocateBlockOfAllocationList( Matrix );
AllocateBlockOfAllocationList( Matrix );
if (Matrix->Error == spNO_MEMORY) {
SP_FREE(AllocatedPtr);
SP_FREE(AllocatedPtr);
return;
}
}

View File

@ -67,7 +67,6 @@
/*
* Function declarations
*/
@ -78,7 +77,6 @@ static void ExpandTranslationArrays( MatrixPtr, int );
/*
* CLEAR MATRIX
*
@ -105,28 +103,28 @@ spClear(MatrixPtr Matrix)
/* Clear matrix. */
if (Matrix->PreviousMatrixWasComplex || Matrix->Complex)
{
for (I = Matrix->Size; I > 0; I--)
{
pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
{
pElement->Real = 0.0;
pElement->Imag = 0.0;
pElement = pElement->NextInCol;
}
}
for (I = Matrix->Size; I > 0; I--)
{
pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
{
pElement->Real = 0.0;
pElement->Imag = 0.0;
pElement = pElement->NextInCol;
}
}
}
else
{
for (I = Matrix->Size; I > 0; I--)
{
pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
{
pElement->Real = 0.0;
pElement = pElement->NextInCol;
}
}
for (I = Matrix->Size; I > 0; I--)
{
pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
{
pElement->Real = 0.0;
pElement = pElement->NextInCol;
}
}
}
/* Empty the trash. */
@ -225,7 +223,6 @@ ElementPtr pElement;
}
/*
* SINGLE ELEMENT ADDITION TO MATRIX BY INDEX
*
@ -270,7 +267,7 @@ spGetElement(MatrixPtr Matrix, int Row, int Col)
assert( IS_SPARSE( Matrix ) && Row >= 0 && Col >= 0 );
if ((Row == 0) || (Col == 0))
return &Matrix->TrashCan.Real;
return &Matrix->TrashCan.Real;
#if !TRANSLATE
assert(Matrix->NeedsOrdering);
@ -289,8 +286,9 @@ spGetElement(MatrixPtr Matrix, int Row, int Col)
#if EXPANDABLE
/* Re-size Matrix if necessary. */
if ((Row > Matrix->Size) || (Col > Matrix->Size))
EnlargeMatrix( Matrix, MAX(Row, Col) );
if (Matrix->Error == spNO_MEMORY) return NULL;
EnlargeMatrix( Matrix, MAX(Row, Col) );
if (Matrix->Error == spNO_MEMORY)
return NULL;
#endif
#endif
@ -305,12 +303,12 @@ spGetElement(MatrixPtr Matrix, int Row, int Col)
if ((Row != Col) || ((pElement = Matrix->Diag[Row]) == NULL))
{
/* Element does not exist or does not reside along diagonal.
* Search column for element. As in the if statement above,
* the pointer to the element which is returned by
* spcFindElementInCol is cast into a pointer to Real, a
* RealNumber. */
pElement = spcFindElementInCol( Matrix,
/* Element does not exist or does not reside along diagonal.
* Search column for element. As in the if statement above,
* the pointer to the element which is returned by
* spcFindElementInCol is cast into a pointer to Real, a
* RealNumber. */
pElement = spcFindElementInCol( Matrix,
&(Matrix->FirstInCol[Col]),
Row, Col, YES );
}
@ -321,12 +319,6 @@ spGetElement(MatrixPtr Matrix, int Row, int Col)
/*
* FIND ELEMENT BY SEARCHING COLUMN
*
@ -371,36 +363,33 @@ spcFindElementInCol(MatrixPtr Matrix, ElementPtr *LastAddr,
/* Search for element. */
while (pElement != NULL)
{
if (pElement->Row < Row)
if (pElement->Row < Row)
{
/* Have not reached element yet. */
LastAddr = &(pElement->NextInCol);
pElement = pElement->NextInCol;
/* Have not reached element yet. */
LastAddr = &(pElement->NextInCol);
pElement = pElement->NextInCol;
}
else if (pElement->Row == Row)
else if (pElement->Row == Row)
{
/* Reached element. */
return pElement;
/* Reached element. */
return pElement;
}
else break; /* while loop */
else break; /* while loop */
}
/* Element does not exist and must be created. */
if (CreateIfMissing)
return spcCreateElement( Matrix, Row, Col, LastAddr, NO );
return spcCreateElement( Matrix, Row, Col, LastAddr, NO );
else
return NULL;
return NULL;
}
#if TRANSLATE
/*
* TRANSLATE EXTERNAL INDICES TO INTERNAL
*
@ -457,7 +446,7 @@ Translate(MatrixPtr Matrix, int *Row, int *Col)
/* Translate external row or node number to internal row or node number. */
if ((IntRow = Matrix->ExtToIntRowMap[ExtRow]) == -1)
{
Matrix->ExtToIntRowMap[ExtRow] = ++Matrix->CurrentSize;
Matrix->ExtToIntRowMap[ExtRow] = ++Matrix->CurrentSize;
Matrix->ExtToIntColMap[ExtRow] = Matrix->CurrentSize;
IntRow = Matrix->CurrentSize;
@ -466,7 +455,7 @@ Translate(MatrixPtr Matrix, int *Row, int *Col)
#endif
#if EXPANDABLE
/* Re-size Matrix if necessary. */
/* Re-size Matrix if necessary. */
if (IntRow > Matrix->Size)
EnlargeMatrix( Matrix, IntRow );
if (Matrix->Error == spNO_MEMORY) return;
@ -479,7 +468,7 @@ Translate(MatrixPtr Matrix, int *Row, int *Col)
/* Translate external column or node number to internal column or node number.*/
if ((IntCol = Matrix->ExtToIntColMap[ExtCol]) == -1)
{
Matrix->ExtToIntRowMap[ExtCol] = ++Matrix->CurrentSize;
Matrix->ExtToIntRowMap[ExtCol] = ++Matrix->CurrentSize;
Matrix->ExtToIntColMap[ExtCol] = Matrix->CurrentSize;
IntCol = Matrix->CurrentSize;
@ -488,7 +477,7 @@ Translate(MatrixPtr Matrix, int *Row, int *Col)
#endif
#if EXPANDABLE
/* Re-size Matrix if necessary. */
/* Re-size Matrix if necessary. */
if (IntCol > Matrix->Size)
EnlargeMatrix( Matrix, IntCol );
if (Matrix->Error == spNO_MEMORY) return;
@ -508,7 +497,6 @@ Translate(MatrixPtr Matrix, int *Row, int *Col)
#if QUAD_ELEMENT
/*
* ADDITION OF ADMITTANCE TO MATRIX BY INDEX
@ -573,7 +561,6 @@ spGetAdmittance(MatrixPtr Matrix, int Node1, int Node2,
#if QUAD_ELEMENT
/*
* ADDITION OF FOUR ELEMENTS TO MATRIX BY INDEX
@ -656,7 +643,6 @@ spGetQuad(MatrixPtr Matrix, int Row1, int Row2, int Col1, int Col2,
#if QUAD_ELEMENT
/*
* ADDITION OF FOUR STRUCTURAL ONES TO MATRIX BY INDEX
@ -723,7 +709,6 @@ spGetOnes(MatrixPtr Matrix, int Pos, int Neg, int Eqn,
/*
*
* CREATE AND SPLICE ELEMENT INTO MATRIX
@ -778,21 +763,22 @@ spcCreateElement(MatrixPtr Matrix, int Row, int Col,
/* Row pointers cannot be ignored. */
if (Fillin)
{
pElement = spcGetFillin( Matrix );
pElement = spcGetFillin( Matrix );
Matrix->Fillins++;
}
else
{
pElement = spcGetElement( Matrix );
Matrix->Originals++;
pElement = spcGetElement( Matrix );
Matrix->Originals++;
Matrix->NeedsOrdering = YES;
}
if (pElement == NULL) return NULL;
/* If element is on diagonal, store pointer in Diag. */
if (Row == Col) Matrix->Diag[Row] = pElement;
/* If element is on diagonal, store pointer in Diag. */
if (Row == Col)
Matrix->Diag[Row] = pElement;
/* Initialize Element. */
/* Initialize Element. */
pCreatedElement = pElement;
pElement->Row = Row;
pElement->Col = Col;
@ -802,55 +788,54 @@ spcCreateElement(MatrixPtr Matrix, int Row, int Col,
pElement->pInitInfo = NULL;
#endif
/* Splice element into column. */
/* Splice element into column. */
pElement->NextInCol = *LastAddr;
*LastAddr = pElement;
/* Search row for proper element position. */
/* Search row for proper element position. */
pElement = Matrix->FirstInRow[Row];
pLastElement = NULL;
while (pElement != NULL)
{
/* Search for element row position. */
/* Search for element row position. */
if (pElement->Col < Col)
{
/* Have not reached desired element. */
/* Have not reached desired element. */
pLastElement = pElement;
pElement = pElement->NextInRow;
}
else pElement = NULL;
}
/* Splice element into row. */
/* Splice element into row. */
pElement = pCreatedElement;
if (pLastElement == NULL)
{
/* Element is first in row. */
/* Element is first in row. */
pElement->NextInRow = Matrix->FirstInRow[Row];
Matrix->FirstInRow[Row] = pElement;
}
else
{
/* Element is not first in row. */
/* Element is not first in row. */
pElement->NextInRow = pLastElement->NextInRow;
pLastElement->NextInRow = pElement;
}
}
else
{
/* Matrix has not been factored yet. Thus get element rather
* than fill-in. Also, row pointers can be ignored. */
/* Matrix has not been factored yet. Thus get element rather
* than fill-in. Also, row pointers can be ignored. */
/* Allocate memory for Element. */
/* Allocate memory for Element. */
pElement = spcGetElement( Matrix );
Matrix->Originals++;
Matrix->Originals++;
if (pElement == NULL) return NULL;
/* If element is on diagonal, store pointer in Diag. */
/* If element is on diagonal, store pointer in Diag. */
if (Row == Col) Matrix->Diag[Row] = pElement;
/* Initialize Element. */
/* Initialize Element. */
pCreatedElement = pElement;
pElement->Row = Row;
#if DEBUG
@ -862,7 +847,7 @@ spcCreateElement(MatrixPtr Matrix, int Row, int Col,
pElement->pInitInfo = NULL;
#endif
/* Splice element into column. */
/* Splice element into column. */
pElement->NextInCol = *LastAddr;
*LastAddr = pElement;
}
@ -876,8 +861,6 @@ spcCreateElement(MatrixPtr Matrix, int Row, int Col,
/*
*
* LINK ROWS
@ -915,12 +898,12 @@ spcLinkRows(MatrixPtr Matrix)
FirstInRowArray = Matrix->FirstInRow;
for (Col = Matrix->Size; Col >= 1; Col--)
{
/* Generate row links for the elements in the Col'th column. */
/* Generate row links for the elements in the Col'th column. */
pElement = Matrix->FirstInCol[Col];
while (pElement != NULL)
{
pElement->Col = Col;
pElement->Col = Col;
FirstInRowEntry = &FirstInRowArray[pElement->Row];
pElement->NextInRow = *FirstInRowEntry;
*FirstInRowEntry = pElement;
@ -937,7 +920,6 @@ spcLinkRows(MatrixPtr Matrix)
/*
* ENLARGE MATRIX
*
@ -971,27 +953,27 @@ EnlargeMatrix(MatrixPtr Matrix, int NewSize)
if (( SP_REALLOC(Matrix->IntToExtColMap, int, NewSize+1)) == NULL)
{
Matrix->Error = spNO_MEMORY;
Matrix->Error = spNO_MEMORY;
return;
}
if (( SP_REALLOC(Matrix->IntToExtRowMap, int, NewSize+1)) == NULL)
{
Matrix->Error = spNO_MEMORY;
Matrix->Error = spNO_MEMORY;
return;
}
if (( SP_REALLOC(Matrix->Diag, ElementPtr, NewSize+1)) == NULL)
{
Matrix->Error = spNO_MEMORY;
Matrix->Error = spNO_MEMORY;
return;
}
if (( SP_REALLOC(Matrix->FirstInCol, ElementPtr, NewSize+1)) == NULL)
{
Matrix->Error = spNO_MEMORY;
Matrix->Error = spNO_MEMORY;
return;
}
if (( SP_REALLOC(Matrix->FirstInRow, ElementPtr, NewSize+1)) == NULL)
{
Matrix->Error = spNO_MEMORY;
Matrix->Error = spNO_MEMORY;
return;
}
@ -1008,7 +990,7 @@ EnlargeMatrix(MatrixPtr Matrix, int NewSize)
/* Initialize the new portion of the vectors. */
for (I = OldAllocatedSize+1; I <= NewSize; I++)
{
Matrix->IntToExtColMap[I] = I;
Matrix->IntToExtColMap[I] = I;
Matrix->IntToExtRowMap[I] = I;
Matrix->Diag[I] = NULL;
Matrix->FirstInRow[I] = NULL;
@ -1026,7 +1008,6 @@ EnlargeMatrix(MatrixPtr Matrix, int NewSize)
#if TRANSLATE
/*
* EXPAND TRANSLATION ARRAYS
*
@ -1061,19 +1042,19 @@ ExpandTranslationArrays(MatrixPtr Matrix, int NewSize)
if (( SP_REALLOC(Matrix->ExtToIntRowMap, int, NewSize+1)) == NULL)
{
Matrix->Error = spNO_MEMORY;
Matrix->Error = spNO_MEMORY;
return;
}
if (( SP_REALLOC(Matrix->ExtToIntColMap, int, NewSize+1)) == NULL)
{
Matrix->Error = spNO_MEMORY;
Matrix->Error = spNO_MEMORY;
return;
}
/* Initialize the new portion of the vectors. */
for (I = OldAllocatedSize+1; I <= NewSize; I++)
{
Matrix->ExtToIntRowMap[I] = -1;
Matrix->ExtToIntRowMap[I] = -1;
Matrix->ExtToIntColMap[I] = -1;
}
@ -1087,8 +1068,6 @@ ExpandTranslationArrays(MatrixPtr Matrix, int NewSize)
#if INITIALIZE
/*
* INITIALIZE MATRIX
@ -1154,12 +1133,12 @@ spInitialize(MatrixPtr Matrix, int (*pInit)(RealNumber*, void *InitInfo, int , i
/* Clear imaginary part of matrix if matrix is real but was complex. */
if (Matrix->PreviousMatrixWasComplex && !Matrix->Complex)
{
for (J = Matrix->Size; J > 0; J--)
for (J = Matrix->Size; J > 0; J--)
{
pElement = Matrix->FirstInCol[J];
while (pElement != NULL)
{
pElement->Imag = 0.0;
pElement->Imag = 0.0;
pElement = pElement->NextInCol;
}
}
@ -1168,22 +1147,22 @@ spInitialize(MatrixPtr Matrix, int (*pInit)(RealNumber*, void *InitInfo, int , i
/* Initialize the matrix. */
for (J = Matrix->Size; J > 0; J--)
{
pElement = Matrix->FirstInCol[J];
pElement = Matrix->FirstInCol[J];
Col = Matrix->IntToExtColMap[J];
while (pElement != NULL)
{
if (pElement->pInitInfo == NULL)
if (pElement->pInitInfo == NULL)
{
pElement->Real = 0.0;
pElement->Imag = 0.0;
pElement->Real = 0.0;
pElement->Imag = 0.0;
}
else
{
Error = pInit (& pElement->Real, pElement->pInitInfo,
Error = pInit (& pElement->Real, pElement->pInitInfo,
Matrix->IntToExtRowMap[pElement->Row], Col);
if (Error)
{
Matrix->Error = spFATAL;
Matrix->Error = spFATAL;
return Error;
}

View File

@ -18,33 +18,33 @@
*/
/*
* Revision and copyright information.
*
* Copyright (c) 1985,86,87,88,89,90
* by Kenneth S. Kundert and the University of California.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the copyright notices appear in all copies and
* supporting documentation and that the authors and the University of
* California are properly credited. The authors and the University of
* California make no representations as to the suitability of this
* software for any purpose. It is provided `as is', without express
* or implied warranty.
*/
/*
* Revision and copyright information.
*
* Copyright (c) 1985,86,87,88,89,90
* by Kenneth S. Kundert and the University of California.
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby granted,
* provided that the copyright notices appear in all copies and
* supporting documentation and that the authors and the University of
* California are properly credited. The authors and the University of
* California make no representations as to the suitability of this
* software for any purpose. It is provided `as is', without express
* or implied warranty.
*/
/*
* IMPORTS
*
* >>> Import descriptions:
* spConfig.h
* Macros that customize the sparse matrix routines.
* spMatrix.h
* Macros and declarations to be imported by the user.
* spDefs.h
* Matrix type and macro definitions for the sparse matrix routines.
*/
/*
* IMPORTS
*
* >>> Import descriptions:
* spConfig.h
* Macros that customize the sparse matrix routines.
* spMatrix.h
* Macros and declarations to be imported by the user.
* spDefs.h
* Matrix type and macro definitions for the sparse matrix routines.
*/
#include <assert.h>
#include <stdlib.h>
@ -63,7 +63,7 @@ int Printer_Width = PRINTER_WIDTH;
#if DOCUMENTATION
/*
* PRINT MATRIX
*
@ -140,22 +140,22 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header)
int J = 0;
int I, Row, Col, Size, Top;
int StartCol = 1, StopCol, Columns, ElementCount = 0;
double Magnitude;
double SmallestDiag = 0;
double Magnitude;
double SmallestDiag = 0;
double SmallestElement = 0;
double LargestElement = 0.0, LargestDiag = 0.0;
ElementPtr pElement, *pImagElements;
int *PrintOrdToIntRowMap, *PrintOrdToIntColMap;
ElementPtr pElement, * pImagElements;
int* PrintOrdToIntRowMap, * PrintOrdToIntColMap;
/* Begin `spPrint'. */
assert( IS_SPARSE( Matrix ) );
assert(IS_SPARSE(Matrix));
Size = Matrix->Size;
SP_CALLOC(pImagElements, ElementPtr, Printer_Width / 10 + 1);
if ( pImagElements == NULL)
if (pImagElements == NULL)
{
Matrix->Error = spNO_MEMORY;
SP_FREE(pImagElements);
return;
Matrix->Error = spNO_MEMORY;
SP_FREE(pImagElements);
return;
}
/* Create a packed external to internal row and column translation
@ -165,49 +165,49 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header)
#else
Top = Matrix->AllocatedSize;
#endif
SP_CALLOC( PrintOrdToIntRowMap, int, Top + 1 );
if ( PrintOrdToIntRowMap == NULL)
SP_CALLOC(PrintOrdToIntRowMap, int, Top + 1);
if (PrintOrdToIntRowMap == NULL)
{
Matrix->Error = spNO_MEMORY;
SP_FREE(pImagElements);
Matrix->Error = spNO_MEMORY;
SP_FREE(pImagElements);
return;
}
SP_CALLOC( PrintOrdToIntColMap, int, Top + 1 );
SP_CALLOC(PrintOrdToIntColMap, int, Top + 1);
if (PrintOrdToIntColMap == NULL)
{
Matrix->Error = spNO_MEMORY;
SP_FREE(pImagElements);
Matrix->Error = spNO_MEMORY;
SP_FREE(pImagElements);
SP_FREE(PrintOrdToIntRowMap);
return;
}
for (I = 1; I <= Size; I++)
{
PrintOrdToIntRowMap[ Matrix->IntToExtRowMap[I] ] = I;
PrintOrdToIntColMap[ Matrix->IntToExtColMap[I] ] = I;
PrintOrdToIntRowMap[Matrix->IntToExtRowMap[I]] = I;
PrintOrdToIntColMap[Matrix->IntToExtColMap[I]] = I;
}
/* Pack the arrays. */
for (J = 1, I = 1; I <= Top; I++)
{
if (PrintOrdToIntRowMap[I] != 0)
PrintOrdToIntRowMap[ J++ ] = PrintOrdToIntRowMap[ I ];
if (PrintOrdToIntRowMap[I] != 0)
PrintOrdToIntRowMap[J++] = PrintOrdToIntRowMap[I];
}
for (J = 1, I = 1; I <= Top; I++)
{
if (PrintOrdToIntColMap[I] != 0)
PrintOrdToIntColMap[ J++ ] = PrintOrdToIntColMap[ I ];
if (PrintOrdToIntColMap[I] != 0)
PrintOrdToIntColMap[J++] = PrintOrdToIntColMap[I];
}
/* Print header. */
if (Header)
{
printf("MATRIX SUMMARY\n\n");
printf("MATRIX SUMMARY\n\n");
printf("Size of matrix = %1d x %1d.\n", Size, Size);
if ( Matrix->Reordered && PrintReordered )
if (Matrix->Reordered && PrintReordered)
printf("Matrix has been reordered.\n");
putchar('\n');
if ( Matrix->Factored )
if (Matrix->Factored)
printf("Matrix after factorization:\n");
else
printf("Matrix before factorization:\n");
@ -219,74 +219,74 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header)
/* Determine how many columns to use. */
Columns = Printer_Width;
if (Header) Columns -= 5;
if (Data) Columns = (Columns+1) / 10;
if (Data) Columns = (Columns + 1) / 10;
/* Print matrix by printing groups of complete columns until all
* the columns are printed. */
J = 0;
while ( J <= Size )
while (J <= Size)
{
/* Calculatestrchr of last column to printed in this group. */
StopCol = StartCol + Columns - 1;
/* Calculatestrchr of last column to printed in this group. */
StopCol = StartCol + Columns - 1;
if (StopCol > Size)
StopCol = Size;
/* Label the columns. */
/* Label the columns. */
if (Header)
{
if (Data)
if (Data)
{
printf(" ");
printf(" ");
for (I = StartCol; I <= StopCol; I++)
{
if (PrintReordered)
if (PrintReordered)
Col = I;
else
Col = PrintOrdToIntColMap[I];
printf(" %9d", Matrix->IntToExtColMap[ Col ]);
printf(" %9d", Matrix->IntToExtColMap[Col]);
}
printf("\n\n");
}
else
{
if (PrintReordered)
printf("Columns %1d to %1d.\n",StartCol,StopCol);
if (PrintReordered)
printf("Columns %1d to %1d.\n", StartCol, StopCol);
else
{
printf("Columns %1d to %1d.\n",
Matrix->IntToExtColMap[ PrintOrdToIntColMap[StartCol] ],
Matrix->IntToExtColMap[ PrintOrdToIntColMap[StopCol] ]);
printf("Columns %1d to %1d.\n",
Matrix->IntToExtColMap[PrintOrdToIntColMap[StartCol]],
Matrix->IntToExtColMap[PrintOrdToIntColMap[StopCol]]);
}
}
}
/* Print every row ... */
/* Print every row ... */
for (I = 1; I <= Size; I++)
{
if (PrintReordered)
if (PrintReordered)
Row = I;
else
Row = PrintOrdToIntRowMap[I];
if (Header)
{
if (PrintReordered && !Data)
if (PrintReordered && !Data)
printf("%4d", I);
else
printf("%4d", Matrix->IntToExtRowMap[ Row ]);
printf("%4d", Matrix->IntToExtRowMap[Row]);
if (!Data) putchar(' ');
}
/* ... in each column of the group. */
/* ... in each column of the group. */
for (J = StartCol; J <= StopCol; J++)
{
if (PrintReordered)
if (PrintReordered)
Col = J;
else
Col = PrintOrdToIntColMap[J];
pElement = Matrix->FirstInCol[Col];
while(pElement != NULL && pElement->Row != Row)
while (pElement != NULL && pElement->Row != Row)
pElement = pElement->NextInCol;
if (Data)
@ -294,24 +294,24 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header)
if (pElement != NULL)
{
/* Case where element exists */
if (Data)
/* Case where element exists */
if (Data)
printf(" %9.3g", pElement->Real);
else
putchar('x');
/* Update status variables */
if ( (Magnitude = ELEMENT_MAG(pElement)) > LargestElement )
/* Update status variables */
if ((Magnitude = ELEMENT_MAG(pElement)) > LargestElement)
LargestElement = Magnitude;
if ((Magnitude < SmallestElement) && (Magnitude != 0.0))
SmallestElement = Magnitude;
ElementCount++;
}
/* Case where element is structurally zero */
/* Case where element is structurally zero */
else
{
if (Data)
if (Data)
printf(" ...");
else
putchar('.');
@ -321,13 +321,13 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header)
if (Matrix->Complex && Data)
{
printf(" ");
printf(" ");
for (J = StartCol; J <= StopCol; J++)
{
if (pImagElements[J - StartCol] != NULL)
if (pImagElements[J - StartCol] != NULL)
{
printf(" %8.2gj",
pImagElements[J-StartCol]->Imag);
printf(" %8.2gj",
pImagElements[J - StartCol]->Imag);
}
else printf(" ");
}
@ -335,44 +335,44 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header)
}
}
/* Calculatestrchr of first column in next group. */
/* Calculatestrchr of first column in next group. */
StartCol = StopCol;
StartCol++;
putchar('\n');
}
if (Header)
{
printf("\nLargest element in matrix = %-1.4g.\n", LargestElement);
printf("\nLargest element in matrix = %-1.4g.\n", LargestElement);
printf("Smallest element in matrix = %-1.4g.\n", SmallestElement);
/* Search for largest and smallest diagonal values */
/* Search for largest and smallest diagonal values */
for (I = 1; I <= Size; I++)
{
if (Matrix->Diag[I] != NULL)
if (Matrix->Diag[I] != NULL)
{
Magnitude = ELEMENT_MAG( Matrix->Diag[I] );
if ( Magnitude > LargestDiag ) LargestDiag = Magnitude;
if ( Magnitude < SmallestDiag ) SmallestDiag = Magnitude;
Magnitude = ELEMENT_MAG(Matrix->Diag[I]);
if (Magnitude > LargestDiag) LargestDiag = Magnitude;
if (Magnitude < SmallestDiag) SmallestDiag = Magnitude;
}
}
/* Print the largest and smallest diagonal values */
if ( Matrix->Factored )
/* Print the largest and smallest diagonal values */
if (Matrix->Factored)
{
printf("\nLargest diagonal element = %-1.4g.\n", LargestDiag);
printf("\nLargest diagonal element = %-1.4g.\n", LargestDiag);
printf("Smallest diagonal element = %-1.4g.\n", SmallestDiag);
}
else
{
printf("\nLargest pivot element = %-1.4g.\n", LargestDiag);
printf("\nLargest pivot element = %-1.4g.\n", LargestDiag);
printf("Smallest pivot element = %-1.4g.\n", SmallestDiag);
}
/* Calculate and print sparsity and number of fill-ins created. */
/* Calculate and print sparsity and number of fill-ins created. */
printf("\nDensity = %2.2f%%.\n", ((double)(ElementCount * 100)) /
((double)(Size * Size)));
((double)(Size * Size)));
printf("Number of originals = %1d.\n", Matrix->Originals);
printf("Number of originals = %1d.\n", Matrix->Originals);
if (!Matrix->NeedsOrdering)
printf("Number of fill-ins = %1d.\n", Matrix->Fillins);
}
@ -393,7 +393,7 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header)
/*
* OUTPUT MATRIX TO FILE
*
@ -437,16 +437,16 @@ spPrint(MatrixPtr Matrix, int PrintReordered, int Data, int Header)
*/
int
spFileMatrix(MatrixPtr Matrix, char *File, char *Label, int Reordered,
int Data, int Header)
spFileMatrix(MatrixPtr Matrix, char* File, char* Label, int Reordered,
int Data, int Header)
{
int I, Size;
ElementPtr pElement;
int Row, Col, Err;
FILE *pMatrixFile;
FILE* pMatrixFile;
/* Begin `spFileMatrix'. */
assert( IS_SPARSE( Matrix ) );
assert(IS_SPARSE(Matrix));
/* Open file matrix file in write mode. */
if ((pMatrixFile = fopen(File, "w")) == NULL)
@ -456,100 +456,100 @@ spFileMatrix(MatrixPtr Matrix, char *File, char *Label, int Reordered,
Size = Matrix->Size;
if (Header)
{
if (Matrix->Factored && Data)
if (Matrix->Factored && Data)
{
Err = fprintf(pMatrixFile,
"Warning : The following matrix is "
"factored in to LU form.\n");
if (Err < 0)
return 0;
Err = fprintf(pMatrixFile,
"Warning : The following matrix is "
"factored in to LU form.\n");
if (Err < 0)
return 0;
}
if (fprintf(pMatrixFile, "%s\n", Label) < 0)
return 0;
Err = fprintf( pMatrixFile, "%d\t%s\n", Size,
(Matrix->Complex ? "complex" : "real"));
return 0;
Err = fprintf(pMatrixFile, "%d\t%s\n", Size,
(Matrix->Complex ? "complex" : "real"));
if (Err < 0)
return 0;
return 0;
}
/* Output matrix. */
if (!Data)
{
for (I = 1; I <= Size; I++)
for (I = 1; I <= Size; I++)
{
pElement = Matrix->FirstInCol[I];
pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
{
if (Reordered)
if (Reordered)
{
Row = pElement->Row;
Row = pElement->Row;
Col = I;
}
else
{
Row = Matrix->IntToExtRowMap[pElement->Row];
Row = Matrix->IntToExtRowMap[pElement->Row];
Col = Matrix->IntToExtColMap[I];
}
pElement = pElement->NextInCol;
if (fprintf(pMatrixFile, "%d\t%d\n", Row, Col) < 0) return 0;
}
}
/* Output terminator, a line of zeros. */
/* Output terminator, a line of zeros. */
if (Header)
if (fprintf(pMatrixFile, "0\t0\n") < 0) return 0;
}
if (Data && Matrix->Complex)
{
for (I = 1; I <= Size; I++)
for (I = 1; I <= Size; I++)
{
pElement = Matrix->FirstInCol[I];
pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
{
if (Reordered)
if (Reordered)
{
Row = pElement->Row;
Row = pElement->Row;
Col = I;
}
else
{
Row = Matrix->IntToExtRowMap[pElement->Row];
Row = Matrix->IntToExtRowMap[pElement->Row];
Col = Matrix->IntToExtColMap[I];
}
Err = fprintf
( pMatrixFile,"%d\t%d\t%-.15g\t%-.15g\n",
Row, Col, pElement->Real, pElement->Imag
);
(pMatrixFile, "%d\t%d\t%-.15g\t%-.15g\n",
Row, Col, pElement->Real, pElement->Imag
);
if (Err < 0) return 0;
pElement = pElement->NextInCol;
}
}
/* Output terminator, a line of zeros. */
/* Output terminator, a line of zeros. */
if (Header)
if (fprintf(pMatrixFile,"0\t0\t0.0\t0.0\n") < 0) return 0;
if (fprintf(pMatrixFile, "0\t0\t0.0\t0.0\n") < 0) return 0;
}
if (Data && !Matrix->Complex)
{
for (I = 1; I <= Size; I++)
for (I = 1; I <= Size; I++)
{
pElement = Matrix->FirstInCol[I];
pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
{
Row = Matrix->IntToExtRowMap[pElement->Row];
Row = Matrix->IntToExtRowMap[pElement->Row];
Col = Matrix->IntToExtColMap[I];
Err = fprintf
( pMatrixFile,"%d\t%d\t%-.15g\n",
Row, Col, pElement->Real
);
(pMatrixFile, "%d\t%d\t%-.15g\n",
Row, Col, pElement->Real
);
if (Err < 0) return 0;
pElement = pElement->NextInCol;
}
}
/* Output terminator, a line of zeros. */
/* Output terminator, a line of zeros. */
if (Header)
if (fprintf(pMatrixFile,"0\t0\t0.0\n") < 0) return 0;
if (fprintf(pMatrixFile, "0\t0\t0.0\n") < 0) return 0;
}
@ -563,7 +563,7 @@ spFileMatrix(MatrixPtr Matrix, char *File, char *Label, int Reordered,
/*
* OUTPUT SOURCE VECTOR TO FILE
*
@ -595,22 +595,22 @@ spFileMatrix(MatrixPtr Matrix, char *File, char *Label, int Reordered,
*/
int
spFileVector(MatrixPtr Matrix, char *File, RealVector RHS, RealVector iRHS)
spFileVector(MatrixPtr Matrix, char* File, RealVector RHS, RealVector iRHS)
{
int I, Size, Err;
FILE *pMatrixFile;
FILE* pMatrixFile;
/* Begin `spFileVector'. */
assert( IS_SPARSE( Matrix ) && RHS != NULL);
assert(IS_SPARSE(Matrix) && RHS != NULL);
if (File) {
/* Open File in write mode. */
pMatrixFile = fopen(File,"w");
pMatrixFile = fopen(File, "w");
if (pMatrixFile == NULL)
return 0;
return 0;
}
else
pMatrixFile=stdout;
else
pMatrixFile = stdout;
/* Output vector. */
Size = Matrix->Size;
@ -618,18 +618,18 @@ spFileVector(MatrixPtr Matrix, char *File, RealVector RHS, RealVector iRHS)
{
for (I = 1; I <= Size; I++)
{
Err = fprintf
( pMatrixFile, "%-.15g\t%-.15g\n",
RHS[I], iRHS[I]
);
Err = fprintf
(pMatrixFile, "%-.15g\t%-.15g\n",
RHS[I], iRHS[I]
);
if (Err < 0) return 0;
}
}
else
{
for (I = 1; I <= Size; I++)
for (I = 1; I <= Size; I++)
{
if (fprintf(pMatrixFile, "%-.15g\n", RHS[I]) < 0)
if (fprintf(pMatrixFile, "%-.15g\n", RHS[I]) < 0)
return 0;
}
}
@ -647,13 +647,13 @@ spFileVector(MatrixPtr Matrix, char *File, RealVector RHS, RealVector iRHS)
/*
* OUTPUT STATISTICS TO FILE
*
* Writes useful information concerning the matrix to a file. Should be
* executed after the matrix is factored.
*
*
* >>> Returns:
* One is returned if routine was successful, otherwise zero is returned.
* The calling function can query errno (the system global error variable)
@ -685,16 +685,16 @@ spFileVector(MatrixPtr Matrix, char *File, RealVector RHS, RealVector iRHS)
*/
int
spFileStats(MatrixPtr Matrix, char *File, char *Label)
spFileStats(MatrixPtr Matrix, char* File, char* Label)
{
int Size, I;
ElementPtr pElement;
int NumberOfElements;
RealNumber Data, LargestElement, SmallestElement;
FILE *pStatsFile;
FILE* pStatsFile;
/* Begin `spFileStats'. */
assert( IS_SPARSE( Matrix ) );
assert(IS_SPARSE(Matrix));
/* Open File in append mode. */
if ((pStatsFile = fopen(File, "a")) == NULL)
@ -710,7 +710,7 @@ spFileStats(MatrixPtr Matrix, char *File, char *Label)
fprintf(pStatsFile, "Matrix is complex.\n");
else
fprintf(pStatsFile, "Matrix is real.\n");
fprintf(pStatsFile," Size = %d\n",Size);
fprintf(pStatsFile, " Size = %d\n", Size);
/* Search matrix. */
NumberOfElements = 0;
@ -719,10 +719,10 @@ spFileStats(MatrixPtr Matrix, char *File, char *Label)
for (I = 1; I <= Size; I++)
{
pElement = Matrix->FirstInCol[I];
pElement = Matrix->FirstInCol[I];
while (pElement != NULL)
{
NumberOfElements++;
NumberOfElements++;
Data = ELEMENT_MAG(pElement);
if (Data > LargestElement)
LargestElement = Data;
@ -732,27 +732,27 @@ spFileStats(MatrixPtr Matrix, char *File, char *Label)
}
}
SmallestElement = MIN( SmallestElement, LargestElement );
SmallestElement = MIN(SmallestElement, LargestElement);
/* Output remaining statistics. */
fprintf(pStatsFile, " Initial number of elements = %d\n",
NumberOfElements - Matrix->Fillins);
NumberOfElements - Matrix->Fillins);
fprintf(pStatsFile,
" Initial average number of elements per row = %f\n",
(double)(NumberOfElements - Matrix->Fillins) / (double)Size);
fprintf(pStatsFile, " Fill-ins = %d\n",Matrix->Fillins);
" Initial average number of elements per row = %f\n",
(double)(NumberOfElements - Matrix->Fillins) / (double)Size);
fprintf(pStatsFile, " Fill-ins = %d\n", Matrix->Fillins);
fprintf(pStatsFile, " Average number of fill-ins per row = %f%%\n",
(double)Matrix->Fillins / (double)Size);
(double)Matrix->Fillins / (double)Size);
fprintf(pStatsFile, " Total number of elements = %d\n",
NumberOfElements);
NumberOfElements);
fprintf(pStatsFile, " Average number of elements per row = %f\n",
(double)NumberOfElements / (double)Size);
fprintf(pStatsFile," Density = %f%%\n",
(double)(100.0*NumberOfElements)/(double)(Size*Size));
fprintf(pStatsFile," Relative Threshold = %e\n", Matrix->RelThreshold);
fprintf(pStatsFile," Absolute Threshold = %e\n", Matrix->AbsThreshold);
fprintf(pStatsFile," Largest Element = %e\n", LargestElement);
fprintf(pStatsFile," Smallest Element = %e\n\n\n", SmallestElement);
(double)NumberOfElements / (double)Size);
fprintf(pStatsFile, " Density = %f%%\n",
(double)(100.0 * NumberOfElements) / (double)(Size * Size));
fprintf(pStatsFile, " Relative Threshold = %e\n", Matrix->RelThreshold);
fprintf(pStatsFile, " Absolute Threshold = %e\n", Matrix->AbsThreshold);
fprintf(pStatsFile, " Largest Element = %e\n", LargestElement);
fprintf(pStatsFile, " Smallest Element = %e\n\n\n", SmallestElement);
/* Close file. */
(void)fclose(pStatsFile);

View File

@ -94,7 +94,7 @@ inchar(FILE *fp)
}
return (int) c;
#elif
#else
return getc(fp);
#endif

View File

@ -182,6 +182,8 @@ typedef void (*sighandler)(int);
#ifdef XSPICE
#include "ngspice/evtshared.h"
#include "ngspice/evtproto.h"
#include "ngspice/evtudn.h"
extern bool wantevtdata;
#endif
@ -222,7 +224,7 @@ extern struct comm spcp_coms[];
struct comm* cp_coms = spcp_coms;
/* Main options */
static bool ft_servermode = FALSE;
bool ft_batchmode = FALSE;
bool ft_pipemode = FALSE;
bool rflag = FALSE; /* has rawfile */
@ -341,6 +343,8 @@ void sh_delete_myvec(void);
#ifdef XSPICE
void shared_send_event(int, double, double, char *, void *, int, int);
void shared_send_dict(int, int, char*, char*);
static int evt_shim(double time, Mif_Value_t *vp, void *ctx, int last);
#endif
#if !defined(low_latency)
@ -397,6 +401,7 @@ static int intermj = 1;
#ifdef XSPICE
static SendInitEvtData* sendinitevt;
static SendEvtData* sendevt;
static SendRawEvtData *sendrawevt;
#endif
static void* euserptr;
static wordlist *shcontrols;
@ -975,13 +980,26 @@ ngSpice_Init(SendChar* printfcn, SendStat* statusfcn, ControlledExit* ngspiceexi
}
#else /* ~ HAVE_PWD_H */
/* load user's initialisation file
try accessing the initialisation file .spiceinit in a user provided
path read from environmental variable SPICE_USERINIT_DIR,
if that fails try the alternate name spice.rc, then look into
the current directory, then the HOME directory, then into USERPROFILE.
Don't read .spiceinit, if ngSpice_nospiceinit() has been called. */
try accessing the initialisation file .spiceinit
(If it fails, try the alternate name spice.rc):
- in the directory Infile_Path received from the caller (sent before initialization)
- in a user provided path read from environmental variable SPICE_USERINIT_DIR,
- in the current directory,
- in the the HOME directory,
- in the USERPROFILE directory.
Don't read .spiceinit, if ngSpice_nospiceinit() has been called. */
if (!cp_getvar("no_spiceinit", CP_BOOL, NULL, 0)) {
do {
{
if (Infile_Path) {
if (read_initialisation_file(Infile_Path, INITSTR) != FALSE) {
break;
}
if (read_initialisation_file(Infile_Path, ALT_INITSTR) != FALSE) {
break;
}
}
}
{
const char* const userinit = getenv("SPICE_USERINIT_DIR");
if (userinit) {
@ -1374,6 +1392,41 @@ int ngSpice_Init_Evt(SendEvtData* sevtdata, SendInitEvtData* sinitevtdata, void
return(TRUE);
}
/* Set callback address for raw XSPICE events.
* The return value identifies the node data type or is -1 on error.
*/
IMPEXP
int ngSpice_Raw_Evt(const char* node, SendRawEvtData* srawevt, void* userData)
{
struct node_parse np;
if (Evt_Parse_Node(node, &np) < 0 || np.member)
return -1; // Invalid node name.
sendrawevt = srawevt;
EVTnew_value_call(node, evt_shim, Evt_Cbt_Raw, userData);
return np.udn_index;
}
IMPEXP
int ngSpice_Decode_Evt(void* evt, int type,
double *pplotval, const char **ppprintval)
{
if (type >= g_evt_num_udn_types)
return 1;
if (!evt) {
if (!ppprintval)
return 2;
*ppprintval = g_evt_udn_info[type]->name;
return 0;
}
if (pplotval)
g_evt_udn_info[type]->plot_val(evt, "", pplotval);
if (ppprintval)
g_evt_udn_info[type]->print_val(evt, "", (char **)ppprintval);
return 0;
}
/* Get info about the event node vector.
If node_name is NULL, just delete previous data */
IMPEXP
@ -1454,7 +1507,7 @@ sh_vfprintf(FILE *f, const char *fmt, va_list args)
{
char buf[1024];
char *p/*, *s*/;
int nchars, /*escapes,*/ result;
int nchars;
size_t size;
@ -1534,7 +1587,7 @@ sh_vfprintf(FILE *f, const char *fmt, va_list args)
Spice_Init() from caller of ngspice.dll */
result = sh_fputs(p, f);
sh_fputs(p, f);
if (p != buf)
tfree(p);
@ -1916,7 +1969,6 @@ void SetAnalyse(
|| defined (HAVE_FTIME)
PerfTime timenow; /* actual time stamp */
int diffsec, diffmillisec; /* differences actual minus prev. time stamp */
int result; /* return value from callback function */
char* s; /* outputs to callback function */
int OldPercent; /* Previous progress value */
char OldAn[128]; /* Previous analysis type */
@ -1981,7 +2033,7 @@ void SetAnalyse(
if (!strcmp(Analyse, "tran")) {
if (ckt && (ckt->CKTtime > ckt->CKTfinalTime - ckt->CKTmaxStep)) {
sprintf(s, "--ready--");
result = statfcn(s, ng_ident, userptr);
statfcn(s, ng_ident, userptr);
tfree(s);
return;
}
@ -1994,7 +2046,7 @@ void SetAnalyse(
return;
}
sprintf( s, "--ready--");
result = statfcn(s, ng_ident, userptr);
statfcn(s, ng_ident, userptr);
tfree(s);
return;
}
@ -2043,7 +2095,7 @@ void SetAnalyse(
}
/* ouput only after a change */
if (strcmp(olds, s))
result = statfcn(s, ng_ident, userptr);
statfcn(s, ng_ident, userptr);
if(thread1)
strcpy(olds1, s);
else
@ -2052,11 +2104,10 @@ void SetAnalyse(
tfree(s);
#else
char* s;
int result;
static bool havesent = FALSE;
if (!havesent) {
s = copy("No usage info available");
result = statfcn(s, ng_ident, userptr);
statfcn(s, ng_ident, userptr);
tfree(s);
havesent = TRUE;
}
@ -2420,8 +2471,14 @@ sharedsync(double *pckttime, double *pcktdelta, double olddelta, double finalt,
step if return value from getsync is 1. */
int retval = getsync(*pckttime, pcktdelta, olddelta, redostep, ng_ident, loc, userptr);
/* never move beyond final time */
if (*pckttime + *pcktdelta > finalt)
*pcktdelta = finalt - *pckttime - 1.1 * delmin;
if (*pckttime + *pcktdelta > finalt) {
double newdelta;
newdelta = finalt - *pckttime - 1.1 * delmin;
if (newdelta <= 0.0)
newdelta = finalt - *pckttime;
*pcktdelta = newdelta;
}
/* user has decided to redo the step, ignoring redostep being set to 0
by ngspice. */
@ -2447,6 +2504,13 @@ void shared_send_dict(int index, int no_of_nodes, char* name, char*type)
if (sendinitevt)
sendinitevt(index, no_of_nodes, name, type, ng_ident, euserptr);
}
static int evt_shim(double time, Mif_Value_t *vp, void *ctx, int last)
{
if (sendrawevt)
return sendrawevt(time, vp->pvalue, ctx, last); // Strip Mif_value.
return 1;
}
#endif
static int totalreset(void)

View File

@ -12,15 +12,15 @@ Copyright 1992 Regents of the University of California. All rights reserved.
/* ARGSUSED */
int
CKTdltNod(CKTcircuit *ckt, CKTnode *node)
CKTdltNod(CKTcircuit* ckt, CKTnode* node)
{
return CKTdltNNum(ckt, node->number);
}
int
CKTdltNNum(CKTcircuit *ckt, int num)
CKTdltNNum(CKTcircuit* ckt, int num)
{
CKTnode *n, *prev, *node, *sprev;
CKTnode* n, * prev, * node, * sprev;
int error;
if (!ckt->prev_CKTlastNode->number || num <= ckt->prev_CKTlastNode->number) {
@ -28,32 +28,33 @@ CKTdltNNum(CKTcircuit *ckt, int num)
controlled_exit(EXIT_FAILURE);
}
prev = NULL;
node = NULL;
prev = NULL;
node = NULL;
sprev = NULL;
for (n = ckt->CKTnodes; n; n = n->next) {
if (n->number == num) {
node = n;
sprev = prev;
}
prev = n;
if (n->number == num) {
node = n;
sprev = prev;
}
prev = n;
}
if (!node)
return OK;
return OK;
ckt->CKTmaxEqNum -= 1;
if (!sprev) {
ckt->CKTnodes = node->next;
} else {
sprev->next = node->next;
ckt->CKTnodes = node->next;
}
else {
sprev->next = node->next;
}
if (node == ckt->CKTlastNode)
ckt->CKTlastNode = sprev;
ckt->CKTlastNode = sprev;
error = SPfrontEnd->IFdelUid (ckt, node->name, UID_SIGNAL);
error = SPfrontEnd->IFdelUid(ckt, node->name, UID_SIGNAL);
tfree(node);
return error;

View File

@ -411,6 +411,65 @@ NOISEan(CKTcircuit* ckt, int restart)
job->NsavInoise = data->inNoise;
return (E_PAUSE);
}
/* Update opertating point, if variable 'hertz' is given */
if (ckt->CKTvarHertz) {
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
{
/* Conversion from Complex Matrix to Real Matrix */
for (i = 0; i < DEVmaxnum; i++)
if (DEVices[i] && DEVices[i]->DEVbindCSCComplexToReal && ckt->CKThead[i])
DEVices[i]->DEVbindCSCComplexToReal(ckt->CKThead[i], ckt);
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixIsComplex = KLUmatrixReal;
}
#endif
#ifdef XSPICE
/* Call EVTop if event-driven instances exist */
if (ckt->evt->counts.num_insts != 0) {
error = EVTop(ckt,
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT,
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT,
ckt->CKTdcMaxIter,
MIF_TRUE);
EVTdump(ckt, IPC_ANAL_DCOP, 0.0);
EVTop_save(ckt, MIF_TRUE, 0.0);
}
else
#endif
// If no event-driven instances, do what SPICE normally does
error = CKTop(ckt,
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT,
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT,
ckt->CKTdcMaxIter);
if (error) {
fprintf(stderr, "\nError: AC operating point with variable 'Hertz' for noise sim failed -\n");
CKTncDump(ckt);
return(error);
}
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
error = CKTload(ckt);
if (error) return(error);
#ifdef KLU
if (ckt->CKTmatrix->CKTkluMODE)
{
/* Conversion from Real Matrix to Complex Matrix */
for (i = 0; i < DEVmaxnum; i++)
if (DEVices[i] && DEVices[i]->DEVbindCSCComplex && ckt->CKThead[i])
DEVices[i]->DEVbindCSCComplex(ckt->CKThead[i], ckt);
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixIsComplex = KLUMatrixComplex;
}
#endif
}
ckt->CKTomega = 2.0 * M_PI * data->freq;
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEAC | MODEACNOISE;
ckt->noise_input = inst;

View File

@ -145,9 +145,9 @@ MOS1noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
N_GAIN, inst->MOS1dNodePrime, inst->MOS1sNodePrime,
(double) 0.0);
if (newcompat.s3) {
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
noizDens[MOS1FLNOIZ] *= inst->MOS1m * model->MOS1fNcoef *
exp(model->MOS1fNexp *
log(MAX(fabs(inst->MOS1cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS1cd / inst->MOS1m), N_MINLOG))) /
(data->freq *
inst->MOS1w *
(inst->MOS1l - 2 * model->MOS1latDiff) *
@ -155,18 +155,18 @@ MOS1noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
} else {
switch (model->MOS1nlev) {
case 0:
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
noizDens[MOS1FLNOIZ] *= inst->MOS1m * model->MOS1fNcoef *
exp(model->MOS1fNexp *
log(MAX(fabs(inst->MOS1cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS1cd / inst->MOS1m), N_MINLOG))) /
(data->freq *
(inst->MOS1l - 2 * model->MOS1latDiff) *
(inst->MOS1l - 2 * model->MOS1latDiff) *
sqrt(coxSquared));
break;
case 1:
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
noizDens[MOS1FLNOIZ] *= inst->MOS1m * model->MOS1fNcoef *
exp(model->MOS1fNexp *
log(MAX(fabs(inst->MOS1cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS1cd / inst->MOS1m), N_MINLOG))) /
(data->freq *
inst->MOS1w *
(inst->MOS1l - 2 * model->MOS1latDiff) *
@ -174,7 +174,7 @@ MOS1noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
break;
case 2: case 3:
noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef *
inst->MOS1gm * inst->MOS1gm /
inst->MOS1gm * inst->MOS1gm / inst->MOS1m /
(pow(data->freq, model->MOS1fNexp) *
inst->MOS1w *
(inst->MOS1l - 2 * model->MOS1latDiff) *

View File

@ -34,7 +34,7 @@ MOS2load(GENmodel *inModel, CKTcircuit *ckt)
double GateBulkOverlapCap;
double GateDrainOverlapCap;
double GateSourceOverlapCap;
double OxideCap;
double OxideCap, unscaledOxideCap;
double SourceSatCur;
double arg;
double cbhat;
@ -144,8 +144,8 @@ MOS2load(GENmodel *inModel, CKTcircuit *ckt)
here->MOS2m * EffectiveLength;
Beta = here->MOS2tTransconductance * here->MOS2w *
here->MOS2m/EffectiveLength;
OxideCap = model->MOS2oxideCapFactor * EffectiveLength *
here->MOS2m * here->MOS2w;
unscaledOxideCap = model->MOS2oxideCapFactor * EffectiveLength * here->MOS2w;
OxideCap = unscaledOxideCap*here->MOS2m;
if(SenCond){
@ -599,7 +599,7 @@ next1: if(vbs <= -3*vt) {
/*XXX constant per device */
factor = 0.125*model->MOS2narrowFactor*2.0*M_PI*EPSSIL/
OxideCap*EffectiveLength;
unscaledOxideCap*EffectiveLength;
/*XXX constant per device */
eta = 1.0+factor;
vbin = here->MOS2tVbi*model->MOS2type+factor*phiMinVbs;
@ -664,7 +664,7 @@ next1: if(vbs <= -3*vt) {
1e4 /*(cm**2/m**2)*/;
cdonco = -(gamasd*dsrgdb+dgddvb*sarg1)+factor;
xn = 1.0+cfs/OxideCap*here->MOS2m*
xn = 1.0+cfs/unscaledOxideCap*
here->MOS2w*EffectiveLength+cdonco;
tmp = vt*xn;

View File

@ -134,9 +134,9 @@ MOS2noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
N_GAIN, inst->MOS2dNodePrime, inst->MOS2sNodePrime,
(double) 0.0);
if (newcompat.s3) {
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
noizDens[MOS2FLNOIZ] *= inst->MOS2m * model->MOS2fNcoef *
exp(model->MOS2fNexp *
log(MAX(fabs(inst->MOS2cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS2cd / inst->MOS2m), N_MINLOG))) /
(data->freq *
inst->MOS2w *
(inst->MOS2l - 2 * model->MOS2latDiff) *
@ -144,18 +144,18 @@ MOS2noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
} else {
switch (model->MOS2nlev) {
case 0:
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
noizDens[MOS2FLNOIZ] *= inst->MOS2m * model->MOS2fNcoef *
exp(model->MOS2fNexp *
log(MAX(fabs(inst->MOS2cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS2cd / inst->MOS2m), N_MINLOG))) /
(data->freq *
(inst->MOS2l - 2 * model->MOS2latDiff) *
(inst->MOS2l - 2 * model->MOS2latDiff) *
model->MOS2oxideCapFactor);
break;
case 1:
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
noizDens[MOS2FLNOIZ] *= inst->MOS2m * model->MOS2fNcoef *
exp(model->MOS2fNexp *
log(MAX(fabs(inst->MOS2cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS2cd / inst->MOS2m), N_MINLOG))) /
(data->freq *
inst->MOS2w *
(inst->MOS2l - 2 * model->MOS2latDiff) *
@ -163,7 +163,7 @@ MOS2noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
break;
case 2: case 3:
noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef *
inst->MOS2gm * inst->MOS2gm /
inst->MOS2gm * inst->MOS2gm / inst->MOS2m /
(pow(data->freq, model->MOS2fNexp) *
inst->MOS2w *
(inst->MOS2l - 2 * model->MOS2latDiff) *

View File

@ -134,9 +134,9 @@ MOS3noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
N_GAIN, inst->MOS3dNodePrime, inst->MOS3sNodePrime,
(double) 0.0);
if (newcompat.s3) {
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
noizDens[MOS3FLNOIZ] *= inst->MOS3m * model->MOS3fNcoef *
exp(model->MOS3fNexp *
log(MAX(fabs(inst->MOS3cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS3cd / inst->MOS3m), N_MINLOG))) /
(data->freq *
(inst->MOS3w - 2 * model->MOS3widthNarrow) *
(inst->MOS3l - 2 * model->MOS3latDiff) *
@ -144,18 +144,18 @@ MOS3noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
} else {
switch (model->MOS3nlev) {
case 0:
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
noizDens[MOS3FLNOIZ] *= inst->MOS3m * model->MOS3fNcoef *
exp(model->MOS3fNexp *
log(MAX(fabs(inst->MOS3cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS3cd / inst->MOS3m), N_MINLOG))) /
(data->freq *
(inst->MOS3l - 2 * model->MOS3latDiff) *
(inst->MOS3l - 2 * model->MOS3latDiff) *
model->MOS3oxideCapFactor);
break;
case 1:
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
noizDens[MOS3FLNOIZ] *= inst->MOS3m * model->MOS3fNcoef *
exp(model->MOS3fNexp *
log(MAX(fabs(inst->MOS3cd), N_MINLOG))) /
log(MAX(fabs(inst->MOS3cd / inst->MOS3m), N_MINLOG))) /
(data->freq *
(inst->MOS3w - 2 * model->MOS3widthNarrow) *
(inst->MOS3l - 2 * model->MOS3latDiff) *
@ -163,7 +163,7 @@ MOS3noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt,
break;
case 2: case 3:
noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef *
inst->MOS3gm * inst->MOS3gm /
inst->MOS3gm * inst->MOS3gm / inst->MOS3m /
(pow(data->freq, model->MOS3fNexp) *
(inst->MOS3w - 2 * model->MOS3widthNarrow) *
(inst->MOS3l - 2 * model->MOS3latDiff) *

View File

@ -94,12 +94,11 @@ MOS9noise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
NevalSrc(&noizDens[MOS9FLNOIZ], NULL, ckt,
N_GAIN,inst->MOS9dNodePrime, inst->MOS9sNodePrime,
(double)0.0);
noizDens[MOS9FLNOIZ] *= model->MOS9fNcoef *
noizDens[MOS9FLNOIZ] *= inst->MOS9m * model->MOS9fNcoef *
exp(model->MOS9fNexp *
log(MAX(fabs(inst->MOS9cd),N_MINLOG))) /
log(MAX(fabs(inst->MOS9cd / inst->MOS9m),N_MINLOG))) /
(data->freq *
(inst->MOS9w - 2*model->MOS9widthNarrow) *
inst->MOS9m *
(inst->MOS9l - 2*model->MOS9latDiff) *
model->MOS9oxideCapFactor * model->MOS9oxideCapFactor);
lnNdens[MOS9FLNOIZ] =

View File

@ -96,8 +96,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
*(here->VDMOSDPgpPtr +1) -= xgd;
*(here->VDMOSSPgpPtr +1) -= xgs;
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance;
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance;
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance + here->VDMOSdsConductance;
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance + here->VDMOSdsConductance;
*(here->VDMOSDPdpPtr) += here->VDMOSdrainConductance+
here->VDMOSgds+xrev*(here->VDMOSgm);
*(here->VDMOSSPspPtr) += here->VDMOSsourceConductance+
@ -110,6 +110,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
*(here->VDMOSSPgpPtr) -= (xnrm-xrev)*here->VDMOSgm;
*(here->VDMOSSPsPtr) -= here->VDMOSsourceConductance;
*(here->VDMOSSPdpPtr) -= here->VDMOSgds+xrev*(here->VDMOSgm);
*(here->VDMOSDsPtr) += (-here->VDMOSdsConductance);
*(here->VDMOSSdPtr) += (-here->VDMOSdsConductance);
/* gate resistor */
*(here->VDMOSGgPtr) += (here->VDMOSgateConductance);
*(here->VDMOSGPgpPtr) += (here->VDMOSgateConductance);

View File

@ -171,10 +171,6 @@ typedef struct sVDMOSinstance {
(source prime node,source prime node) */
double *VDMOSDdpPtr; /* pointer to sparse matrix element at
(drain node,drain prime node) */
double *VDMOSGdpPtr; /* pointer to sparse matrix element at
(gate node,drain prime node) */
double *VDMOSGspPtr; /* pointer to sparse matrix element at
(gate node,source prime node) */
double *VDMOSSspPtr; /* pointer to sparse matrix element at
(source node,source prime node) */
double *VDMOSDPspPtr; /* pointer to sparse matrix element at

View File

@ -99,7 +99,7 @@ VDMOSdSetup(GENmodel *inModel, CKTcircuit *ckt)
/* scale vds with mtr (except with lambda) */
double vdss = vds*mtr*here->VDMOSmode;
double t0 = 1 + lambda*vds;
double t1 = 1 + theta*vgst;
double t1 = 1 + theta*vdsat;
double betap = Beta*t0/t1;
double dbetapdvgs = -Beta*theta*t0/(t1*t1);
double dbetapdvds = Beta*lambda/t1;

View File

@ -364,7 +364,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
/* scale vds with mtr (except with lambda) */
double vdss = vds*mtr*here->VDMOSmode;
double t0 = 1 + lambda*vds;
double t1 = 1 + theta*vgst;
double t1 = 1 + theta*vdsat;
double betap = Beta*t0/t1;
double dbetapdvgs = -Beta*theta*t0/(t1*t1);
double dbetapdvds = Beta*lambda/t1;

View File

@ -55,22 +55,23 @@ VDMOSpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
* load matrix
*/
*(here->VDMOSGgPtr ) += (xgd+xgs)*s->real;
*(here->VDMOSGgPtr +1) += (xgd+xgs)*s->imag;
*(here->VDMOSGPgpPtr ) += (xgd+xgs)*s->real;
*(here->VDMOSGPgpPtr +1) += (xgd+xgs)*s->imag;
*(here->VDMOSDPdpPtr ) += (xgd)*s->real;
*(here->VDMOSDPdpPtr +1) += (xgd)*s->imag;
*(here->VDMOSSPspPtr ) += (xgs)*s->real;
*(here->VDMOSSPspPtr +1) += (xgs)*s->imag;
*(here->VDMOSGdpPtr ) -= xgd*s->real;
*(here->VDMOSGdpPtr +1) -= xgd*s->imag;
*(here->VDMOSGspPtr ) -= xgs*s->real;
*(here->VDMOSGspPtr +1) -= xgs*s->imag;
*(here->VDMOSDPgPtr ) -= xgd*s->real;
*(here->VDMOSDPgPtr +1) -= xgd*s->imag;
*(here->VDMOSSPgPtr ) -= xgs*s->real;
*(here->VDMOSSPgPtr +1) -= xgs*s->imag;
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance;
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance;
*(here->VDMOSGPdpPtr ) -= xgd*s->real;
*(here->VDMOSGPdpPtr +1) -= xgd*s->imag;
*(here->VDMOSGPspPtr ) -= xgs*s->real;
*(here->VDMOSGPspPtr +1) -= xgs*s->imag;
*(here->VDMOSDPgpPtr ) -= xgd*s->real;
*(here->VDMOSDPgpPtr +1) -= xgd*s->imag;
*(here->VDMOSSPgpPtr ) -= xgs*s->real;
*(here->VDMOSSPgpPtr +1) -= xgs*s->imag;
*(here->VDMOSDdPtr) += here->VDMOSdrainConductance + here->VDMOSdsConductance;
*(here->VDMOSSsPtr) += here->VDMOSsourceConductance + here->VDMOSdsConductance;
*(here->VDMOSDPdpPtr) += here->VDMOSdrainConductance+
here->VDMOSgds+xrev*(here->VDMOSgm);
*(here->VDMOSSPspPtr) += here->VDMOSsourceConductance+
@ -83,6 +84,8 @@ VDMOSpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
*(here->VDMOSSPgpPtr) -= (xnrm-xrev)*here->VDMOSgm;
*(here->VDMOSSPsPtr) -= here->VDMOSsourceConductance;
*(here->VDMOSSPdpPtr) -= here->VDMOSgds+xrev*(here->VDMOSgm);
*(here->VDMOSDsPtr) += (-here->VDMOSdsConductance);
*(here->VDMOSSdPtr) += (-here->VDMOSdsConductance);
/* gate resistor */
*(here->VDMOSGgPtr) += (here->VDMOSgateConductance);
*(here->VDMOSGPgpPtr) += (here->VDMOSgateConductance);

View File

@ -65,7 +65,7 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
&& here->VSRCcoeffs[4] != 0.0
? here->VSRCcoeffs[4] : ckt->CKTstep;
PW = here->VSRCfunctionOrder > 5
&& here->VSRCcoeffs[5] != 0.0
&& here->VSRCcoeffs[5] >= 0.0
? here->VSRCcoeffs[5] : ckt->CKTfinalTime;
PER = here->VSRCfunctionOrder > 6
&& here->VSRCcoeffs[6] != 0.0

View File

@ -112,7 +112,7 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt)
&& here->VSRCcoeffs[4] != 0.0
? here->VSRCcoeffs[4] : ckt->CKTstep;
PW = here->VSRCfunctionOrder > 5
&& here->VSRCcoeffs[5] != 0.0
&& here->VSRCcoeffs[5] >= 0.0
? here->VSRCcoeffs[5] : ckt->CKTfinalTime;
PER = here->VSRCfunctionOrder > 6
&& here->VSRCcoeffs[6] != 0.0

View File

@ -22,79 +22,96 @@ void INP2N(CKTcircuit *ckt, INPtables *tab, struct card *current) {
* [IC=<val>,<val>,<val>]
*/
int type; /* the type the model says it is */
char *line; /* the part of the current line left to parse */
char *name; /* the resistor's name */
// limit to at most 20 nodes
const int max_i = 20;
CKTnode *node[20];
int error; /* error code temporary */
int numnodes; /* flag indicating 4 or 5 (or 6 or 7) nodes */
GENinstance *fast; /* pointer to the actual instance */
int waslead; /* flag to indicate that funny unlabeled number was found */
double leadval; /* actual value of unlabeled number */
INPmodel *thismodel; /* pointer to model description for user's model */
GENmodel *mdfast; /* pointer to the actual model */
int i;
int type; /* Model type. */
char *line; /* Unparsed part of the current line. */
char *name; /* Device instance name. */
int error; /* Temporary error code. */
int numnodes; /* Flag indicating 4 or 5 (or 6 or 7) nodes. */
GENinstance *fast; /* Pointer to the actual instance. */
int waslead; /* Funny unlabeled number was found. */
double leadval; /* Value of unlabeled number. */
INPmodel *thismodel; /* Pointer to model description for user's model. */
GENmodel *mdfast; /* Pointer to the actual model. */
IFdevice *dev;
CKTnode *node;
char *c, *token = NULL, *prev = NULL, *pprev = NULL;
int i;
line = current->line;
INPgetNetTok(&line, &name, 1);
INPinsert(&name, tab);
for (i = 0;; i++) {
char *token;
INPgetNetTok(&line, &token, 1);
/* Find the last non-parameter token in the line. */
/* We have single terminal Verilog-A modules */
if (i >= 1) {
txfree(INPgetMod(ckt, token, &thismodel, tab));
c = line;
for (i = 0; *c != '\0'; ++i) {
tfree(pprev);
pprev = prev;
prev = token;
token = gettok_instance(&c);
if (strchr(token, '='))
break;
}
if (*c) {
tfree(token); // A parameter or starts with '='.
if (*c == '=') {
/* Now prev points to a parameter pprev is the model. */
/* /1* check if using model binning -- pass in line since need 'l' and 'w' *1/ */
/* if (!thismodel) */
/* txfree(INPgetModBin(ckt, token, &thismodel, tab, line)); */
if (thismodel) {
INPinsert(&token, tab);
break;
--i;
token = pprev;
tfree(prev);
} else {
token = prev;
tfree(pprev);
}
}
if (i >= max_i) {
LITERR("could not find a valid modelname");
return;
}
INPtermInsert(ckt, &token, tab, &node[i]);
}
/* We have single terminal Verilog-A modules */
if (i >= 2) {
c = INPgetMod(ckt, token, &thismodel, tab);
if (c) {
LITERR(c);
tfree(c);
tfree(token);
return;
}
}
tfree(token);
if (i < 2 || !thismodel) {
LITERR("could not find a valid modelname");
return;
}
type = thismodel->INPmodType;
mdfast = thismodel->INPmodfast;
IFdevice *dev = ft_sim->devices[type];
dev = ft_sim->devices[type];
if (!dev->registry_entry) {
LITERR("incorrect model type! Expected OSDI device");
return;
}
if (i == 0) {
LITERR("not enough nodes");
return;
}
if (i > *dev->terms) {
numnodes = i - 1;
if (numnodes > *dev->terms) {
LITERR("too many nodes connected to instance");
return;
}
numnodes = i;
IFC(newInstance, (ckt, mdfast, &fast, name));
for (i = 0; i < *dev->terms; i++)
if (i < numnodes)
IFC(bindNode, (ckt, fast, i + 1, node[i]));
else
GENnode(fast)[i] = -1;
/* Rescan to process nodes. */
for (i = 0; i < *dev->terms; i++) {
if (i < numnodes) {
token = gettok_instance(&line);
INPtermInsert(ckt, &token, tab, &node); // Consumes token
IFC(bindNode, (ckt, fast, i + 1, node));
} else {
GENnode(fast)[i] = -1;
}
}
token = gettok_instance(&line); // Eat model name.
tfree(token);
PARSECALL((&line, ckt, type, fast, &leadval, &waslead, tab));
if (waslead)
LITERR(" error: no unlabeled parameter permitted on osdi devices\n");

View File

@ -372,7 +372,7 @@ INPevaluateRKM_R(char** line, int* error, int gobble)
int num;
char ch;
if (sscanf(here + 1, "%i%c", &num, &ch) == 1) {
expo1 = expo1;
//expo1 = expo1;
hasmulti = TRUE;
}
else {
@ -612,7 +612,7 @@ INPevaluateRKM_C(char** line, int* error, int gobble)
case 'r':
case 'R':
expo1 = expo1;
//expo1 = expo1;
hasmulti = TRUE;
break;
case 'n':
@ -850,7 +850,7 @@ INPevaluateRKM_L(char** line, int* error, int gobble)
case 'r':
case 'R':
expo1 = expo1;
//expo1 = expo1;
hasmulti = TRUE;
break;
case 'n':

View File

@ -149,12 +149,18 @@ create_model(CKTcircuit *ckt, INPmodel *modtmp, INPtables *tab)
if (p) {
char *value;
INPgetTok(&line, &value, 1);
modtmp->INPmodfast->defaults =
wl_cons(copy(parm),
wl_cons(value,
modtmp->INPmodfast->defaults));
INPgetTok(&line, &value, 1);
if (p->dataType & IF_SET) {
modtmp->INPmodfast->defaults =
wl_cons(copy(parm),
wl_cons(value, modtmp->INPmodfast->defaults));
} else {
fprintf(stderr,
"Ignoring attempt to set a default "
"for read-only instance parameter %s in:\n %s\n",
p->keyword, modtmp->INPmodLine->line);
}
} else {
double dval;
@ -286,6 +292,7 @@ INPgetModBin(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab, char
for (modtmp = modtab; modtmp; modtmp = modtmp->INPnextModel) {
/* exact: 1, with binning extension .[0-9]: 2*/
if (model_name_match(name, modtmp->INPmodName) < 2)
continue;
@ -328,8 +335,8 @@ INPgetModBin(CKTcircuit *ckt, char *name, INPmodel **model, INPtables *tab, char
*model = modtmp;
return NULL;
}
fprintf(stderr, "Warning: no model found for w=%.3e and l=%.3e\n", w, l);
}
return NULL;
}

View File

@ -45,6 +45,7 @@ NON-STANDARD FEATURES
#include "ngspice/mif.h"
#include "ngspice/evt.h"
#include "ngspice/evtudn.h"
#include "ngspice/evtproto.h"
@ -160,18 +161,62 @@ void EVTaccept(
num_modified = node_data->num_modified;
/* Loop through list of items modified since last time */
for(i = 0; i < num_modified; i++) {
Evt_Node_t *this;
Evt_Node_Info_t *node_info;
Evt_Node_Cb_t *cb, **cbpp;
int udn_index;
/* Get the index of the node modified */
index = node_data->modified_index[i];
/* Reset the modified flag */
node_data->modified[index] = MIF_FALSE;
/* Call any value-change functions registered for this node. */
node_info = node_table[index];
udn_index = node_info->udn_index;
cbpp = &node_info->cbs;
for (;;) {
Mif_Value_t val;
cb = *cbpp;
if (cb == NULL)
break;
for (this = *node_data->last_step[index];
this;
this = this->next) {
switch (cb->type) {
case Evt_Cbt_Raw:
val.pvalue = this->node_value;
break;
case Evt_Cbt_Plot:
g_evt_udn_info[udn_index]->plot_val(this->node_value,
(char *)cb->member,
&val.rvalue);
break;
}
if ((*cb->fn)(this->step, &val, cb->ctx, !this->next)) {
/* Remove callback from chain. */
*cbpp = cb->next;
txfree(cb);
break;
}
}
if (this == NULL) // Normal loop exit.
cbpp = &cb->next;
}
/* Optionally store node values for later examination.
* The test of CKTtime here is copied from dctran.c.
* CKTinitTime is from the tstart parameter of the "tran"
* command or card.
*/
if (node_table[index]->save && ckt->CKTtime >= ckt->CKTinitTime &&
if (node_info->save && ckt->CKTtime >= ckt->CKTinitTime &&
(ckt->CKTtime > 0 || !(ckt->CKTmode & MODEUIC))) {
/* Update last_step for this index */
node_data->last_step[index] = node_data->tail[index];
@ -239,3 +284,77 @@ void EVTaccept(
} /* EVTaccept */
/* Functions to set-up and cancel value-changed callbacks. */
Mif_Boolean_t EVTnew_value_call(const char *node,
Evt_New_Value_Cb_t fn,
Evt_Node_Cb_Type_t type,
void *ctx)
{
struct node_parse result;
int index;
Evt_Ckt_Data_t *evt;
CKTcircuit *ckt;
Evt_Node_Info_t *node_info;
Evt_Node_Cb_t *cb;
index = Evt_Parse_Node(node, &result);
if (index < 0)
return MIF_FALSE;
ckt = g_mif_info.ckt;
evt = ckt->evt;
node_info = evt->info.node_table[index];
cb = tmalloc(sizeof *cb);
cb->next = node_info->cbs;
node_info->cbs = cb;
cb->fn = fn;
cb->type = type;
cb->member = copy(result.member);
cb->ctx = ctx;
txfree(result.node);
return MIF_TRUE;
}
void EVTcancel_value_call(const char *node,
Evt_New_Value_Cb_t fn,
void *ctx)
{
Evt_Ckt_Data_t *evt;
CKTcircuit *ckt;
Evt_Node_Info_t **node_table, *node_info;
Evt_Node_Cb_t **cbpp, *cb;
int i, num_nodes;
ckt = g_mif_info.ckt;
if (!ckt)
return;
evt = ckt->evt;
if (!evt)
return;
/* Look for node name in the event-driven node list */
node_table = evt->info.node_table;
num_nodes = evt->counts.num_nodes;
for (i = 0; i < num_nodes; i++) {
if (cieq(node, node_table[i]->name))
break;
}
if (i >= num_nodes)
return;
node_info = node_table[i];
cbpp = &node_info->cbs;
cb = node_info->cbs;
while (cb) {
if (cb->fn == fn && cb->ctx == ctx) {
*cbpp = cb->next;
tfree(cb);
} else {
cbpp = &cb->next;
}
cb = *cbpp;
}
}

View File

@ -167,10 +167,12 @@ Evt_Node_Data_destroy(Evt_Ckt_Data_t *evt, Evt_Node_Data_t *node_data)
for (i = 0; i < evt->counts.num_nodes; i++) {
Evt_Node_Info_t *info = evt->info.node_table[i];
Evt_Node_t *node;
Evt_Node_t *node;
node = node_data->head[i];
while (node) {
Evt_Node_t *next = node->next;
Evt_Node_destroy(info, node);
tfree(node);
node = next;
@ -178,6 +180,7 @@ Evt_Node_Data_destroy(Evt_Ckt_Data_t *evt, Evt_Node_Data_t *node_data)
node = node_data->free[i];
while (node) {
Evt_Node_t *next = node->next;
Evt_Node_destroy(info, node);
tfree(node);
node = next;
@ -193,6 +196,7 @@ Evt_Node_Data_destroy(Evt_Ckt_Data_t *evt, Evt_Node_Data_t *node_data)
for (i = 0; i < evt->counts.num_nodes; i++) {
Evt_Node_Info_t *info = evt->info.node_table[i];
Evt_Node_destroy(info, &(node_data->rhs[i]));
Evt_Node_destroy(info, &(node_data->rhsold[i]));
}
@ -287,6 +291,7 @@ static void
Evt_Info_destroy(Evt_Info_t *info)
{
Evt_Inst_Info_t *inst = info->inst_list;
while (inst) {
Evt_Inst_Info_t *next_inst = inst->next;
tfree(inst);
@ -295,14 +300,24 @@ Evt_Info_destroy(Evt_Info_t *info)
tfree(info->inst_table);
Evt_Node_Info_t *nodei = info->node_list;
while (nodei) {
Evt_Node_Info_t *next_nodei = nodei->next;
Evt_Node_Cb_t *cb, *cb_next;
tfree(nodei->name);
for (cb = nodei->cbs; cb; cb = cb_next) {
cb_next = cb->next;
if (cb->member)
txfree(cb->member);
tfree(cb);
}
Evt_Inst_Index_t *p = nodei->inst_list;
while (p) {
Evt_Inst_Index_t *next_p = p->next;
tfree(p);
txfree(p);
p = next_p;
}

View File

@ -45,15 +45,79 @@ NON-STANDARD FEATURES
#include "ngspice/mif.h"
#include "ngspice/mifproto.h"
/*saj for output */
#include "ngspice/sim.h"
#include "ngspice/dvec.h"
//#include "ftedata.h"
//#include "fteconstant.h"
//#include "util.h"
#include "ngspice/cpstd.h"
/* Parse member qualifier from node name and find node index.
* The node name may be qualified by a member name for nodes with
* composite values such as Digital_t, as in "node_name(state)".
*/
int Evt_Parse_Node(const char *node, struct node_parse *result)
{
Evt_Ckt_Data_t *evt;
CKTcircuit *ckt;
Evt_Node_Info_t **node_table;
char *name, *ptr;
int i, num_nodes;
ckt = g_mif_info.ckt;
if (!ckt)
return -1;
evt = ckt->evt;
if (!evt)
return -1;
if (!evt->info.node_table)
return -1;
if (evt->counts.num_nodes == 0)
return -1;
/* Make a copy of the node name. Do not free this string. */
name = MIFcopy((char *)node);
/* Convert to all lower case */
strtolower(name);
/* Divide into the node name and member name */
result->node = name;
for (ptr = name; *ptr != '\0'; ptr++)
if (*ptr == '(')
break;
if (*ptr == '(') {
*ptr = '\0';
ptr++;
result->member = ptr;
for( ; *ptr != '\0'; ptr++)
if (*ptr == ')')
break;
*ptr = '\0';
} else {
result->member = NULL;
}
/* Look for node name in the event-driven node list */
node_table = evt->info.node_table;
num_nodes = evt->counts.num_nodes;
for (i = 0; i < num_nodes; i++) {
if (cieq(name, node_table[i]->name))
break;
}
if (i >= num_nodes) {
tfree(name);
return -1;
}
result->udn_index = node_table[i]->udn_index;
return i;
}
/*
EVTfindvec()
@ -79,21 +143,16 @@ keyword "all" is supplied to the plot_val routine for the member name.
struct dvec *EVTfindvec(
char *node) /* The node name (and optional member name) */
{
char *name;
char *member = "all";
char *ptr;
struct node_parse result;
int index, i;
int udn_index;
int num_events;
int i;
int num_nodes;
int udn_index;
int num_events;
Mif_Boolean_t found;
Evt_Ckt_Data_t *evt;
CKTcircuit *ckt;
Evt_Node_Info_t **node_table;
Evt_Node_t *head;
Evt_Node_t *event;
Evt_Ckt_Data_t *evt;
CKTcircuit *ckt;
Evt_Node_Info_t *node_info;
Evt_Node_t *head;
Evt_Node_t *event;
double *anal_point_vec;
double *value_vec;
@ -106,66 +165,24 @@ struct dvec *EVTfindvec(
/* or if number of event nodes is zero. */
ckt = g_mif_info.ckt;
if(! ckt)
return(NULL);
if (!ckt)
return NULL;
evt = ckt->evt;
if(! evt)
return(NULL);
if(! evt->info.node_table)
return(NULL);
if(evt->counts.num_nodes == 0)
return(NULL);
if (!evt || !evt->data.node)
return NULL;
/* Make a copy of the node name. */
/* Do not free this string. It is assigned into the dvec structure below. */
name = MIFcopy(node);
/* Convert to all lower case */
strtolower(name);
/* Divide into the node name and member name */
for(ptr = name; *ptr != '\0'; ptr++)
if(*ptr == '(')
break;
if(*ptr == '(') {
*ptr = '\0';
ptr++;
member = ptr;
for( ; *ptr != '\0'; ptr++)
if(*ptr == ')')
break;
*ptr = '\0';
}
/* Look for node name in the event-driven node list */
num_nodes = evt->counts.num_nodes;
node_table = evt->info.node_table;
for(i = 0, found = MIF_FALSE; i < num_nodes; i++) {
if(cieq(name, node_table[i]->name)) {
found = MIF_TRUE;
break;
}
}
if(! found) {
tfree(name);
return(NULL);
}
index = Evt_Parse_Node(node, &result);
if (index < 0)
return NULL;
/* Get the UDN type index */
udn_index = node_table[i]->udn_index;
if (!evt->data.node) {
// fprintf(stderr, "Warning: No event data available! \n Simulation not yet run?\n");
tfree(name);
return(NULL);
}
node_info = evt->info.node_table[index];
udn_index = node_info->udn_index;
/* Count the number of events */
head = evt->data.node->head[i];
head = evt->data.node->head[index];
for(event = head, num_events = 0; event; event = event->next)
num_events++;
@ -187,9 +204,9 @@ struct dvec *EVTfindvec(
/* Get the next value by calling the appropriate UDN plot_val function */
value = 0.0;
g_evt_udn_info[udn_index]->plot_val (event->node_value,
member,
&value);
g_evt_udn_info[udn_index]->plot_val(event->node_value,
result.member ? result.member : "all",
&value);
/* Put the first value of the horizontal line in the vector */
anal_point_vec[i] = event->step;
@ -197,6 +214,7 @@ struct dvec *EVTfindvec(
i++;
}
txfree(result.node);
/* Add one more point so that the line will extend to the end of the plot. */
@ -206,20 +224,18 @@ struct dvec *EVTfindvec(
/* Allocate dvec structures and assign the vectors into them. */
/* See FTE/OUTinterface.c:plotInit() for initialization example. */
ptr = tprintf("%s_steps", name);
scale = dvec_alloc(ptr,
scale = dvec_alloc(tprintf("%s_steps", node),
SV_TIME,
(VF_REAL | VF_EVENT_NODE) & ~VF_PERMANENT,
i, anal_point_vec);
d = dvec_alloc(name,
d = dvec_alloc(copy(node),
SV_VOLTAGE,
(VF_REAL | VF_EVENT_NODE) & ~VF_PERMANENT,
i, value_vec);
d->v_scale = scale;
/* Return the dvec */
return(d);
}

View File

@ -330,6 +330,7 @@ static void EVTnode_insert(
node->name = MIFcopy(node_name);
node->udn_index = udn_index;
node->save = MIF_TRUE; /* Backward compatible behaviour: save all. */
node->cbs = NULL;
index = ckt->evt->counts.num_nodes;
(ckt->evt->counts.num_nodes)++;
}

View File

@ -210,7 +210,7 @@ static void idn_digital_plot_val(void *evt_struct, char *member, double *val)
/* Output a value for the requested member of the digital struct */
if(strcmp(member,"strength") == 0) {
if (member && strcmp(member,"strength") == 0) {
/* Choose values that will not make plots lie on state plots */
switch(dig_struct->strength) {

View File

@ -4,7 +4,7 @@
* an Icarus Verilog simulation (libvvp.so).
* Licensed on the same terms as Ngspice.
*
* Copyright (c) 2024 Giles Atkinson
* Copyright (c) 2024-2025 Giles Atkinson
*/
#include <stdio.h>
@ -18,6 +18,12 @@
#include "coroutine_shim.h"
#ifdef _MSC_VER
#include "../../../visualc/src/include/ngspice/config.h"
#else
#include "ngspice/config.h" // For NGSPICELIBDIR
#endif
#include "ngspice/cmtypes.h" // For Digital_t
#include "ngspice/cosim.h"

View File

@ -342,7 +342,7 @@ else
if $fh > 0
fclose $fh
else
echo Can not find bulid file $msvcfile
echo Can not find build file $msvcfile
quit
end

View File

@ -673,7 +673,7 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
<IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<WholeProgramOptimization>true</WholeProgramOptimization>
<AdditionalIncludeDirectories>..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll32;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\src\maths\poly;..\src\frontend;..\src\spicelib\devices;tmp-bison;src\include;..\src\spicelib\parser;..\src\include;..\src\include\cppduals;.;..\..\fftw-3.3-dll64;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_CRT_SECURE_NO_DEPRECATE;SIMULATOR;XSPICE;USE_OMP;CONFIG64;HAVE_LIBFFTW3;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>