Compare commits
51 Commits
684dad0f9d
...
87925e4e87
| Author | SHA1 | Date |
|---|---|---|
|
|
87925e4e87 | |
|
|
91f20af48f | |
|
|
4b3de8e3bb | |
|
|
8b778c56f0 | |
|
|
5d4bb23e3c | |
|
|
0a224fa704 | |
|
|
4881b29730 | |
|
|
78908b8543 | |
|
|
db92688f54 | |
|
|
ad6635210a | |
|
|
33f18b485a | |
|
|
bb90e83f3d | |
|
|
8da323b502 | |
|
|
fdf1a7d791 | |
|
|
86467457ed | |
|
|
1a175dde2f | |
|
|
78581e3ad4 | |
|
|
a91cd8292c | |
|
|
46c5a8d375 | |
|
|
b8b83b1601 | |
|
|
31e0c8e6cf | |
|
|
cd6784a079 | |
|
|
1d435daed7 | |
|
|
db39671ae2 | |
|
|
33f206b916 | |
|
|
f4963b1ada | |
|
|
c264b71e22 | |
|
|
3bf94321e6 | |
|
|
13bbe47020 | |
|
|
7b1ecb261b | |
|
|
1445a51a2e | |
|
|
9b430ae6e4 | |
|
|
cac885401c | |
|
|
c0775705e5 | |
|
|
16fbe0fb8b | |
|
|
e7a7e8c64c | |
|
|
83d3890490 | |
|
|
317378085b | |
|
|
fc76d4d63b | |
|
|
312ef68614 | |
|
|
2988b2e279 | |
|
|
2ae162d779 | |
|
|
dae27b5135 | |
|
|
8694ce2649 | |
|
|
77131a2a33 | |
|
|
7fc4c6b5bd | |
|
|
4bc4f7a0d0 | |
|
|
82fc5e3806 | |
|
|
2ce35885ff | |
|
|
dd916b1d0e | |
|
|
0e032f30b1 |
|
|
@ -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)
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
42
src/main.c
42
src/main.c
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ inchar(FILE *fp)
|
|||
}
|
||||
|
||||
return (int) c;
|
||||
#elif
|
||||
#else
|
||||
|
||||
return getc(fp);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) *
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) *
|
||||
|
|
|
|||
|
|
@ -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) *
|
||||
|
|
|
|||
|
|
@ -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] =
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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':
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue