Merge branch 'pre-master-46' into bt_dev
This commit is contained in:
commit
e29452bdab
13
configure.ac
13
configure.ac
|
|
@ -285,10 +285,6 @@ AC_ARG_ENABLE([expdevices],
|
|||
AC_ARG_ENABLE([ndev],
|
||||
[AS_HELP_STRING([--enable-ndev], [Enable NDEV interface, (experimental)])])
|
||||
|
||||
# --enable-cluster: define CLUSTER in the code. This is for cluster support
|
||||
AC_ARG_ENABLE([cluster],
|
||||
[AS_HELP_STRING([--enable-cluster], [Enable cluster support, (experimental)])])
|
||||
|
||||
# --enable-cmathtests: run the ancient tests in src/math/cmaths
|
||||
AC_ARG_ENABLE([cmathtests],
|
||||
[AS_HELP_STRING([--enable-cmathtests], [Enable ancient tests in src/math/cmaths])])
|
||||
|
|
@ -1244,14 +1240,6 @@ if test "x$enable_ndev" = xyes; then
|
|||
fi
|
||||
AM_CONDITIONAL([NDEV_WANTED], [test "x$enable_ndev" = xyes])
|
||||
|
||||
|
||||
# Cluster option
|
||||
if test "x$enable_cluster" = xyes; then
|
||||
AC_MSG_RESULT([Cluster version is being compiled])
|
||||
AC_DEFINE([CLUSTER], [], [Spice cluster support])
|
||||
LIBS="$LIBS -lpthread"
|
||||
fi
|
||||
|
||||
if test "x$enable_expdevices" = xyes; then
|
||||
AC_DEFINE([EXP_DEV], [], [Define if we want to enable experimental devices])
|
||||
AC_MSG_RESULT([WARNING: Experimental devices enabled])
|
||||
|
|
@ -1440,7 +1428,6 @@ AC_CONFIG_FILES([Makefile
|
|||
src/xspice/mif/Makefile
|
||||
src/xspice/evt/Makefile
|
||||
src/xspice/enh/Makefile
|
||||
src/xspice/ipc/Makefile
|
||||
src/xspice/idn/Makefile
|
||||
src/xspice/verilog/Makefile
|
||||
src/xspice/vhdl/Makefile
|
||||
|
|
|
|||
|
|
@ -42,33 +42,36 @@ mp17 2 18 1 1 p1 l=0.1u w=10u ad=5p pd=6u as=5p ps=6u
|
|||
mn17 2 18 0 0 n1 l=0.1u w=5u ad=5p pd=6u as=5p ps=6u
|
||||
c1 18 0 .1p
|
||||
|
||||
* .ic v(2)=1.0 v(3)=1.0 v(4)=1.0
|
||||
* .ic v(2)=2.0 v(3)=0.0 v(4)=2.0
|
||||
* .ic v(2)=2.0 v(3)=0.0 v(4)=2.0 v(5)=0.0 v(6)=2.0
|
||||
* .ic v(7)=0.0 v(8)=2.0 v(9)=0.0 v(10)=2.0 v(11)=0.0 v(12)=2.0
|
||||
* .ic v(13)=0.0 v(14)=2.0 v(15)=0.0 v(16)=2.0 v(17)=0.0 v(18)=2.0
|
||||
* .ic V(10)=5 v(2)=5 v(3)=5 v(4)=5 v(5)=5 v(6)=5
|
||||
|
||||
* .ic v(18)=1
|
||||
|
||||
.tran .1ns 150ns uic
|
||||
|
||||
* .option xmu = 0.49
|
||||
* .print tran v(5)
|
||||
|
||||
.control
|
||||
|
||||
* reduce current ringing
|
||||
option xmu = 0.49
|
||||
* set xmu=0.49
|
||||
|
||||
set num_threads=8
|
||||
set noinit
|
||||
run
|
||||
run ; temp is 27°C
|
||||
|
||||
* current and output in a single plot
|
||||
plot v(18) 1000*(-I(vdd)) ylimit -1 6
|
||||
|
||||
meas tran tdiff TRIG v(18) VAL=0.5 RISE=10 TARG v(18) VAL=0.5 RISE=20
|
||||
let freq = 10/tdiff
|
||||
let delay = tdiff/17
|
||||
print freq delay
|
||||
echo
|
||||
echo
|
||||
|
||||
set temp=100
|
||||
run ; temp is 100°C
|
||||
|
||||
* current and output in a single plot
|
||||
plot v(18) 1000*(-I(vdd)) ylimit -1 6
|
||||
|
||||
meas tran tdiff TRIG v(18) VAL=0.5 RISE=10 TARG v(18) VAL=0.5 RISE=20
|
||||
let freq = 10/tdiff
|
||||
let delay = tdiff/17
|
||||
print freq delay
|
||||
.endc
|
||||
|
||||
* Short channel models from CMOS Circuit Design, Layout, and Simulation,
|
||||
|
|
|
|||
|
|
@ -163,7 +163,6 @@ ngspice_LDADD += \
|
|||
xspice/mif/libmifxsp.la \
|
||||
xspice/evt/libevtxsp.la \
|
||||
xspice/enh/libenhxsp.la \
|
||||
xspice/ipc/libipcxsp.la \
|
||||
xspice/idn/libidnxsp.la
|
||||
endif
|
||||
ngspice_LDADD += $(XSPICEDLLIBS)
|
||||
|
|
@ -459,7 +458,6 @@ if XSPICE_WANTED
|
|||
libspice_la_LIBADD += \
|
||||
xspice/evt/libevtxsp.la \
|
||||
xspice/enh/libenhxsp.la \
|
||||
xspice/ipc/libipcxsp.la \
|
||||
xspice/idn/libidnxsp.la
|
||||
endif
|
||||
libspice_la_LIBADD += $(XSPICEDLLIBS)
|
||||
|
|
@ -586,7 +584,6 @@ if XSPICE_WANTED
|
|||
libngspice_la_LIBADD += \
|
||||
xspice/evt/libevtxsp.la \
|
||||
xspice/enh/libenhxsp.la \
|
||||
xspice/ipc/libipcxsp.la \
|
||||
xspice/idn/libidnxsp.la
|
||||
endif
|
||||
libngspice_la_LIBADD += $(XSPICEDLLIBS)
|
||||
|
|
|
|||
|
|
@ -1542,6 +1542,7 @@ com_alter_mod(wordlist *wl)
|
|||
|
||||
if (modfile == NULL) {
|
||||
fprintf(cp_err, "Warning: Could not open file %s, altermod ignored\n", filename);
|
||||
perror(" Cause: ");
|
||||
tfree(input);
|
||||
tfree(filename);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -244,13 +244,6 @@ inp_list(FILE *file, struct card *deck, struct card *extras, int type)
|
|||
bool useout = (file == cp_out);
|
||||
int i = 1;
|
||||
|
||||
/* gtri - wbk - 03/07/91 - Don't use 'more' type output if ipc enabled */
|
||||
#ifdef XSPICE
|
||||
if (g_ipc.enabled)
|
||||
useout = FALSE;
|
||||
#endif
|
||||
/* gtri - end - 03/07/91 */
|
||||
|
||||
if (useout) {
|
||||
out_init();
|
||||
file = cp_more;
|
||||
|
|
@ -852,6 +845,7 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
#ifdef OSDI
|
||||
inputdir = dir_name;
|
||||
#endif
|
||||
/* process each pre_xxx command */
|
||||
cp_evloop(wl->wl_word);
|
||||
}
|
||||
|
||||
|
|
@ -1000,19 +994,21 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
tc->linenum, tc->line);
|
||||
}
|
||||
}
|
||||
fprintf(fdo, "**************** uncommented deck **************\n\n");
|
||||
/* always print first line */
|
||||
fprintf(fdo, "%6s %6d %6d %s\n", deck->linesource, deck->linenum_orig, deck->linenum, deck->line);
|
||||
/* here without out-commented lines */
|
||||
for (tc = deck->nextcard; tc; tc = tc->nextcard) {
|
||||
if (*(tc->line) == '*')
|
||||
continue;
|
||||
fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line);
|
||||
if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) {
|
||||
fprintf(fdo, "**************** uncommented deck **************\n\n");
|
||||
/* always print first line */
|
||||
fprintf(fdo, "%6s %6d %6d %s\n", deck->linesource, deck->linenum_orig, deck->linenum, deck->line);
|
||||
/* here without out-commented lines */
|
||||
for (tc = deck->nextcard; tc; tc = tc->nextcard) {
|
||||
if (*(tc->line) == '*')
|
||||
continue;
|
||||
fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line);
|
||||
}
|
||||
fprintf(fdo, "\n****************** complete deck ***************\n\n");
|
||||
/* now completely */
|
||||
for (tc = deck; tc; tc = tc->nextcard)
|
||||
fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line);
|
||||
}
|
||||
fprintf(fdo, "\n****************** complete deck ***************\n\n");
|
||||
/* now completely */
|
||||
for (tc = deck; tc; tc = tc->nextcard)
|
||||
fprintf(fdo, "%6s %6d %6d %s\n", tc->linesource, tc->linenum_orig, tc->linenum, tc->line);
|
||||
fclose(fdo);
|
||||
}
|
||||
else
|
||||
|
|
@ -1216,10 +1212,12 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
|
|||
continue;
|
||||
fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line);
|
||||
}
|
||||
fprintf(fdo, "\n****************** complete deck ***************\n\n");
|
||||
/* now completely */
|
||||
for (tc = deck; tc; tc = tc->nextcard)
|
||||
fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line);
|
||||
if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) {
|
||||
fprintf(fdo, "\n****************** complete deck ***************\n\n");
|
||||
/* now completely */
|
||||
for (tc = deck; tc; tc = tc->nextcard)
|
||||
fprintf(fdo, "%6d %6d %s\n", tc->linenum_orig, tc->linenum, tc->line);
|
||||
}
|
||||
fclose(fdo);
|
||||
}
|
||||
else
|
||||
|
|
@ -1474,10 +1472,6 @@ inp_dodeck(
|
|||
|
||||
if (dd->error) {
|
||||
char *p, *q;
|
||||
#ifdef XSPICE
|
||||
/* add setting of ipc syntax error flag */
|
||||
g_ipc.syntax_error = IPC_TRUE;
|
||||
#endif
|
||||
p = dd->error;
|
||||
fflush(stdout);
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -583,6 +583,7 @@ static struct library *read_a_lib(const char *y, const char *dir_name)
|
|||
|
||||
if (!newfp) {
|
||||
fprintf(cp_err, "Error: Could not open library file %s\n", y);
|
||||
perror(" Cause: ");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -1256,32 +1257,35 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name,
|
|||
t->linenum, t->line);
|
||||
}
|
||||
}
|
||||
fprintf(fd,
|
||||
"\n\n**************** uncommented deck "
|
||||
"**************\n\n");
|
||||
/* always print first line */
|
||||
fprintf(fd, "%6s %6d %6d %s\n", cc->linesource, cc->linenum_orig, cc->linenum,
|
||||
cc->line);
|
||||
/* here without out-commented lines */
|
||||
for (t = cc->nextcard; t; t = t->nextcard) {
|
||||
if (*(t->line) == '*')
|
||||
continue;
|
||||
fprintf(fd, "%6s %6d %6d %s\n",
|
||||
t->linesource, t->linenum_orig, t->linenum, t->line);
|
||||
}
|
||||
fprintf(fd,
|
||||
if (!cp_getvar("debug-out-short", CP_BOOL, NULL, 0)) {
|
||||
fprintf(fd,
|
||||
"\n\n**************** uncommented deck "
|
||||
"**************\n\n");
|
||||
/* always print first line */
|
||||
fprintf(fd, "%6s %6d %6d %s\n", cc->linesource, cc->linenum_orig, cc->linenum,
|
||||
cc->line);
|
||||
/* here without out-commented lines */
|
||||
for (t = cc->nextcard; t; t = t->nextcard) {
|
||||
if (*(t->line) == '*')
|
||||
continue;
|
||||
fprintf(fd, "%6s %6d %6d %s\n",
|
||||
t->linesource, t->linenum_orig, t->linenum, t->line);
|
||||
}
|
||||
fprintf(fd,
|
||||
"\n\n****************** complete deck "
|
||||
"***************\n\n");
|
||||
/* now completely */
|
||||
for (t = cc; t; t = t->nextcard)
|
||||
fprintf(fd, "%6s %6d %6d %s\n",
|
||||
t->linesource, t->linenum_orig,t->linenum, t->line);
|
||||
/* now completely */
|
||||
for (t = cc; t; t = t->nextcard)
|
||||
fprintf(fd, "%6s %6d %6d %s\n",
|
||||
t->linesource, t->linenum_orig, t->linenum, t->line);
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
fprintf(stdout,
|
||||
"max line length %d, max subst. per line %d, number "
|
||||
"of lines %d\n",
|
||||
(int) max_line_length, no_braces, dynmaxline);
|
||||
"max line length %d, max subst. per line %d, number "
|
||||
"of lines %d\n",
|
||||
(int)max_line_length, no_braces, dynmaxline);
|
||||
|
||||
}
|
||||
else
|
||||
fprintf(stderr,
|
||||
|
|
@ -1354,53 +1358,24 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name
|
|||
else {
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - modify - 12/12/90 - wbk - read from mailbox if ipc
|
||||
* enabled */
|
||||
|
||||
/* If IPC is not enabled, do equivalent of what SPICE did before
|
||||
*/
|
||||
if (!g_ipc.enabled) {
|
||||
if (call_depth == 0 && line_count == 0) {
|
||||
line_count++;
|
||||
if (fgets(big_buff, 5000, fp))
|
||||
buffer = copy(big_buff);
|
||||
}
|
||||
else {
|
||||
buffer = readline(fp);
|
||||
if (!buffer)
|
||||
break;
|
||||
}
|
||||
if (call_depth == 0 && line_count == 0) {
|
||||
line_count++;
|
||||
if (fgets(big_buff, 5000, fp))
|
||||
buffer = copy(big_buff);
|
||||
}
|
||||
else {
|
||||
/* else, get the line from the ipc channel. */
|
||||
/* We assume that newlines are not sent by the client */
|
||||
/* so we add them here */
|
||||
char ipc_buffer[1025]; /* Had better be big enough */
|
||||
int ipc_len;
|
||||
Ipc_Status_t ipc_status =
|
||||
ipc_get_line(ipc_buffer, &ipc_len, IPC_WAIT);
|
||||
if (ipc_status == IPC_STATUS_END_OF_DECK) {
|
||||
buffer = NULL;
|
||||
buffer = readline(fp);
|
||||
if (!buffer)
|
||||
break;
|
||||
}
|
||||
else if (ipc_status == IPC_STATUS_OK) {
|
||||
buffer = TMALLOC(char, strlen(ipc_buffer) + 3);
|
||||
strcpy(buffer, ipc_buffer);
|
||||
strcat(buffer, "\n");
|
||||
}
|
||||
else { /* No good way to report this so just die */
|
||||
fprintf(stderr, "Error: IPC status not o.k.\n");
|
||||
controlled_exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* gtri - end - 12/12/90 */
|
||||
#else
|
||||
|
||||
buffer = readline(fp);
|
||||
if (!buffer) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1564,6 +1539,7 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name
|
|||
else
|
||||
fprintf(cp_err, " While reading %s\n", y_resolved);
|
||||
}
|
||||
perror(" Cause: ");
|
||||
tfree(buffer); /* allocated by readline() above */
|
||||
controlled_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
@ -3473,7 +3449,7 @@ static void inp_stripcomments_deck(struct card *c, bool cf)
|
|||
found_control = TRUE;
|
||||
if (ciprefix(".endc", c->line))
|
||||
found_control = FALSE;
|
||||
inp_stripcomments_line(c->line, found_control | cf, FALSE);
|
||||
inp_stripcomments_line(c->line, found_control || cf, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -255,8 +255,10 @@ do_measure(
|
|||
|
||||
if (cp_getvar("measoutfile", CP_STRING, out_file, sizeof(out_file))) {
|
||||
measout = fopen(out_file, "w");
|
||||
if (!measout)
|
||||
if (!measout) {
|
||||
fprintf(stderr, " Warning: Could not open file %s\n", out_file);
|
||||
perror(" Cause: ");
|
||||
}
|
||||
}
|
||||
|
||||
/* Evaluating the linked list of .meas cards, assembled from the input deck
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ extern long dynsubst; /* see inpcom.c */
|
|||
#define S_stop 4
|
||||
|
||||
static char* sort_idlist(char *list);
|
||||
static char *string_expr(dico_t *, DSTRINGPTR, const char *, const char *);
|
||||
|
||||
static double
|
||||
ternary_fcn(double conditional, double if_value, double else_value)
|
||||
|
|
@ -83,23 +84,27 @@ limit(double nominal_val, double abs_variation)
|
|||
return (nominal_val + (drand() > 0 ? abs_variation : -1. * abs_variation));
|
||||
}
|
||||
|
||||
/* The list of built-in functions. Patch 'mathfunction', here to get more ...
|
||||
* Function "vec" and following take a string argument and must come last.
|
||||
*/
|
||||
|
||||
static const char *fmathS = /* all math functions */
|
||||
"sqr sqrt sin cos exp ln arctan abs pow pwr max min int log log10 sinh cosh"
|
||||
" tanh ternary_fcn agauss sgn gauss unif aunif limit ceil floor"
|
||||
" asin acos atan asinh acosh atanh tan nint";
|
||||
" asin acos atan asinh acosh atanh tan nint"
|
||||
" vec var";
|
||||
|
||||
|
||||
enum {
|
||||
XFU_SQR = 1, XFU_SQRT, XFU_SIN, XFU_COS, XFU_EXP, XFU_LN, XFU_ARCTAN, XFU_ABS, XFU_POW, XFU_PWR, XFU_MAX, XFU_MIN, XFU_INT, XFU_LOG, XFU_LOG10, XFU_SINH, XFU_COSH,
|
||||
XFU_TANH, XFU_TERNARY_FCN, XFU_AGAUSS, XFU_SGN, XFU_GAUSS, XFU_UNIF, XFU_AUNIF, XFU_LIMIT, XFU_CEIL, XFU_FLOOR,
|
||||
XFU_ASIN, XFU_ACOS, XFU_ATAN, XFU_ASINH, XFU_ACOSH, XFU_ATANH, XFU_TAN, XFU_NINT
|
||||
XFU_ASIN, XFU_ACOS, XFU_ATAN, XFU_ASINH, XFU_ACOSH, XFU_ATANH, XFU_TAN, XFU_NINT,
|
||||
XFU_VEC, XFU_VAR // String arguments.
|
||||
};
|
||||
|
||||
|
||||
static double
|
||||
mathfunction(int f, double z, double x)
|
||||
/* the list of built-in functions. Patch 'fmath', here and near line 888 to get more ...*/
|
||||
{
|
||||
double y;
|
||||
switch (f)
|
||||
|
|
@ -946,6 +951,48 @@ formula(dico_t *dico, const char *s, const char *s_end, bool *perror)
|
|||
if (kptr >= s_end) {
|
||||
error = message(dico, "Closing \")\" not found.\n");
|
||||
natom++; /* shut up other error message */
|
||||
} else if (fu >= XFU_VEC) {
|
||||
struct dvec *d;
|
||||
char *vec_name;
|
||||
|
||||
/* Special case: function with string arg.
|
||||
* Try to evaluate any string expression, else use directly.
|
||||
*/
|
||||
|
||||
if (string_expr(dico, &tstr, s, kptr) != kptr)
|
||||
pscopy(&tstr, s, kptr); // No, or not fully consumed.
|
||||
vec_name = ds_get_buf(&tstr);
|
||||
|
||||
if (fu == XFU_VEC) {
|
||||
struct plot *cplot, *prev;
|
||||
|
||||
d = vec_get(vec_name);
|
||||
|
||||
/* A simple name will be looked-up is the current plot.
|
||||
* Try "const" if not found.
|
||||
*/
|
||||
|
||||
if (!d && !strchr(vec_name, '.')) {
|
||||
cplot = get_plot("const");
|
||||
if (plot_cur != cplot) {
|
||||
prev = plot_cur;
|
||||
plot_cur = cplot;
|
||||
d = vec_get(vec_name);
|
||||
plot_cur = prev;
|
||||
}
|
||||
}
|
||||
|
||||
if (d && d->v_length > 0 && isreal(d))
|
||||
u = d->v_realdata[0];
|
||||
else
|
||||
u = 0;
|
||||
} else if (fu == XFU_VAR) {
|
||||
if (!cp_getvar(vec_name, CP_REAL, &u, sizeof u))
|
||||
u = 0;
|
||||
}
|
||||
state = S_atom;
|
||||
s = kptr + 1;
|
||||
fu = 0;
|
||||
} else {
|
||||
if (arg2 >= s) {
|
||||
v = formula(dico, s, arg2, &error);
|
||||
|
|
@ -1088,7 +1135,7 @@ formula(dico_t *dico, const char *s, const char *s_end, bool *perror)
|
|||
}
|
||||
|
||||
|
||||
/* Check for a string expression, return end pointer or NULL.
|
||||
/* Check for a string expression, return end pointer or NULL.
|
||||
* A string expression is a sequence of quoted strings and string
|
||||
* variables, optionally enclosed by '{}' with no interventing space.
|
||||
* If successful return pointer to next char, otherwise NULL.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ Modified: 2000 AlansFixes, 2013/2015 patch by Krzysztof Blaszkowski
|
|||
#include "variable.h"
|
||||
#include <fcntl.h>
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "ngspice/inpdefs.h"
|
||||
#include "breakp2.h"
|
||||
#include "runcoms.h"
|
||||
#include "plotting/graf.h"
|
||||
|
|
@ -119,20 +118,6 @@ OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr,
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
OUTwBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr,
|
||||
IFuid analName,
|
||||
IFuid refName, int refType,
|
||||
int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr)
|
||||
{
|
||||
|
||||
return (beginPlot(analysisPtr, circuitPtr, "circuit name",
|
||||
analName, refName, refType, numNames,
|
||||
dataNames, dataType, TRUE,
|
||||
plotPtr));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analName, char *refName, int refType, int numNames, char **dataNames, int dataType, bool windowed, runDesc **runp)
|
||||
{
|
||||
|
|
@ -149,10 +134,9 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam
|
|||
bool savenointernals = FALSE;
|
||||
char *an_name;
|
||||
int initmem;
|
||||
/*to resume a run saj
|
||||
*All it does is reassign the file pointer and return (requires *runp to be NULL if this is not needed)
|
||||
*/
|
||||
|
||||
/*to resume a run, Reassign the file pointer and return
|
||||
(requires *runp to be NULL if this is not needed)*/
|
||||
if (dataType == 666 && numNames == 666) {
|
||||
run = *runp;
|
||||
run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary,
|
||||
|
|
@ -280,6 +264,12 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam
|
|||
saves[i].used = 1;
|
||||
break;
|
||||
}
|
||||
else if (ft_ngdebug && refName && eq(refName, "time") && eq(saves[i].name, "deltacheck")) {
|
||||
addDataDesc(run, "deltacheck", IF_REAL, j, initmem);
|
||||
savesused[i] = TRUE;
|
||||
saves[i].used = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -307,6 +297,7 @@ beginPlot(JOB *analysisPtr, CKTcircuit *circuitPtr, char *cktName, char *analNam
|
|||
/* generate a vector of real time information */
|
||||
if (ft_ngdebug && refName && eq(refName, "time")) {
|
||||
addDataDesc(run, "speedcheck", IF_REAL, numNames, initmem);
|
||||
addDataDesc(run, "deltacheck", IF_REAL, numNames, initmem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -582,6 +573,9 @@ OUTpD_memory(runDesc *run, IFvalue *refValue, IFvalue *valuePtr)
|
|||
double tt = ((double)cl - (double)startclock) / CLOCKS_PER_SEC;
|
||||
plotAddRealValue(d, tt);
|
||||
}
|
||||
else if (ft_ngdebug && d->type == IF_REAL && eq(d->name, "deltacheck")) {
|
||||
plotAddRealValue(d, ft_curckt->ci_ckt->CKTdeltaOld[0]);
|
||||
}
|
||||
else if (d->type == IF_REAL)
|
||||
plotAddRealValue(d, valuePtr->v.vec.rVec[d->outIndex]);
|
||||
else if (d->type == IF_COMPLEX)
|
||||
|
|
@ -693,6 +687,9 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr)
|
|||
double tt = ((double)cl - (double)startclock) / CLOCKS_PER_SEC;
|
||||
fileAddRealValue(run->fp, run->binary, tt);
|
||||
}
|
||||
else if (ft_ngdebug && run->data[i].type == IF_REAL && eq(run->data[i].name, "deltacheck")) {
|
||||
fileAddRealValue(run->fp, run->binary, ft_curckt->ci_ckt->CKTdeltaOld[0]);
|
||||
}
|
||||
else if (run->data[i].type == IF_REAL)
|
||||
fileAddRealValue(run->fp, run->binary,
|
||||
valuePtr->v.vec.rVec [run->data[i].outIndex]);
|
||||
|
|
@ -789,38 +786,6 @@ OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr)
|
|||
} /* end of function OUTpData */
|
||||
|
||||
|
||||
|
||||
int OUTwReference(runDesc*plotPtr, IFvalue *valuePtr, void **refPtr)
|
||||
{
|
||||
NG_IGNORE(refPtr);
|
||||
NG_IGNORE(valuePtr);
|
||||
NG_IGNORE(plotPtr);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr)
|
||||
{
|
||||
NG_IGNORE(refPtr);
|
||||
NG_IGNORE(valuePtr);
|
||||
NG_IGNORE(dataIndex);
|
||||
NG_IGNORE(plotPtr);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
OUTwEnd(runDesc *plotPtr)
|
||||
{
|
||||
NG_IGNORE(plotPtr);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
OUTendPlot(runDesc *plotPtr)
|
||||
{
|
||||
|
|
@ -840,27 +805,6 @@ OUTendPlot(runDesc *plotPtr)
|
|||
}
|
||||
|
||||
|
||||
int
|
||||
OUTbeginDomain(runDesc *plotPtr, IFuid refName, int refType, IFvalue *outerRefValue)
|
||||
{
|
||||
NG_IGNORE(outerRefValue);
|
||||
NG_IGNORE(refType);
|
||||
NG_IGNORE(refName);
|
||||
NG_IGNORE(plotPtr);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
OUTendDomain(runDesc *plotPtr)
|
||||
{
|
||||
NG_IGNORE(plotPtr);
|
||||
|
||||
return (OK);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
OUTattributes(runDesc *plotPtr, IFuid varName, int param, IFvalue *value)
|
||||
{
|
||||
|
|
@ -957,8 +901,9 @@ fileInit(runDesc *run)
|
|||
}
|
||||
|
||||
/* Trying to guess the type of a vector, using either their special names
|
||||
or special parameter names for @ vecors. FIXME This guessing may fail
|
||||
due to the many options, especially for the @ vectors. */
|
||||
or special parameter names for @ vectors. FIXME This guessing may fail
|
||||
due to the many options, especially for the @ vectors. pltypename
|
||||
may be run->type in batch mode or the plot name in control mode. */
|
||||
static int
|
||||
guess_type(const char *name, char* pltypename)
|
||||
{
|
||||
|
|
@ -970,6 +915,8 @@ guess_type(const char *name, char* pltypename)
|
|||
type = SV_TIME;
|
||||
else if ( cieq(name, "speedcheck"))
|
||||
type = SV_TIME;
|
||||
else if ( cieq(name, "deltacheck"))
|
||||
type = SV_TIME;
|
||||
else if (cieq(name, "frequency"))
|
||||
type = SV_FREQUENCY;
|
||||
else if (ciprefix("inoise", name))
|
||||
|
|
@ -1025,13 +972,15 @@ static void
|
|||
fileInit_pass2(runDesc *run)
|
||||
{
|
||||
int i, type;
|
||||
|
||||
bool keepbranch = cp_getvar("keep#branch", CP_BOOL, NULL, 0);
|
||||
|
||||
for (i = 0; i < run->numData; i++) {
|
||||
|
||||
char *name = run->data[i].name;
|
||||
|
||||
type = guess_type(name, NULL);
|
||||
/* Use run->type to detect SP analysis */
|
||||
type = guess_type(name, run->type);
|
||||
|
||||
if (type == SV_CURRENT && !keepbranch) {
|
||||
char *branch = strstr(name, "#branch");
|
||||
|
|
@ -1170,6 +1119,7 @@ plotInit(runDesc *run)
|
|||
else
|
||||
name = copy(dd->name);
|
||||
|
||||
/* Use pl->pl_typename to detect SP analysis */
|
||||
v = dvec_alloc(name,
|
||||
guess_type(name, pl->pl_typename),
|
||||
run->isComplex
|
||||
|
|
|
|||
|
|
@ -50,17 +50,8 @@ int OUTpBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr,
|
|||
IFuid analName,
|
||||
IFuid refName, int refType,
|
||||
int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr);
|
||||
int OUTwBeginPlot(CKTcircuit *circuitPtr, JOB *analysisPtr,
|
||||
IFuid analName,
|
||||
IFuid refName, int refType,
|
||||
int numNames, IFuid *dataNames, int dataType, runDesc **plotPtr);
|
||||
int OUTpData(runDesc *plotPtr, IFvalue *refValue, IFvalue *valuePtr);
|
||||
int OUTwReference(runDesc *plotPtr, IFvalue *valuePtr, void **refPtr);
|
||||
int OUTwData(runDesc *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr);
|
||||
int OUTwEnd(runDesc *plotPtr);
|
||||
int OUTendPlot(runDesc *plotPtr);
|
||||
int OUTbeginDomain(runDesc *plotPtr, IFuid refName, int refType, IFvalue *outerRefValue);
|
||||
int OUTendDomain(runDesc *plotPtr);
|
||||
int OUTattributes(runDesc *plotPtr, IFuid varName, int param, IFvalue *value);
|
||||
int OUTstopnow(void);
|
||||
void OUTerror(int flags, char *format, IFuid *names);
|
||||
|
|
|
|||
|
|
@ -213,14 +213,6 @@ printres(char *name)
|
|||
called = TRUE;
|
||||
}
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - 12/12/90 - wbk - record cpu time used for ipc */
|
||||
g_ipc.cpu_time = (double) last_msec;
|
||||
g_ipc.cpu_time /= 1000.0;
|
||||
g_ipc.cpu_time += (double) last_sec;
|
||||
/* gtri - end - 12/12/90 */
|
||||
#endif
|
||||
|
||||
yy = TRUE;
|
||||
#else
|
||||
if (!name || eq(name, "totalcputime"))
|
||||
|
|
|
|||
|
|
@ -323,14 +323,6 @@ static int dosim(
|
|||
if (if_sens_run(ft_curckt->ci_ckt, ww, ft_curckt->ci_symtab) == 1) {
|
||||
/* The circuit was interrupted somewhere. */
|
||||
fprintf(cp_err, "%s simulation interrupted\n", what);
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - 12/12/90 - wbk - record error and return errchk */
|
||||
g_ipc.run_error = IPC_TRUE;
|
||||
if (g_ipc.enabled) {
|
||||
ipc_send_errchk();
|
||||
}
|
||||
/* gtri - end - 12/12/90 */
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
ft_curckt->ci_inprogress = FALSE;
|
||||
|
|
@ -342,14 +334,6 @@ static int dosim(
|
|||
if (err == 1) {
|
||||
/* The circuit was interrupted somewhere. */
|
||||
fprintf(cp_err, "%s simulation interrupted\n", what);
|
||||
#ifdef XSPICE
|
||||
/* record error and return errchk */
|
||||
g_ipc.run_error = IPC_TRUE;
|
||||
if (g_ipc.enabled) {
|
||||
ipc_send_errchk();
|
||||
}
|
||||
/* gtri - end - 12/12/90 */
|
||||
#endif
|
||||
err = 0;
|
||||
}
|
||||
else if (err == 2) {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ struct bxx_buffer;
|
|||
static void finishLine(struct bxx_buffer *dst, char *src, char *scname);
|
||||
static int settrans(char *formal, int flen, char *actual, const char *subname);
|
||||
static char *gettrans(const char *name, const char *name_end, bool *isglobal);
|
||||
static int numnodes(const char *line);
|
||||
static int numnodes(const char* line, struct subs* subs);
|
||||
static int numdevs(char *s);
|
||||
static wordlist *modtranslate(struct card *deck, char *subname, wordlist *new_modnames);
|
||||
static void devmodtranslate(struct card *deck, char *subname, wordlist * const orig_modnames);
|
||||
|
|
@ -135,9 +135,6 @@ struct subs {
|
|||
* list of translated names (i.e. after subckt expansion)
|
||||
*/
|
||||
|
||||
/* flag indicating use of the experimental numparams library */
|
||||
static bool use_numparams = FALSE;
|
||||
|
||||
static char start[32], sbend[32], invoke[32], model[32];
|
||||
|
||||
static void
|
||||
|
|
@ -224,48 +221,41 @@ inp_subcktexpand(struct card *deck) {
|
|||
if (!cp_getvar("modelline", CP_STRING, model, sizeof(model)))
|
||||
strcpy(model, ".model");
|
||||
|
||||
/* use_numparams = cp_getvar("numparams", CP_BOOL, NULL, 0); */
|
||||
|
||||
use_numparams = TRUE;
|
||||
// tprint(deck);
|
||||
/* deck has .control sections already removed, but not comments */
|
||||
if (use_numparams) {
|
||||
|
||||
#ifdef TRACE
|
||||
fprintf(stderr, "Numparams is processing this deck:\n");
|
||||
for (c = deck; c; c = c->nextcard) {
|
||||
if (ciprefix("*", c->line))
|
||||
continue;
|
||||
fprintf(stderr, "%3d:%s\n", c->linenum, c->line);
|
||||
}
|
||||
#endif
|
||||
|
||||
nupa_signal(NUPADECKCOPY);
|
||||
/* get the subckt names from the deck */
|
||||
for (c = deck; c; c = c->nextcard) { /* first Numparam pass */
|
||||
if (ciprefix(".subckt", c->line)) {
|
||||
nupa_scan(c);
|
||||
}
|
||||
}
|
||||
|
||||
/* now copy instances */
|
||||
for (c = deck; c; c = c->nextcard) { /* first Numparam pass */
|
||||
if (*(c->line) == '*') {
|
||||
continue;
|
||||
}
|
||||
c->line = nupa_copy(c);
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
fprintf(stderr, "Numparams transformed deck:\n");
|
||||
for (c = deck; c; c = c->nextcard) {
|
||||
if (ciprefix("*", c->line))
|
||||
continue;
|
||||
fprintf(stderr, "%3d:%s\n", c->linenum, c->line);
|
||||
}
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "Numparams is processing this deck:\n");
|
||||
for (c = deck; c; c = c->nextcard) {
|
||||
if (ciprefix("*", c->line))
|
||||
continue;
|
||||
fprintf(stderr, "%3d:%s\n", c->linenum, c->line);
|
||||
}
|
||||
#endif
|
||||
|
||||
nupa_signal(NUPADECKCOPY);
|
||||
/* get the subckt names from the deck */
|
||||
for (c = deck; c; c = c->nextcard) { /* first Numparam pass */
|
||||
if (ciprefix(".subckt", c->line)) {
|
||||
nupa_scan(c);
|
||||
}
|
||||
}
|
||||
|
||||
/* now copy instances */
|
||||
for (c = deck; c; c = c->nextcard) { /* first Numparam pass */
|
||||
if (*(c->line) == '*') {
|
||||
continue;
|
||||
}
|
||||
c->line = nupa_copy(c);
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
fprintf(stderr, "Numparams transformed deck:\n");
|
||||
for (c = deck; c; c = c->nextcard) {
|
||||
if (ciprefix("*", c->line))
|
||||
continue;
|
||||
fprintf(stderr, "%3d:%s\n", c->linenum, c->line);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get all the model names so we can deal with BJTs, etc.
|
||||
* Stick all the model names into the doubly-linked wordlist modnames.
|
||||
|
|
@ -374,36 +364,34 @@ inp_subcktexpand(struct card *deck) {
|
|||
if (ciprefix(invoke, c->line)) {
|
||||
fprintf(cp_err, "Error: unknown subckt: %s\n", c->line);
|
||||
fprintf(cp_err, " in line no. %d from file %s\n", c->linenum_orig, c->linesource);
|
||||
if (use_numparams)
|
||||
nupa_signal(NUPAEVALDONE);
|
||||
|
||||
nupa_signal(NUPAEVALDONE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (use_numparams) {
|
||||
/* the NUMPARAM final line translation pass */
|
||||
nupa_signal(NUPASUBDONE);
|
||||
for (c = deck; c; c = c->nextcard)
|
||||
/* 'param' .meas statements can have dependencies on measurement values */
|
||||
/* need to skip evaluating here and evaluate after other .meas statements */
|
||||
if (ciprefix(".meas", c->line) && strstr(c->line, "param")) {
|
||||
;
|
||||
} else {
|
||||
nupa_eval(c);
|
||||
}
|
||||
/* the NUMPARAM final line translation pass */
|
||||
nupa_signal(NUPASUBDONE);
|
||||
for (c = deck; c; c = c->nextcard)
|
||||
/* 'param' .meas statements can have dependencies on measurement values */
|
||||
/* need to skip evaluating here and evaluate after other .meas statements */
|
||||
if (ciprefix(".meas", c->line) && strstr(c->line, "param")) {
|
||||
;
|
||||
} else {
|
||||
nupa_eval(c);
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
fprintf(stderr, "Numparams converted deck:\n");
|
||||
for (c = deck; c; c = c->nextcard) {
|
||||
if (ciprefix("*", c->line))
|
||||
continue;
|
||||
fprintf(stderr, "%3d:%s\n", c->linenum, c->line);
|
||||
}
|
||||
fprintf(stderr, "Numparams converted deck:\n");
|
||||
for (c = deck; c; c = c->nextcard) {
|
||||
if (ciprefix("*", c->line))
|
||||
continue;
|
||||
fprintf(stderr, "%3d:%s\n", c->linenum, c->line);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*nupa_list_params(stdout);*/
|
||||
nupa_copy_inst_dico();
|
||||
nupa_signal(NUPAEVALDONE);
|
||||
}
|
||||
/*nupa_list_params(stdout);*/
|
||||
nupa_copy_inst_dico();
|
||||
nupa_signal(NUPAEVALDONE);
|
||||
|
||||
return (deck); /* return the spliced deck. */
|
||||
}
|
||||
|
|
@ -535,13 +523,8 @@ doit(struct card *deck, wordlist *modnames) {
|
|||
else
|
||||
deck = c;
|
||||
|
||||
if (use_numparams == FALSE) {
|
||||
line_free_x(ends, FALSE); /* drop the .ends card */
|
||||
prev_of_ends->nextcard = NULL;
|
||||
} else {
|
||||
ends->line[0] = '*'; /* comment the .ends card */
|
||||
ends->nextcard = NULL;
|
||||
}
|
||||
ends->line[0] = '*'; /* comment the .ends card */
|
||||
ends->nextcard = NULL;
|
||||
|
||||
} else {
|
||||
|
||||
|
|
@ -760,18 +743,8 @@ doit(struct card *deck, wordlist *modnames) {
|
|||
error = 1;
|
||||
|
||||
/* Now splice the decks together. */
|
||||
|
||||
if (use_numparams == FALSE) {
|
||||
line_free_x(c, FALSE); /* drop the invocation */
|
||||
if (prev_of_c)
|
||||
prev_of_c->nextcard = su_deck;
|
||||
else
|
||||
deck = su_deck;
|
||||
} else {
|
||||
c->line[0] = '*'; /* comment the invocation */
|
||||
c->nextcard = su_deck;
|
||||
}
|
||||
|
||||
c->line[0] = '*'; /* comment the invocation */
|
||||
c->nextcard = su_deck;
|
||||
c = su_deck;
|
||||
while (c->nextcard)
|
||||
c = c->nextcard;
|
||||
|
|
@ -1173,11 +1146,15 @@ translate_inst_name(struct bxx_buffer *buffer, const char *scname, const char *n
|
|||
static int
|
||||
translate(struct card *deck, char *formal, int flen, char *actual, char *scname, const char *subname, struct subs *subs, wordlist const *modnames)
|
||||
{
|
||||
|
||||
struct card *c;
|
||||
struct bxx_buffer buffer;
|
||||
char *next_name, *name, *t, *nametofree, *paren_ptr;
|
||||
int nnodes, i, dim;
|
||||
int rtn = 0;
|
||||
|
||||
NG_IGNORE(modnames);
|
||||
|
||||
#ifdef XSPICE
|
||||
bool got_vnam = FALSE;
|
||||
#endif
|
||||
|
|
@ -1387,7 +1364,7 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname,
|
|||
* Ignore controlling nodes as they get special treatment for POLY.
|
||||
*/
|
||||
|
||||
nnodes = numnodes(c->line);
|
||||
nnodes = numnodes(c->line, subs);
|
||||
while (--nnodes >= 0) {
|
||||
name = gettok_node(&s);
|
||||
if (name == NULL) {
|
||||
|
|
@ -1477,7 +1454,7 @@ translate(struct card *deck, char *formal, int flen, char *actual, char *scname,
|
|||
tfree(name);
|
||||
bxx_putc(&buffer, ' ');
|
||||
|
||||
nnodes = numnodes(c->line);
|
||||
nnodes = numnodes(c->line, subs);
|
||||
while (--nnodes >= 0) {
|
||||
name = gettok_node(&s);
|
||||
if (name == NULL) {
|
||||
|
|
@ -1690,18 +1667,26 @@ gettrans(const char *name, const char *name_end, bool *isglobal)
|
|||
/* Control nodes for E and G sources are not counted as they vary in
|
||||
* the case of POLY. The count returned by get_number_terminals() includes
|
||||
* devices for K (mutual inductors) and W (current-controlled switch).
|
||||
*/
|
||||
|
||||
* x lines are special, when nested and containing parameters.
|
||||
* Therefore the old code is kept.*/
|
||||
static int
|
||||
numnodes(const char *line)
|
||||
numnodes(const char* line, struct subs* subs)
|
||||
{
|
||||
switch (*line) {
|
||||
case 'e':
|
||||
case 'g':
|
||||
case 'w':
|
||||
return 2;
|
||||
case 'k':
|
||||
return 0;
|
||||
case 'e':
|
||||
case 'g':
|
||||
case 'w':
|
||||
return 2;
|
||||
case 'k':
|
||||
return 0;
|
||||
case 'x':
|
||||
{
|
||||
const char* xname_e = skip_back_ws(strchr(line, '\0'), line);
|
||||
const char* xname = skip_back_non_ws(xname_e, line);
|
||||
for (; subs; subs = subs->su_next)
|
||||
if (eq_substr(xname, xname_e, subs->su_name))
|
||||
return subs->su_numargs;
|
||||
}
|
||||
}
|
||||
return get_number_terminals((char *)line);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ noinst_HEADERS = \
|
|||
ciderinp.h \
|
||||
cidersupt.h \
|
||||
cktdefs.h \
|
||||
cluster.h \
|
||||
cmconstants.h \
|
||||
cm.h \
|
||||
cmproto.h \
|
||||
|
|
|
|||
|
|
@ -206,11 +206,11 @@ struct CKTcircuit {
|
|||
int CKTtranMaxIter; /* iteration limit for each timepoint
|
||||
for tran*/
|
||||
/* (itl4) */
|
||||
int CKTbreakSize; /* ??? */
|
||||
int CKTbreak; /* ??? */
|
||||
double CKTsaveDelta; /* ??? */
|
||||
double CKTminBreak; /* ??? */
|
||||
double *CKTbreaks; /* List of breakpoints ??? */
|
||||
int CKTbreakSize; /* number of breakpoints in table *CKTbreaks */
|
||||
int CKTbreak; /* if 1, a breakpoint may be set (only used in isrcacct.c) */
|
||||
double CKTsaveDelta; /* previous delta, before breakpoints set a new delta */
|
||||
double CKTminBreak; /* minimum time difference between breakpoints */
|
||||
double *CKTbreaks; /* List of breakpoints as an array of doubles */
|
||||
double CKTabstol; /* --- */
|
||||
double CKTpivotAbsTol; /* --- */
|
||||
double CKTpivotRelTol; /* --- */
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef ngspice_CLUSTER_H
|
||||
#define ngspice_CLUSTER_H
|
||||
#include "ngspice/cktdefs.h"
|
||||
|
||||
/* Cluster definitions */
|
||||
#define PORT 1234
|
||||
#define TIME_PORT 1235
|
||||
#define DOMAIN_NAME "cluster.multigig"
|
||||
#define CLUSTER_WIDTH 4
|
||||
#define TIME_HOST "time.cluster.multigig"
|
||||
/* does all the setups */
|
||||
extern int CLUsetup(CKTcircuit *ckt);
|
||||
|
||||
/* reads input pipes and sets voltages*/
|
||||
/* call each time the present time is changed, ie just before NIinter*/
|
||||
extern int CLUinput(CKTcircuit *ckt);
|
||||
|
||||
/* call after each accepted timestep, ie CKTdump */
|
||||
extern int CLUoutput(CKTcircuit *ckt);
|
||||
|
||||
|
||||
/* the time step control */
|
||||
extern int CLUsync(double time,double *delta, int error);
|
||||
#endif
|
||||
|
|
@ -455,23 +455,8 @@ struct IFfrontEnd {
|
|||
/* start pointwise output plot */
|
||||
int (*OUTpData) (runDesc *, IFvalue *, IFvalue *);
|
||||
/* data for pointwise plot */
|
||||
int (*OUTwBeginPlot) (CKTcircuit *, JOB *,
|
||||
IFuid,
|
||||
IFuid, int,
|
||||
int, IFuid *, int, runDesc **);
|
||||
/* start windowed output plot */
|
||||
int (*OUTwReference) (runDesc *, IFvalue *, void **);
|
||||
/* independent vector for windowed plot */
|
||||
int (*OUTwData) (runDesc *, int, IFvalue *, void *);
|
||||
/* data for windowed plot */
|
||||
int (*OUTwEnd) (runDesc *);
|
||||
/* signal end of windows */
|
||||
int (*OUTendPlot) (runDesc *);
|
||||
/* end of plot */
|
||||
int (*OUTbeginDomain) (runDesc *, IFuid, int, IFvalue *);
|
||||
/* start nested domain */
|
||||
int (*OUTendDomain) (runDesc *);
|
||||
/* end nested domain */
|
||||
int (*OUTattributes) (runDesc *, IFuid, int, IFvalue *);
|
||||
/* specify output attributes of node */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -497,6 +497,19 @@ int ngSpice_nospinit(void);
|
|||
IMPEXP
|
||||
int ngSpice_nospiceinit(void);
|
||||
|
||||
/* Locking and unlocking the realloc of output vectors during simulation. May be set
|
||||
during reading output vectors in the primary thread, while the simulation in the
|
||||
background thread is moving on. */
|
||||
IMPEXP
|
||||
int ngSpice_LockRealloc(void);
|
||||
|
||||
IMPEXP
|
||||
int ngSpice_UnlockRealloc(void);
|
||||
|
||||
/* Reset ngspice as far as possible. */
|
||||
IMPEXP
|
||||
int ngSpice_Reset(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
15
src/main.c
15
src/main.c
|
|
@ -200,11 +200,8 @@ struct comm *cp_coms = spcp_coms;
|
|||
|
||||
extern int OUTpBeginPlot(CKTcircuit *, JOB *, IFuid, IFuid, int, int, IFuid *, int, runDesc **);
|
||||
extern int OUTpData(runDesc *, IFvalue *, IFvalue *);
|
||||
extern int OUTwBeginPlot(CKTcircuit *, JOB *, IFuid, IFuid, int, int, IFuid *, int, runDesc **);
|
||||
extern int OUTwReference(runDesc *, IFvalue *, void **);
|
||||
extern int OUTwData(runDesc *, int, IFvalue *, void *), OUTwEnd(runDesc *), OUTendPlot(runDesc *);
|
||||
extern int OUTbeginDomain(runDesc *, IFuid, int, IFvalue *);
|
||||
extern int OUTendDomain(runDesc *), OUTstopnow(void);
|
||||
extern int OUTendPlot(runDesc *);
|
||||
extern int OUTstopnow(void);
|
||||
extern void OUTerror(int, char *, IFuid *);
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
|
@ -224,13 +221,7 @@ IFfrontEnd nutmeginfo = {
|
|||
OUTerrorf,
|
||||
OUTpBeginPlot,
|
||||
OUTpData,
|
||||
OUTwBeginPlot,
|
||||
OUTwReference,
|
||||
OUTwData,
|
||||
OUTwEnd,
|
||||
OUTendPlot,
|
||||
OUTbeginDomain,
|
||||
OUTendDomain,
|
||||
OUTattributes
|
||||
};
|
||||
|
||||
|
|
@ -1397,7 +1388,7 @@ int main(int argc, char **argv)
|
|||
tpf = smktemp("sp");
|
||||
tempfile = fopen(tpf, "w+bTD");
|
||||
if (tempfile == NULL) {
|
||||
fprintf(stderr, "Could not open a temporary file "
|
||||
fprintf(stderr, "Error: Could not open a temporary file "
|
||||
"to save and use optional arguments.\n");
|
||||
sp_shutdown(EXIT_BAD);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,13 +258,7 @@ IFfrontEnd nutmeginfo = {
|
|||
OUTerrorf,
|
||||
OUTpBeginPlot,
|
||||
OUTpData,
|
||||
OUTwBeginPlot,
|
||||
OUTwReference,
|
||||
OUTwData,
|
||||
OUTwEnd,
|
||||
OUTendPlot,
|
||||
OUTbeginDomain,
|
||||
OUTendDomain,
|
||||
OUTattributes
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -98,8 +98,7 @@ libckt_la_SOURCES = \
|
|||
tfsetp.c \
|
||||
tranaskq.c \
|
||||
traninit.c \
|
||||
transetp.c \
|
||||
cluster.c
|
||||
transetp.c
|
||||
|
||||
|
||||
if PSS_WANTED
|
||||
|
|
|
|||
|
|
@ -62,16 +62,9 @@ ACan(CKTcircuit* ckt, int restart)
|
|||
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */
|
||||
|
||||
/* Tell the beginPlot routine what mode we're in */
|
||||
g_ipc.anal_type = IPC_ANAL_AC;
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_DC;
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
/* start at beginning */
|
||||
|
|
@ -152,40 +145,6 @@ ACan(CKTcircuit* ckt, int restart)
|
|||
else
|
||||
fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n");
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
||||
|
||||
/* Send the operating point results for Mspice compatibility */
|
||||
if (g_ipc.enabled)
|
||||
{
|
||||
/* Call CKTnames to get names of nodes/branches used by
|
||||
BeginPlot */
|
||||
/* Probably should free nameList after this block since
|
||||
called again... */
|
||||
error = CKTnames(ckt, &numNames, &nameList);
|
||||
if (error) return(error);
|
||||
|
||||
/* We have to do a beginPlot here since the data to return is
|
||||
* different for the DCOP than it is for the AC analysis.
|
||||
* Moreover the begin plot has not even been done yet at this
|
||||
* point...
|
||||
*/
|
||||
SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob,
|
||||
ckt->CKTcurJob->JOBname,
|
||||
NULL, IF_REAL,
|
||||
numNames, nameList, IF_REAL,
|
||||
&acPlot);
|
||||
txfree(nameList);
|
||||
|
||||
ipc_send_dcop_prefix();
|
||||
CKTdump(ckt, 0.0, acPlot);
|
||||
ipc_send_dcop_suffix();
|
||||
|
||||
SPfrontEnd->OUTendPlot(acPlot);
|
||||
}
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
|
||||
error = CKTload(ckt);
|
||||
if (error) return(error);
|
||||
|
|
@ -376,21 +335,8 @@ ACan(CKTcircuit* ckt, int restart)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
||||
|
||||
if (g_ipc.enabled)
|
||||
ipc_send_data_prefix(freq);
|
||||
|
||||
error = CKTacDump(ckt, freq, acPlot);
|
||||
|
||||
if (g_ipc.enabled)
|
||||
ipc_send_data_suffix();
|
||||
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
||||
#else
|
||||
error = CKTacDump(ckt, freq, acPlot);
|
||||
#endif
|
||||
if (error) {
|
||||
UPDATE_STATS(DOING_AC);
|
||||
return(error);
|
||||
|
|
|
|||
|
|
@ -157,51 +157,15 @@ CKTdoJob(CKTcircuit* ckt, int reset, TSKtask* task)
|
|||
if (!error)
|
||||
error = CKTunsetup(ckt);
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */
|
||||
if (error) g_ipc.syntax_error = IPC_TRUE;
|
||||
/* gtri - end - 12/12/90 */
|
||||
#endif
|
||||
|
||||
if (!error)
|
||||
error = CKTsetup(ckt);
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */
|
||||
if (error) g_ipc.syntax_error = IPC_TRUE;
|
||||
/* gtri - end - 12/12/90 */
|
||||
#endif
|
||||
|
||||
if (!error)
|
||||
error = CKTtemp(ckt);
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - 12/12/90 - wbk - set ipc syntax error flag */
|
||||
if (error) g_ipc.syntax_error = IPC_TRUE;
|
||||
/* gtri - end - 12/12/90 */
|
||||
#endif
|
||||
|
||||
if (error) {
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - 12/12/90 - wbk - return if syntax errors from parsing */
|
||||
if (g_ipc.enabled) {
|
||||
if (g_ipc.syntax_error)
|
||||
;
|
||||
else {
|
||||
/* else, send (GO) errchk status if we got this far */
|
||||
/* Caller is responsible for sending NOGO status if we returned earlier */
|
||||
ipc_send_errchk();
|
||||
}
|
||||
}
|
||||
/* gtri - end - 12/12/90 */
|
||||
#endif
|
||||
|
||||
|
||||
return error;
|
||||
|
||||
|
||||
}/* if error */
|
||||
}
|
||||
}
|
||||
|
||||
error2 = OK;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ Author: 1985 Thomas L. Quarles
|
|||
#ifdef USE_OMP
|
||||
#include <omp.h>
|
||||
#include "ngspice/cpextern.h"
|
||||
int nthreads;
|
||||
#endif
|
||||
|
||||
#define CKALLOC(var,size,type) \
|
||||
|
|
@ -36,7 +35,9 @@ CKTsetup(CKTcircuit *ckt)
|
|||
{
|
||||
int i;
|
||||
int error;
|
||||
|
||||
#ifdef USE_OMP
|
||||
int nthreads = 2;
|
||||
#endif
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - Setup for adding rshunt option resistors */
|
||||
CKTnode *node;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,9 @@ CKTterr(int qcap, CKTcircuit *ckt, double *timeStep)
|
|||
del = ckt->CKTtrtol * tol/MAX(ckt->CKTabstol,factor * fabs(diff[0]));
|
||||
if(ckt->CKTorder == 2) {
|
||||
del = sqrt(del);
|
||||
} else if (ckt->CKTorder > 2) {
|
||||
} else if (ckt->CKTorder == 3) {
|
||||
del = cbrt(del);
|
||||
} else if (ckt->CKTorder > 3) {
|
||||
del = exp(log(del)/ckt->CKTorder);
|
||||
}
|
||||
*timeStep = MIN(*timeStep,del);
|
||||
|
|
|
|||
|
|
@ -1,426 +0,0 @@
|
|||
/* Spice hooks */
|
||||
#include "ngspice/ngspice.h"
|
||||
#ifdef CLUSTER
|
||||
#include "ngspice/inpdefs.h"
|
||||
#include "ngspice/cluster.h"
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "ngspice/gendefs.h"
|
||||
|
||||
/* Misc stuff */
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
|
||||
/*Network stuff*/
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
struct input_pipe {
|
||||
/*the names of the local and remote nodes*/
|
||||
char remote[32];
|
||||
char local[32];
|
||||
int fd;
|
||||
FILE *stream;
|
||||
/* the data recieved */
|
||||
double time;
|
||||
double data;
|
||||
/*resistance of this link*/
|
||||
double res;
|
||||
/* The value controled */
|
||||
double *currentPtr;
|
||||
/*The output it is linked to*/
|
||||
struct output_pipe *link;
|
||||
struct input_pipe *next;
|
||||
};
|
||||
|
||||
struct output_pipe {
|
||||
int fd;
|
||||
FILE *stream;
|
||||
/*the names of the local and remote nodes*/
|
||||
char local[32];
|
||||
char remote[32];
|
||||
/* The index of the local node value in the ckt->CKTrhsOld array */
|
||||
int outIndex;
|
||||
/*Last values sent*/
|
||||
double time,data;
|
||||
struct input_pipe *link;
|
||||
struct output_pipe *next;
|
||||
};
|
||||
|
||||
static double lastTimeSent=0;
|
||||
|
||||
static int time_sock=0;
|
||||
static FILE *time_outfile=NULL;
|
||||
static FILE *time_infile=NULL;
|
||||
|
||||
static struct input_pipe* input_pipes=NULL;
|
||||
static struct output_pipe* output_pipes=NULL;
|
||||
|
||||
/* sets up deamon which waits for connections
|
||||
*and sets up input pipes as it recieves them */
|
||||
static void *start_listener(void *);
|
||||
|
||||
/* Setup the output pipes*/
|
||||
static int setup_output(CKTcircuit *ckt);
|
||||
static int setup_input(CKTcircuit *ckt);
|
||||
static int setup_time();
|
||||
|
||||
int CLUsetup(CKTcircuit *ckt){
|
||||
pthread_t tid;
|
||||
struct input_pipe *curr;
|
||||
int i, connections=0;
|
||||
GENmodel *mod;
|
||||
GENinstance *inst;
|
||||
|
||||
/* count the number of connections expected */
|
||||
i = INPtypelook("Isource");
|
||||
for(mod = ckt->CKThead[i];
|
||||
mod != NULL;
|
||||
mod = mod->GENnextModel)
|
||||
for (inst = mod->GENinstances;
|
||||
inst != NULL;
|
||||
inst = inst->GENnextInstance)
|
||||
if(strncmp("ipcx",inst->GENname,4) == 0)
|
||||
connections++;
|
||||
|
||||
/* allocate the input connections */
|
||||
for(i=0;i<connections;i++) {
|
||||
curr = TMALLOC(struct input_pipe, 1);
|
||||
if(input_pipes)
|
||||
curr->next = input_pipes;
|
||||
else
|
||||
curr->next = NULL;
|
||||
input_pipes = curr;
|
||||
}
|
||||
|
||||
pthread_create(&tid,NULL,start_listener,(void *)&connections);
|
||||
setup_output(ckt);
|
||||
pthread_join(tid,NULL);
|
||||
setup_input(ckt);
|
||||
setup_time();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "../devices/isrc/isrcdefs.h"
|
||||
/*Connect to remote machine and find the data*/
|
||||
static int setup_output(CKTcircuit *ckt){
|
||||
int type;
|
||||
GENmodel *mod;
|
||||
GENinstance *inst;
|
||||
char hostname[64];
|
||||
|
||||
lastTimeSent = 0;
|
||||
type = INPtypelook("Isource");
|
||||
|
||||
for(mod = ckt->CKThead[type];
|
||||
mod != NULL;
|
||||
mod = mod->GENnextModel)
|
||||
|
||||
for (inst = mod->GENinstances;
|
||||
inst != NULL;
|
||||
inst = inst->GENnextInstance)
|
||||
|
||||
if(strncmp("ipcx",inst->GENname,4) == 0){
|
||||
ISRCinstance *isrc = (ISRCinstance *)inst;
|
||||
CKTnode *node;
|
||||
struct output_pipe *curr;
|
||||
struct sockaddr_in address;
|
||||
struct hostent *host=NULL;
|
||||
int sock,nodeNum,i;
|
||||
|
||||
/*Create the struct*/
|
||||
curr = TMALLOC(struct output_pipe, 1);
|
||||
if(output_pipes)
|
||||
curr->next = output_pipes;
|
||||
else
|
||||
curr->next = NULL;
|
||||
output_pipes = curr;
|
||||
|
||||
/* The node names */
|
||||
strcpy(curr->local,CKTnodName(ckt,isrc->ISRCnegNode));/*weird*/
|
||||
strcpy(curr->remote,isrc->ISRCname);
|
||||
|
||||
/* extract remote node number */
|
||||
nodeNum = /*Xcoord*/(curr->remote[4] - '0') * CLUSTER_WIDTH
|
||||
+ /*Ycoord*/(curr->remote[9] - '0');
|
||||
sprintf(hostname,"n%d."DOMAIN_NAME,nodeNum);
|
||||
|
||||
/* network stuff */
|
||||
host = gethostbyname(hostname);
|
||||
if(!host){
|
||||
printf("Host not found in setup_output\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){
|
||||
printf("Socket open in setup_output\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(PORT);
|
||||
memcpy(&address.sin_addr,host->h_addr_list[0],
|
||||
sizeof(address.sin_addr));
|
||||
|
||||
printf("connecting to %s ...... ",hostname);
|
||||
fflush(stdout);
|
||||
|
||||
while(connect(sock,(struct sockaddr *)&address,sizeof(address))){
|
||||
usleep(500);/*wait for the sever to start*/
|
||||
}
|
||||
|
||||
printf("connected\n");
|
||||
|
||||
curr->fd = sock;
|
||||
|
||||
/* send stuff */
|
||||
/* buffer */
|
||||
i = (strlen(curr->remote) + strlen(curr->local) + 2)*sizeof(char);
|
||||
setsockopt(sock,SOL_SOCKET,SO_SNDBUF,&i,sizeof(i));
|
||||
|
||||
curr->stream = fdopen(curr->fd,"w");
|
||||
|
||||
fwrite(curr->remote,sizeof(char),strlen(curr->remote),curr->stream);
|
||||
fputc('\0',curr->stream);
|
||||
fwrite(curr->local,sizeof(char),strlen(curr->local),curr->stream);
|
||||
fputc('\0',curr->stream);
|
||||
fflush(curr->stream);
|
||||
|
||||
/* buffer, what is done per time point */
|
||||
i = sizeof(double)*2;
|
||||
setsockopt(sock,SOL_SOCKET,SO_SNDBUF,&i,sizeof(i));
|
||||
|
||||
/* find the index in ckt->rhsOld which contains the local node */
|
||||
i = 0;
|
||||
for(node = ckt->CKTnodes->next;node;node = node->next){
|
||||
i++;
|
||||
if(strcmp(node->name,curr->local)==0){
|
||||
curr->outIndex = i;
|
||||
goto next;
|
||||
}
|
||||
}
|
||||
printf("Local node %s not found\n",curr->local);
|
||||
exit(0);
|
||||
next:
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Processes the connections recieved by start_listener*/
|
||||
static int setup_input(CKTcircuit *ckt){
|
||||
int type;
|
||||
GENmodel *mod;
|
||||
GENinstance *inst;
|
||||
struct input_pipe *input;
|
||||
type = INPtypelook("Isource");
|
||||
|
||||
for(input = input_pipes;input;input = input->next){
|
||||
int i;
|
||||
|
||||
input->stream = fdopen(input->fd,"r");
|
||||
|
||||
/*Get the local and remote node names*/
|
||||
i=0;
|
||||
do {
|
||||
while(fread(&input->local[i],sizeof(char),1,input->stream) != 1);
|
||||
}while(input->local[i++] != '\0');
|
||||
|
||||
i=0;
|
||||
do {
|
||||
while(fread(&input->remote[i],sizeof(char),1,input->stream) != 1);
|
||||
}while(input->remote[i++] != '\0');
|
||||
|
||||
/* initilise */
|
||||
input->time = -1;
|
||||
|
||||
/*Find the Isource to control*/
|
||||
for(mod = ckt->CKThead[type];
|
||||
mod != NULL;
|
||||
mod = mod->GENnextModel)
|
||||
|
||||
for (inst = mod->GENinstances;
|
||||
inst != NULL;
|
||||
inst = inst->GENnextInstance)
|
||||
|
||||
if(strcmp(input->remote,&inst->GENname[11]) == 0){
|
||||
|
||||
ISRCinstance *isrc = (ISRCinstance *)inst;
|
||||
input->res = isrc->ISRCdcValue;
|
||||
isrc->ISRCdcValue = 0;
|
||||
input->currentPtr = &isrc->ISRCdcValue;
|
||||
goto next;
|
||||
}
|
||||
/* We get here if no Isource matches */
|
||||
printf("Current source %s not found\n",input->remote);
|
||||
exit(0);
|
||||
|
||||
next:
|
||||
|
||||
/* Now find the corresponding output */
|
||||
{
|
||||
struct output_pipe *output;
|
||||
for(output = output_pipes;output;output = output->next)
|
||||
if(strcmp(&input->local[11],output->local)==0){
|
||||
input->link = output;
|
||||
output->link = input;
|
||||
goto next2;
|
||||
}
|
||||
printf("Parent to %s not found\n",&input->local[11]);
|
||||
exit(0);
|
||||
next2:
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This starts a server and waits for connections, number given by argument*/
|
||||
static void *start_listener(void *v){
|
||||
int *connections = (int *)v;
|
||||
int count=0;
|
||||
struct sockaddr_in address;
|
||||
int sock, conn,i;
|
||||
size_t addrLength = sizeof(struct sockaddr_in);
|
||||
struct input_pipe *curr;
|
||||
|
||||
if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){
|
||||
printf("socket in start_listener\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Allow reuse of the socket */
|
||||
i = 1;
|
||||
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
|
||||
|
||||
/* port, inferface ..*/
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(PORT);
|
||||
memset(&address.sin_addr,0,sizeof(address.sin_addr));
|
||||
|
||||
if(bind(sock, (struct sockaddr *)&address,sizeof(address))){
|
||||
printf("bind in start_listener\n");
|
||||
exit(0);
|
||||
}
|
||||
if(listen(sock,5)){
|
||||
printf("listen in start_listener\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Loop till recieved all connections */
|
||||
curr = input_pipes;
|
||||
while (count < *connections){
|
||||
if((conn = accept(sock, (struct sockaddr *)&address,&addrLength)) < 0){
|
||||
printf("accept in start_listener\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
curr->fd = conn;
|
||||
/* will fill rest of structure later in setup_input*/
|
||||
count ++;
|
||||
curr = curr->next;
|
||||
}
|
||||
|
||||
close(sock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*Writes data to remote computer*/
|
||||
int CLUoutput(CKTcircuit *ckt){
|
||||
struct output_pipe *output;
|
||||
lastTimeSent = ckt->CKTtime;
|
||||
for(output = output_pipes;
|
||||
output;
|
||||
output = output->next){
|
||||
output->time = ckt->CKTtime;
|
||||
output->data = ckt->CKTrhsOld[output->outIndex];
|
||||
fwrite(&output->time,sizeof(double),1,output->stream);
|
||||
fwrite(&output->data,
|
||||
sizeof(double),1,output->stream);
|
||||
fflush(output->stream);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*Maniputates the local circuit based on the links*/
|
||||
int CLUinput(CKTcircuit *ckt){
|
||||
struct input_pipe *input;
|
||||
double tmp;
|
||||
for(input= input_pipes;input;input = input->next){
|
||||
/*recieve data till we get a good time point*/
|
||||
while (input->time < lastTimeSent){
|
||||
while(fread(&input->time, sizeof(double), 1, input->stream) != 1){}
|
||||
while(fread(&input->data, sizeof(double), 1, input->stream) != 1){}
|
||||
}
|
||||
tmp = (input->link->data - input->data) / input->res;
|
||||
|
||||
/*dampen out large currents*/
|
||||
if(tmp > 0)
|
||||
*input->currentPtr = 0.2 * (1 - exp(-tmp/0.2));
|
||||
else
|
||||
*input->currentPtr = -0.2 * (1 - exp(tmp/0.2));
|
||||
|
||||
/*GND is the posNode, local node is the negNode*/
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_time(){
|
||||
struct sockaddr_in address;
|
||||
struct hostent *host=NULL;
|
||||
char *hostname = TIME_HOST;
|
||||
int sock,i;
|
||||
|
||||
/* network stuff */
|
||||
host = gethostbyname(hostname);
|
||||
if(!host){
|
||||
printf("Host not found in setup_time\n");
|
||||
exit(0);
|
||||
}
|
||||
if((sock = socket(PF_INET,SOCK_STREAM,0)) < 0){
|
||||
printf("Socket open in setup_time\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
i = sizeof(double)*2;
|
||||
setsockopt(sock,SOL_SOCKET,SO_SNDBUF ,&i,sizeof(i));
|
||||
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(TIME_PORT);
|
||||
memcpy(&address.sin_addr,host->h_addr_list[0],
|
||||
sizeof(address.sin_addr));
|
||||
|
||||
|
||||
while(connect(sock,(struct sockaddr *)&address,sizeof(address))){
|
||||
usleep(500);/*wait for the sever to start*/
|
||||
}
|
||||
time_sock=sock;
|
||||
time_outfile=fdopen(sock,"w");
|
||||
time_infile=fdopen(sock,"r");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CLUsync(double time,double *delta, int error){
|
||||
double tmp;
|
||||
if(error)
|
||||
tmp = *delta * (-1);
|
||||
else
|
||||
tmp = *delta;
|
||||
fwrite(&time,sizeof(double),1,time_outfile);
|
||||
fwrite(&tmp,sizeof(double),1,time_outfile);
|
||||
fflush(time_outfile);
|
||||
while(fread(&tmp,sizeof(double),1,time_infile) != 1);
|
||||
if(tmp < 0){
|
||||
*delta = -tmp;
|
||||
return 0;
|
||||
} else {
|
||||
*delta = tmp;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -35,18 +35,13 @@ DCop(CKTcircuit *ckt, int notused)
|
|||
NG_IGNORE(notused);
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and initialize anal_init and anal_type */
|
||||
|
||||
/* Tell the beginPlot routine what mode we're in */
|
||||
g_ipc.anal_type = IPC_ANAL_DCOP;
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_DC;
|
||||
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
error = CKTnames(ckt,&numNames,&nameList);
|
||||
if(error) return(error);
|
||||
|
|
@ -114,31 +109,17 @@ DCop(CKTcircuit *ckt, int notused)
|
|||
|
||||
}
|
||||
#endif
|
||||
|
||||
converged = CKTload(ckt);
|
||||
#ifdef XSPICE
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC data delimiters */
|
||||
|
||||
if(g_ipc.enabled)
|
||||
ipc_send_dcop_prefix();
|
||||
|
||||
CKTdump(ckt, 0.0, plot);
|
||||
|
||||
if (ckt->CKTsoaCheck)
|
||||
error = CKTsoaCheck(ckt);
|
||||
|
||||
if(g_ipc.enabled)
|
||||
ipc_send_dcop_suffix();
|
||||
|
||||
/* gtri - end - wbk */
|
||||
#else
|
||||
if(converged == 0) {
|
||||
CKTdump(ckt, 0.0, plot);
|
||||
if (ckt->CKTsoaCheck)
|
||||
error = CKTsoaCheck(ckt);
|
||||
} else {
|
||||
fprintf(stderr,"error: circuit reload failed.\n");
|
||||
}
|
||||
#endif
|
||||
CKTdump(ckt, 0.0, plot);
|
||||
if (ckt->CKTsoaCheck)
|
||||
error = CKTsoaCheck(ckt);
|
||||
} else {
|
||||
fprintf(stderr,"error: circuit reload failed.\n");
|
||||
}
|
||||
|
||||
SPfrontEnd->OUTendPlot (plot);
|
||||
return(converged);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
/* gtri - end - wbk - Add headers */
|
||||
#endif
|
||||
|
||||
#ifdef CLUSTER
|
||||
#include "ngspice/cluster.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define INIT_STATS() \
|
||||
do { \
|
||||
startTime = SPfrontEnd->IFseconds(); \
|
||||
|
|
@ -89,18 +84,6 @@ DCpss(CKTcircuit *ckt,
|
|||
|
||||
int ltra_num;
|
||||
CKTnode *node;
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
||||
Ipc_Boolean_t ipc_firsttime = IPC_TRUE;
|
||||
Ipc_Boolean_t ipc_secondtime = IPC_FALSE;
|
||||
Ipc_Boolean_t ipc_delta_cut = IPC_FALSE;
|
||||
double ipc_last_time = 0.0;
|
||||
double ipc_last_delta = 0.0;
|
||||
/* gtri - end - wbk - 12/19/90 - Add IPC stuff */
|
||||
#endif
|
||||
#ifdef CLUSTER
|
||||
int redostep;
|
||||
#endif
|
||||
|
||||
/* New variables */
|
||||
int j, oscnNode;
|
||||
|
|
@ -224,15 +207,12 @@ DCpss(CKTcircuit *ckt,
|
|||
#endif
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and set anal_init and anal_type */
|
||||
/* Tell the beginPlot routine what mode we're in */
|
||||
g_ipc.anal_type = IPC_ANAL_TRAN;
|
||||
/* set anal_init and anal_type */
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_DC;
|
||||
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
/* Time Domain plot start and prepared to be filled in later */
|
||||
|
|
@ -306,35 +286,18 @@ DCpss(CKTcircuit *ckt,
|
|||
#endif
|
||||
|
||||
/* If no convergence reached - NO valid Operating Point */
|
||||
if(converged != 0) return(converged);
|
||||
if(converged != 0)
|
||||
return(converged);
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
||||
|
||||
/* Send the operating point results for Mspice compatibility */
|
||||
if(g_ipc.enabled) {
|
||||
ipc_send_dcop_prefix();
|
||||
CKTdump(ckt, 0.0, job->PSSplot_td);
|
||||
ipc_send_dcop_suffix();
|
||||
}
|
||||
|
||||
/* gtri - end - wbk */
|
||||
|
||||
/* gtri - add - wbk - 12/19/90 - set anal_init and anal_type */
|
||||
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_TRAN;
|
||||
|
||||
/* gtri - end - wbk */
|
||||
|
||||
/* gtri - begin - wbk - Add Breakpoint stuff */
|
||||
|
||||
/* Initialize the temporary breakpoint variables to infinity */
|
||||
g_mif_info.breakpoint.current = HUGE_VAL;
|
||||
g_mif_info.breakpoint.last = HUGE_VAL;
|
||||
|
||||
/* gtri - end - wbk - Add Breakpoint stuff */
|
||||
#endif
|
||||
ckt->CKTstat->STATtimePts ++;
|
||||
|
||||
|
|
@ -365,9 +328,7 @@ DCpss(CKTcircuit *ckt,
|
|||
|
||||
/* Statistics Initialization using a macro at the beginning of this code */
|
||||
INIT_STATS();
|
||||
#ifdef CLUSTER
|
||||
CLUsetup(ckt);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
/* saj As traninit resets CKTmode */
|
||||
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITPRED;
|
||||
|
|
@ -444,56 +405,16 @@ DCpss(CKTcircuit *ckt,
|
|||
return(error);
|
||||
}
|
||||
#ifdef XSPICE
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
||||
|
||||
if ((g_ipc.enabled) || wantevtdata) {
|
||||
if (wantevtdata) {
|
||||
|
||||
if (pss_state == PSS)
|
||||
{
|
||||
/* Send event-driven results */
|
||||
EVTdump(ckt, IPC_ANAL_TRAN, 0.0);
|
||||
|
||||
/* Then follow with analog results... */
|
||||
|
||||
/* Test to see if delta was cut by a breakpoint, */
|
||||
/* a non-convergence, or a too large truncation error */
|
||||
if(ipc_firsttime)
|
||||
ipc_delta_cut = IPC_FALSE;
|
||||
else if(ckt->CKTtime < (ipc_last_time + (0.999 * ipc_last_delta)))
|
||||
ipc_delta_cut = IPC_TRUE;
|
||||
else
|
||||
ipc_delta_cut = IPC_FALSE;
|
||||
|
||||
/* Record the data required to check for delta cuts */
|
||||
ipc_last_time = ckt->CKTtime;
|
||||
ipc_last_delta = MIN(ckt->CKTdelta, ckt->CKTmaxStep);
|
||||
|
||||
/* Send results data if time since last dump is greater */
|
||||
/* than 'mintime', or if first or second timepoints, */
|
||||
/* or if delta was cut */
|
||||
if( (ckt->CKTtime >= (g_ipc.mintime + g_ipc.last_time)) ||
|
||||
ipc_firsttime || ipc_secondtime || ipc_delta_cut ) {
|
||||
|
||||
ipc_send_data_prefix(ckt->CKTtime);
|
||||
CKTdump(ckt, ckt->CKTtime, job->PSSplot_td);
|
||||
ipc_send_data_suffix();
|
||||
|
||||
if(ipc_firsttime) {
|
||||
ipc_firsttime = IPC_FALSE;
|
||||
ipc_secondtime = IPC_TRUE;
|
||||
} else if(ipc_secondtime) {
|
||||
ipc_secondtime = IPC_FALSE;
|
||||
}
|
||||
|
||||
g_ipc.last_time = ckt->CKTtime;
|
||||
}
|
||||
/* Send event-driven results */
|
||||
EVTdump(ckt, IPC_ANAL_TRAN, 0.0);
|
||||
}
|
||||
} else
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
||||
#endif
|
||||
#ifdef CLUSTER
|
||||
if (pss_state == PSS)
|
||||
CLUoutput(ckt);
|
||||
|
||||
#endif
|
||||
|
||||
if (pss_state == PSS)
|
||||
|
|
@ -1278,14 +1199,6 @@ resume:
|
|||
} /* end if there are event instances */
|
||||
|
||||
/* gtri - end - wbk - Do event solution */
|
||||
#else
|
||||
|
||||
#ifdef CLUSTER
|
||||
if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) {
|
||||
fprintf (stderr, "Sync error!\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif /* CLUSTER */
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1302,9 +1215,6 @@ resume:
|
|||
|
||||
/* 600 */
|
||||
for (;;) {
|
||||
#ifdef CLUSTER
|
||||
redostep = 1;
|
||||
#endif
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 4/17/91 - Fix Berkeley bug */
|
||||
/* This is needed here to allow CAPask to output currents */
|
||||
|
|
@ -1318,9 +1228,6 @@ resume:
|
|||
olddelta=ckt->CKTdelta;
|
||||
/* time abort? */
|
||||
ckt->CKTtime += ckt->CKTdelta;
|
||||
#ifdef CLUSTER
|
||||
CLUinput(ckt);
|
||||
#endif
|
||||
ckt->CKTdeltaOld[0]=ckt->CKTdelta;
|
||||
NIcomCof(ckt);
|
||||
#ifdef PREDICTOR
|
||||
|
|
@ -1384,10 +1291,8 @@ resume:
|
|||
fprintf (stderr, "pss_state: %d, converged: %d\n", pss_state, converged) ;
|
||||
#endif
|
||||
if(converged != 0) {
|
||||
#ifndef CLUSTER
|
||||
ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta;
|
||||
ckt->CKTstat->STATrejected ++;
|
||||
#endif
|
||||
ckt->CKTtime = ckt->CKTtime - ckt->CKTdelta;
|
||||
ckt->CKTstat->STATrejected++;
|
||||
ckt->CKTdelta = ckt->CKTdelta/8;
|
||||
#ifdef STEPDEBUG
|
||||
fprintf (stderr, "delta cut to %g for non-convergence\n", ckt->CKTdelta) ;
|
||||
|
|
@ -1419,14 +1324,9 @@ resume:
|
|||
} else {
|
||||
if (firsttime) {
|
||||
firsttime = 0;
|
||||
#ifndef CLUSTER
|
||||
goto nextTime; /* no check on
|
||||
* first time point
|
||||
*/
|
||||
#else
|
||||
redostep = 0;
|
||||
goto chkStep;
|
||||
#endif
|
||||
}
|
||||
newdelta = ckt->CKTdelta;
|
||||
error = CKTtrunc(ckt,&newdelta);
|
||||
|
|
@ -1467,18 +1367,13 @@ resume:
|
|||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
#ifndef CLUSTER
|
||||
|
||||
/* go to 650 - trapezoidal */
|
||||
goto nextTime;
|
||||
#else
|
||||
redostep = 0;
|
||||
goto chkStep;
|
||||
#endif
|
||||
|
||||
} else { /* newdelta <= .9 * ckt->CKTdelta */
|
||||
#ifndef CLUSTER
|
||||
ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta;
|
||||
ckt->CKTstat->STATrejected ++;
|
||||
#endif
|
||||
ckt->CKTdelta = newdelta;
|
||||
#ifdef STEPDEBUG
|
||||
fprintf (stderr, "delta set to truncation error result:point rejected\n") ;
|
||||
|
|
@ -1505,15 +1400,6 @@ resume:
|
|||
EVTbackup(ckt, ckt->CKTtime + ckt->CKTdelta);
|
||||
|
||||
/* gtri - end - wbk - Do event backup */
|
||||
#endif
|
||||
#ifdef CLUSTER
|
||||
chkStep:
|
||||
if(CLUsync(ckt->CKTtime,&ckt->CKTdelta,redostep)){
|
||||
goto nextTime;
|
||||
} else {
|
||||
ckt->CKTtime -= olddelta;
|
||||
ckt->CKTstat->STATrejected ++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
|
|
|||
|
|
@ -5,8 +5,14 @@ Modified: 2000 AlansFixes
|
|||
Modified: 2023 XSPICE breakpoint fix for shared ngspice by Vyacheslav Shevchuk
|
||||
**********/
|
||||
|
||||
/* subroutine to do DC TRANSIENT analysis
|
||||
--- ONLY, unlike spice2 routine with the same name! */
|
||||
/* subroutine to do DC TRANSIENT analysis */
|
||||
|
||||
|
||||
/* line goto label:
|
||||
373 nextTime
|
||||
515 resume
|
||||
786 past_breakpoint
|
||||
985 chkStep */
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/cktdefs.h"
|
||||
|
|
@ -21,19 +27,12 @@ extern struct dbcomm *dbs;
|
|||
#include "ngspice/ftedebug.h"
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - Add headers */
|
||||
#include "ngspice/miftypes.h"
|
||||
|
||||
#include "ngspice/evt.h"
|
||||
#include "ngspice/enh.h"
|
||||
#include "ngspice/mif.h"
|
||||
#include "ngspice/evtproto.h"
|
||||
#include "ngspice/ipctiein.h"
|
||||
/* gtri - end - wbk - Add headers */
|
||||
#endif
|
||||
|
||||
#ifdef CLUSTER
|
||||
#include "ngspice/cluster.h"
|
||||
#endif
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
|
|
@ -100,37 +99,29 @@ DCtran(CKTcircuit *ckt,
|
|||
int ltra_num;
|
||||
CKTnode *node;
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
||||
Ipc_Boolean_t ipc_firsttime = IPC_TRUE;
|
||||
Ipc_Boolean_t ipc_secondtime = IPC_FALSE;
|
||||
Ipc_Boolean_t ipc_delta_cut = IPC_FALSE;
|
||||
double ipc_last_time = 0.0;
|
||||
double ipc_last_delta = 0.0;
|
||||
/* gtri - end - wbk - 12/19/90 - Add IPC stuff */
|
||||
|
||||
// Fix for sharedsync olddelta: When DCTran processes
|
||||
// either analog or XSPICE breakpoint, then it subtracts delta from
|
||||
// ckt->CKTtime. It sends 0 as olddelta after analog breakpoint
|
||||
// processing. Still, for XSPICE breakpoints it subtracts delta (see code
|
||||
// 'else if(g_mif_info.breakpoint.current < ckt->CKTtime)' branch) and
|
||||
// then sends non zero olddelta to sharedsync at the end of the function
|
||||
// (see chkStep: label). Thus olddelta is subtracted twice. Then
|
||||
// ckt->CKTtime becomes less than last_accepted_time.
|
||||
// xspice_breakpoints_processed 0:
|
||||
// XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime].
|
||||
// xspice_breakpoints_processed 1:
|
||||
// convergence criteria are satisfied but XSPICE breakpoint(s) is in the
|
||||
// time interval [last_accepted_time, CKTtime].
|
||||
/* xspice_breakpoints_processed 0:
|
||||
XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime].
|
||||
xspice_breakpoints_processed 1:
|
||||
convergence criteria are satisfied but XSPICE breakpoint(s) is in the
|
||||
time interval [last_accepted_time, CKTtime]. */
|
||||
int xspice_breakpoints_processed = 0;
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
double olddelta_for_shared_sync = 0.0;
|
||||
#endif // SHARED_MODULE
|
||||
#endif
|
||||
#if defined CLUSTER || defined SHARED_MODULE
|
||||
#endif
|
||||
#if defined SHARED_MODULE
|
||||
int redostep;
|
||||
#endif
|
||||
if(restart || ckt->CKTtime == 0) {
|
||||
/* dctran() is entered here upon starting transient simulation
|
||||
with time 0 and restart 1.
|
||||
ckt->CKTstep, CKTfinalTime, CKTinitTime, CKTmaxStep have been
|
||||
set already in fcn TRANinit() of traninit.c according to
|
||||
TSTEP TSTOP TSTART TMAX given on the .tran line. TMAX is set to TSTEP,
|
||||
if 'set nostepsizelimit' is not given in .spiceinit.*/
|
||||
|
||||
/* Set the first delta (step) time, typically depending on TSTEP */
|
||||
delta=MIN(ckt->CKTfinalTime/100,ckt->CKTstep)/10;
|
||||
|
||||
#ifdef STEPDEBUG
|
||||
|
|
@ -153,6 +144,8 @@ DCtran(CKTcircuit *ckt,
|
|||
ckt->CKTtimePoints = TMALLOC(double, ckt->CKTtimeListSize);
|
||||
/* end LTRA code addition */
|
||||
|
||||
/* Reset the breakpoint list.
|
||||
Add breakpoints at 0 time and TSTOP (final) time */
|
||||
if(ckt->CKTbreaks) FREE(ckt->CKTbreaks);
|
||||
ckt->CKTbreaks = TMALLOC(double, 2);
|
||||
if(ckt->CKTbreaks == NULL) return(E_NOMEM);
|
||||
|
|
@ -165,25 +158,23 @@ DCtran(CKTcircuit *ckt,
|
|||
#endif
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - 12/19/90 - Modify setting of CKTminBreak */
|
||||
/* Set to 10 times delmin for ATESSE 1 compatibity */
|
||||
if(ckt->CKTminBreak==0) ckt->CKTminBreak = 10.0 * ckt->CKTdelmin;
|
||||
/* gtri - end - wbk - 12/19/90 - Modify setting of CKTminBreak */
|
||||
/* Modify setting of CKTminBreak
|
||||
Set to 10 times delmin (minimum delta step time). */
|
||||
if(ckt->CKTminBreak == 0)
|
||||
ckt->CKTminBreak = 10.0 * ckt->CKTdelmin;
|
||||
|
||||
#else
|
||||
if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5;
|
||||
if(ckt->CKTminBreak == 0)
|
||||
ckt->CKTminBreak = ckt->CKTmaxStep * 5e-5;
|
||||
#endif
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and set anal_init and anal_type */
|
||||
/* Tell the beginPlot routine what mode we're in */
|
||||
g_ipc.anal_type = IPC_ANAL_TRAN;
|
||||
|
||||
/* set anal_init and anal_type */
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_DC;
|
||||
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
/* Scan ckt->CKTnodes and create list of node names */
|
||||
error = CKTnames(ckt,&numNames,&nameList);
|
||||
if(error) return(error);
|
||||
SPfrontEnd->IFnewUid (ckt, &timeUid, NULL, "time", UID_OTHER, NULL);
|
||||
|
|
@ -195,7 +186,7 @@ DCtran(CKTcircuit *ckt,
|
|||
tfree(nameList);
|
||||
if(error) return(error);
|
||||
|
||||
/* initialize CKTsoaCheck `warn' counters */
|
||||
/* initialize CKTsoaCheck 'warn' counters */
|
||||
if (ckt->CKTsoaCheck)
|
||||
error = CKTsoaInit();
|
||||
|
||||
|
|
@ -224,13 +215,12 @@ DCtran(CKTcircuit *ckt,
|
|||
}
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - set a breakpoint at end of supply ramping time */
|
||||
/* must do this after CKTtime set to 0 above */
|
||||
/* set a breakpoint at end of supply ramping time.
|
||||
Must do this after CKTtime is set to 0 above */
|
||||
if(ckt->enh->ramp.ramptime > 0.0)
|
||||
CKTsetBreak(ckt, ckt->enh->ramp.ramptime);
|
||||
/* gtri - end - wbk - set a breakpoint at end of supply ramping time */
|
||||
|
||||
/* gtri - begin - wbk - Call EVTop if event-driven instances exist */
|
||||
/* Call EVTop if event-driven instances exist */
|
||||
if(ckt->evt->counts.num_insts != 0) {
|
||||
/* use new DCOP algorithm */
|
||||
converged = EVTop(ckt,
|
||||
|
|
@ -241,20 +231,19 @@ DCtran(CKTcircuit *ckt,
|
|||
EVTdump(ckt, IPC_ANAL_DCOP, 0.0);
|
||||
|
||||
EVTop_save(ckt, MIF_FALSE, 0.0);
|
||||
|
||||
/* gtri - end - wbk - Call EVTop if event-driven instances exist */
|
||||
} else
|
||||
#endif
|
||||
/* Get operating point for analogue circuit */
|
||||
converged = CKTop(ckt,
|
||||
(ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITJCT,
|
||||
(ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITFLOAT,
|
||||
ckt->CKTdcMaxIter);
|
||||
|
||||
if(converged != 0) {
|
||||
fprintf(stdout,"\nTransient solution failed -\n");
|
||||
fprintf(stderr,"\nError: Finding the operating point for transient simulation failed \n");
|
||||
CKTncDump(ckt);
|
||||
fprintf(stdout,"\n");
|
||||
fflush(stdout);
|
||||
fprintf(stderr,"\n");
|
||||
fflush(stderr);
|
||||
} else if (ckt->CKTmode & MODEUIC && !ft_ngdebug) {
|
||||
fprintf(stdout,"Operating point simulation skipped by 'uic',\n");
|
||||
fprintf(stdout," now using transient initial conditions.\n");
|
||||
|
|
@ -273,45 +262,30 @@ DCtran(CKTcircuit *ckt,
|
|||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* return upon failure to converge during op */
|
||||
if (converged != 0) {
|
||||
SPfrontEnd->OUTendPlot(job->TRANplot);
|
||||
return(converged);
|
||||
}
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
||||
|
||||
/* Send the operating point results for Mspice compatibility */
|
||||
if(g_ipc.enabled) {
|
||||
ipc_send_dcop_prefix();
|
||||
CKTdump(ckt, 0.0, job->TRANplot);
|
||||
ipc_send_dcop_suffix();
|
||||
}
|
||||
|
||||
/* gtri - end - wbk */
|
||||
|
||||
/* gtri - add - wbk - 12/19/90 - set anal_init and anal_type */
|
||||
|
||||
/* set anal_init and anal_type */
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_TRAN;
|
||||
|
||||
/* gtri - end - wbk */
|
||||
|
||||
/* gtri - begin - wbk - Add Breakpoint stuff */
|
||||
|
||||
/* Breakpoint stuff */
|
||||
/* Initialize the temporary breakpoint variables to infinity */
|
||||
g_mif_info.breakpoint.current = 1.0e30;
|
||||
g_mif_info.breakpoint.last = 1.0e30;
|
||||
|
||||
/* gtri - end - wbk - Add Breakpoint stuff */
|
||||
#endif
|
||||
ckt->CKTstat->STATtimePts ++;
|
||||
ckt->CKTorder = 1;
|
||||
/* Initialze CKTdeltaOld with maximum value */
|
||||
for(i=0;i<7;i++) {
|
||||
ckt->CKTdeltaOld[i]=ckt->CKTmaxStep;
|
||||
}
|
||||
ckt->CKTdelta = delta;
|
||||
ckt->CKTdelta = delta; /* delta set in line 130 */
|
||||
#ifdef STEPDEBUG
|
||||
(void)printf("delta initialized to %g\n",ckt->CKTdelta);
|
||||
#endif
|
||||
|
|
@ -337,9 +311,9 @@ DCtran(CKTcircuit *ckt,
|
|||
ckt->CKTorder = save2;
|
||||
}
|
||||
#endif
|
||||
|
||||
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN;
|
||||
/* modeinittran set here */
|
||||
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN;
|
||||
/* Reset the gear variable coefficient matrix. */
|
||||
ckt->CKTag[0]=ckt->CKTag[1]=0;
|
||||
if (ckt->CKTstate1 && ckt->CKTstate0) {
|
||||
memcpy(ckt->CKTstate1, ckt->CKTstate0,
|
||||
|
|
@ -355,17 +329,17 @@ DCtran(CKTcircuit *ckt,
|
|||
#endif
|
||||
|
||||
INIT_STATS();
|
||||
#ifdef CLUSTER
|
||||
CLUsetup(ckt);
|
||||
#endif
|
||||
|
||||
/* End of (restart || ckt->CKTtime == 0) */
|
||||
} else {
|
||||
/* saj As traninit resets CKTmode */
|
||||
/* traninit resets CKTmode */
|
||||
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITPRED;
|
||||
/* saj */
|
||||
|
||||
INIT_STATS();
|
||||
if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5;
|
||||
if(ckt->CKTminBreak == 0)
|
||||
ckt->CKTminBreak = ckt->CKTmaxStep * 5e-5;
|
||||
firsttime=0;
|
||||
/* To get rawfile working saj*/
|
||||
/* To get rawfile working */
|
||||
error = SPfrontEnd->OUTpBeginPlot (NULL, NULL,
|
||||
NULL,
|
||||
NULL, 0,
|
||||
|
|
@ -375,11 +349,9 @@ DCtran(CKTcircuit *ckt,
|
|||
fprintf(stderr, "Couldn't relink rawfile\n");
|
||||
return error;
|
||||
}
|
||||
/* end saj*/
|
||||
goto resume;
|
||||
goto resume; /* line 515 */
|
||||
}
|
||||
|
||||
/* 650 */
|
||||
nextTime:
|
||||
|
||||
/* begin LTRA code addition */
|
||||
|
|
@ -401,7 +373,8 @@ DCtran(CKTcircuit *ckt,
|
|||
|
||||
error = CKTaccept(ckt);
|
||||
/* check if current breakpoint is outdated; if so, clear */
|
||||
if (ckt->CKTtime > ckt->CKTbreaks[0]) CKTclrBreak(ckt);
|
||||
if (ckt->CKTtime > ckt->CKTbreaks[0])
|
||||
CKTclrBreak(ckt);
|
||||
|
||||
if (ckt->CKTsoaCheck)
|
||||
error = CKTsoaCheck(ckt);
|
||||
|
|
@ -429,71 +402,30 @@ DCtran(CKTcircuit *ckt,
|
|||
UPDATE_STATS(DOING_TRAN);
|
||||
return(error);
|
||||
}
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
||||
|
||||
if ((g_ipc.enabled) || wantevtdata) {
|
||||
|
||||
/* Send evt data stuff in shared library */
|
||||
if (wantevtdata) {
|
||||
/* Send event-driven results */
|
||||
EVTdump(ckt, IPC_ANAL_TRAN, 0.0);
|
||||
|
||||
/* Then follow with analog results... */
|
||||
|
||||
/* Test to see if delta was cut by a breakpoint, */
|
||||
/* a non-convergence, or a too large truncation error */
|
||||
if(ipc_firsttime)
|
||||
ipc_delta_cut = IPC_FALSE;
|
||||
else if(ckt->CKTtime < (ipc_last_time + (0.999 * ipc_last_delta)))
|
||||
ipc_delta_cut = IPC_TRUE;
|
||||
else
|
||||
ipc_delta_cut = IPC_FALSE;
|
||||
|
||||
/* Record the data required to check for delta cuts */
|
||||
ipc_last_time = ckt->CKTtime;
|
||||
ipc_last_delta = MIN(ckt->CKTdelta, ckt->CKTmaxStep);
|
||||
|
||||
/* Send results data if time since last dump is greater */
|
||||
/* than 'mintime', or if first or second timepoints, */
|
||||
/* or if delta was cut */
|
||||
if( (ckt->CKTtime >= (g_ipc.mintime + g_ipc.last_time)) ||
|
||||
ipc_firsttime || ipc_secondtime || ipc_delta_cut ) {
|
||||
|
||||
if (wantevtdata)
|
||||
CKTdump(ckt, ckt->CKTtime, job->TRANplot);
|
||||
else {
|
||||
ipc_send_data_prefix(ckt->CKTtime);
|
||||
CKTdump(ckt, ckt->CKTtime, job->TRANplot);
|
||||
ipc_send_data_suffix();
|
||||
}
|
||||
|
||||
if(ipc_firsttime) {
|
||||
ipc_firsttime = IPC_FALSE;
|
||||
ipc_secondtime = IPC_TRUE;
|
||||
} else if(ipc_secondtime) {
|
||||
ipc_secondtime = IPC_FALSE;
|
||||
}
|
||||
|
||||
g_ipc.last_time = ckt->CKTtime;
|
||||
}
|
||||
} else
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
||||
}
|
||||
#endif
|
||||
#ifdef CLUSTER
|
||||
CLUoutput(ckt);
|
||||
#endif
|
||||
if((ckt->CKTmode&MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime)
|
||||
|| (!(ckt->CKTmode&MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime))
|
||||
CKTdump(ckt, ckt->CKTtime, job->TRANplot);
|
||||
|
||||
/* Output the data of the current accepted time point */
|
||||
if ((ckt->CKTmode & MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime)
|
||||
|| (!(ckt->CKTmode & MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) {
|
||||
CKTdump(ckt, ckt->CKTtime, job->TRANplot);
|
||||
}
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - Update event queues/data for accepted timepoint */
|
||||
/* Note: this must be done AFTER sending results to SI so it can't */
|
||||
/* go next to CKTaccept() above */
|
||||
/* Update event queues/data for accepted timepoint */
|
||||
/* Note: this must be done AFTER sending results to SI so it can't
|
||||
go next to CKTaccept() above */
|
||||
if(ckt->evt->counts.num_insts > 0)
|
||||
EVTaccept(ckt, ckt->CKTtime);
|
||||
/* gtri - end - wbk - Update event queues/data for accepted timepoint */
|
||||
#endif
|
||||
ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter;
|
||||
/* check for the end of the tran simulation, either by< stop time given,
|
||||
/* Check for the end of the tran simulation, either by stop time given,
|
||||
or final time has been reached. */
|
||||
if (have_autostop)
|
||||
/* time consuming autostop check only, when variable 'autostop' has been set
|
||||
|
|
@ -516,7 +448,7 @@ DCtran(CKTcircuit *ckt,
|
|||
if (flag_autostop)
|
||||
fprintf(stdout, "\nNote: Autostop after %e s, all measurement conditions are fulfilled.\n", ckt->CKTtime);
|
||||
|
||||
/* Final return from tran*/
|
||||
/* Final return from tran upon success */
|
||||
return(OK);
|
||||
}
|
||||
if(SPfrontEnd->IFpauseTest()) {
|
||||
|
|
@ -543,25 +475,21 @@ resume:
|
|||
else
|
||||
SetAnalyse( "tran", (int)((ckt->CKTtime * 1000.) / ckt->CKTfinalTime + 0.5));
|
||||
#endif
|
||||
ckt->CKTdelta =
|
||||
MIN(ckt->CKTdelta,ckt->CKTmaxStep);
|
||||
|
||||
ckt->CKTdelta = MIN(ckt->CKTdelta,ckt->CKTmaxStep);
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - Cut integration order if first timepoint after breakpoint */
|
||||
/* if(ckt->CKTtime == g_mif_info.breakpoint.last) */
|
||||
/* Cut integration order if first timepoint after breakpoint */
|
||||
if ( AlmostEqualUlps( ckt->CKTtime, g_mif_info.breakpoint.last, 100 ) )
|
||||
ckt->CKTorder = 1;
|
||||
/* gtri - end - wbk - Cut integration order if first timepoint after breakpoint */
|
||||
|
||||
#endif
|
||||
|
||||
/* are we at a breakpoint, or indistinguishably close? */
|
||||
/* if ((ckt->CKTtime == ckt->CKTbreaks[0]) || (ckt->CKTbreaks[0] - */
|
||||
/* Are we at a breakpoint, or indistinguishably close? */
|
||||
if ( AlmostEqualUlps( ckt->CKTtime, ckt->CKTbreaks[0], 100 ) ||
|
||||
ckt->CKTbreaks[0] - ckt->CKTtime <= ckt->CKTdelmin) {
|
||||
/* first timepoint after a breakpoint - cut integration order */
|
||||
/* and limit timestep to .1 times minimum of time to next breakpoint,
|
||||
* and previous timestep
|
||||
*/
|
||||
/* First timepoint after a breakpoint: cut integration order
|
||||
and limit timestep to .1 times minimum of time to next breakpoint,
|
||||
and previous timestep. */
|
||||
ckt->CKTorder = 1;
|
||||
#ifdef STEPDEBUG
|
||||
if( (ckt->CKTdelta > .1*ckt->CKTsaveDelta) ||
|
||||
|
|
@ -597,6 +525,7 @@ resume:
|
|||
}
|
||||
|
||||
#ifndef XSPICE
|
||||
/* Force the breakpoint if appropriate */
|
||||
else if(ckt->CKTtime + ckt->CKTdelta >= ckt->CKTbreaks[0]) {
|
||||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||
ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime;
|
||||
|
|
@ -606,15 +535,23 @@ resume:
|
|||
#endif
|
||||
ckt->CKTbreak = 1; /* why? the current pt. is not a bkpt. */
|
||||
}
|
||||
/* Try to equalise the last two time steps before the breakpoint,
|
||||
if the second step would be smaller than CKTdelta otherwise.*/
|
||||
else if (ckt->CKTtime + 1.9 * ckt->CKTdelta > ckt->CKTbreaks[0]) {
|
||||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||
ckt->CKTdelta = (ckt->CKTbreaks[0] - ckt->CKTtime) / 2.;
|
||||
#ifdef STEPDEBUG
|
||||
fprintf(stdout, "Delta equalising step at time %e with delta %e\n", ckt->CKTtime, ckt->CKTdelta);
|
||||
#endif
|
||||
}
|
||||
#endif /* !XSPICE */
|
||||
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - Add Breakpoint stuff */
|
||||
|
||||
/* More Breakpoint stuff */
|
||||
if(ckt->CKTtime + ckt->CKTdelta >= g_mif_info.breakpoint.current) {
|
||||
/* If next time > temporary breakpoint, force it to the breakpoint */
|
||||
/* And mark that timestep was set by temporary breakpoint */
|
||||
/* If next time > temporary breakpoint, force it to the breakpoint,
|
||||
and mark that timestep was set by temporary breakpoint */
|
||||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
||||
g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta;
|
||||
|
|
@ -623,12 +560,8 @@ resume:
|
|||
g_mif_info.breakpoint.last = 1.0e30;
|
||||
}
|
||||
|
||||
/* gtri - end - wbk - Add Breakpoint stuff */
|
||||
|
||||
/* gtri - begin - wbk - Modify Breakpoint stuff */
|
||||
/* Throw out any permanent breakpoint with time <= current time or in the
|
||||
* very near future, unless it the final stop break.
|
||||
*/
|
||||
very near future, unless it is the final stop break. */
|
||||
#ifdef STEPDEBUG
|
||||
printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n",
|
||||
ckt->CKTbreaks[0], ckt->CKTtime, ckt->CKTminBreak);
|
||||
|
|
@ -651,8 +584,15 @@ resume:
|
|||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||
ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime;
|
||||
}
|
||||
|
||||
/* gtri - end - wbk - Modify Breakpoint stuff */
|
||||
/* Try to equalise the last two time steps before the breakpoint,
|
||||
if the second step would be smaller than CKTdelta otherwise.*/
|
||||
else if (ckt->CKTtime + 1.9 * ckt->CKTdelta > ckt->CKTbreaks[0]) {
|
||||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||
ckt->CKTdelta = (ckt->CKTbreaks[0] - ckt->CKTtime) / 2.;
|
||||
#ifdef STEPDEBUG
|
||||
fprintf(stdout, "Delta equalising step at time %e with delta %e\n", ckt->CKTtime, ckt->CKTdelta);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
/* Either directly go to next time step, or modify ckt->CKTdelta depending on
|
||||
|
|
@ -661,17 +601,16 @@ resume:
|
|||
ckt->CKTdelmin, 0, &ckt->CKTstat->STATrejected, 0);
|
||||
#endif
|
||||
|
||||
/* gtri - begin - wbk - Do event solution */
|
||||
|
||||
/* Do event solution */
|
||||
if(ckt->evt->counts.num_insts > 0) {
|
||||
|
||||
/* if time = 0 and op_alternate was specified as false during */
|
||||
/* dcop analysis, call any changed instances to let them */
|
||||
/* post their outputs with their associated delays */
|
||||
/* If time = 0 and op_alternate was specified as false during
|
||||
dcop analysis, call any changed instances to let them
|
||||
post their outputs with their associated delays */
|
||||
if((ckt->CKTtime == 0.0) && (! ckt->evt->options.op_alternate))
|
||||
EVTiter(ckt);
|
||||
|
||||
/* while there are events on the queue with event time <= next */
|
||||
/* While there are events on the queue with event time <= next */
|
||||
/* projected analog time, process them */
|
||||
while((g_mif_info.circuit.evt_step = EVTnext_time(ckt))
|
||||
<= (ckt->CKTtime + ckt->CKTdelta)) {
|
||||
|
|
@ -683,14 +622,14 @@ resume:
|
|||
EVTdequeue(ckt, g_mif_info.circuit.evt_step);
|
||||
EVTiter(ckt);
|
||||
|
||||
/* If any instances have forced an earlier */
|
||||
/* next analog time, cut the delta */
|
||||
/* If any instances have forced an earlier
|
||||
next analog time, cut the delta */
|
||||
if(ckt->CKTbreaks[0] < g_mif_info.breakpoint.current)
|
||||
if(ckt->CKTbreaks[0] > ckt->CKTtime + ckt->CKTminBreak)
|
||||
g_mif_info.breakpoint.current = ckt->CKTbreaks[0];
|
||||
if(g_mif_info.breakpoint.current < ckt->CKTtime + ckt->CKTdelta) {
|
||||
/* Breakpoint must be > last accepted timepoint */
|
||||
/* and >= current event time */
|
||||
/* Breakpoint must be > last accepted timepoint
|
||||
and >= current event time */
|
||||
if(g_mif_info.breakpoint.current > ckt->CKTtime + ckt->CKTminBreak &&
|
||||
g_mif_info.breakpoint.current >= g_mif_info.circuit.evt_step) {
|
||||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||
|
|
@ -702,16 +641,8 @@ resume:
|
|||
} /* end while next event time <= next analog time */
|
||||
} /* end if there are event instances */
|
||||
|
||||
/* gtri - end - wbk - Do event solution */
|
||||
#else /* no XSPICE */
|
||||
|
||||
#ifdef CLUSTER
|
||||
if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) {
|
||||
printf("Sync error!\n");
|
||||
exit(0);
|
||||
}
|
||||
#endif /* CLUSTER */
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
/* Either directly go to next time step, or modify ckt->CKTdelta depending on
|
||||
synchronization requirements. sharedsync() returns 0.
|
||||
|
|
@ -733,26 +664,19 @@ resume:
|
|||
|
||||
/* 600 */
|
||||
for (;;) {
|
||||
#if defined CLUSTER || defined SHARED_MODULE
|
||||
#if defined SHARED_MODULE
|
||||
redostep = 1;
|
||||
#endif
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 4/17/91 - Fix Berkeley bug */
|
||||
/* This is needed here to allow CAPask to output currents */
|
||||
/* during Transient analysis. A grep for CKTcurrentAnalysis */
|
||||
/* indicates that it should not hurt anything else ... */
|
||||
|
||||
/* This is needed here to allow CAPask to output currents
|
||||
during Transient analysis. */
|
||||
ckt->CKTcurrentAnalysis = DOING_TRAN;
|
||||
|
||||
/* gtri - end - wbk - 4/17/91 - Fix Berkeley bug */
|
||||
xspice_breakpoints_processed = 0;
|
||||
#endif
|
||||
olddelta=ckt->CKTdelta;
|
||||
/* time abort? */
|
||||
ckt->CKTtime += ckt->CKTdelta;
|
||||
#ifdef CLUSTER
|
||||
CLUinput(ckt);
|
||||
#endif
|
||||
ckt->CKTdeltaOld[0]=ckt->CKTdelta;
|
||||
NIcomCof(ckt);
|
||||
#ifdef PREDICTOR
|
||||
|
|
@ -761,33 +685,25 @@ resume:
|
|||
save_mode = ckt->CKTmode;
|
||||
save_order = ckt->CKTorder;
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - Add Breakpoint stuff */
|
||||
|
||||
/* Initialize temporary breakpoint to infinity */
|
||||
g_mif_info.breakpoint.current = 1.0e30;
|
||||
|
||||
/* gtri - end - wbk - Add Breakpoint stuff */
|
||||
|
||||
|
||||
/* gtri - begin - wbk - add convergence problem reporting flags */
|
||||
/* Add convergence problem reporting flags */
|
||||
/* delta is forced to equal delmin on last attempt near line 650 */
|
||||
if(ckt->CKTdelta <= ckt->CKTdelmin)
|
||||
ckt->enh->conv_debug.last_NIiter_call = MIF_TRUE;
|
||||
else
|
||||
ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE;
|
||||
/* gtri - begin - wbk - add convergence problem reporting flags */
|
||||
|
||||
/* Call all hybrids */
|
||||
|
||||
/* gtri - begin - wbk - Call all hybrids */
|
||||
|
||||
/* gtri - begin - wbk - Set evt_step */
|
||||
|
||||
/* Set evt_step */
|
||||
if(ckt->evt->counts.num_insts > 0) {
|
||||
g_mif_info.circuit.evt_step = ckt->CKTtime;
|
||||
}
|
||||
/* gtri - end - wbk - Set evt_step */
|
||||
#endif
|
||||
|
||||
/* Central solver step */
|
||||
converged = NIiter(ckt,ckt->CKTtranMaxIter);
|
||||
|
||||
ckt->CKTstat->STATtimePts ++;
|
||||
|
|
@ -803,14 +719,14 @@ resume:
|
|||
return(converged);
|
||||
}
|
||||
|
||||
/* If no convergence in Central solver step */
|
||||
if(converged != 0) {
|
||||
#ifndef CLUSTER
|
||||
|
||||
#ifndef SHARED_MODULE
|
||||
ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta;
|
||||
ckt->CKTstat->STATrejected ++;
|
||||
#else
|
||||
redostep = 1;
|
||||
#endif
|
||||
#endif
|
||||
ckt->CKTdelta = ckt->CKTdelta/8;
|
||||
#ifdef STEPDEBUG
|
||||
|
|
@ -823,10 +739,12 @@ resume:
|
|||
ckt->CKTorder = 1;
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - Add Breakpoint stuff */
|
||||
|
||||
/* Add Breakpoint stuff */
|
||||
} else if(g_mif_info.breakpoint.current < ckt->CKTtime) {
|
||||
/* Force backup if temporary breakpoint is < current time */
|
||||
/* Force backup if temporary breakpoint is < current time:
|
||||
- save old delta
|
||||
- retract time by old delta
|
||||
- new delta by difference between by retracted time and breakpoint */
|
||||
|
||||
past_breakpoint:
|
||||
ckt->CKTsaveDelta = ckt->CKTdelta;
|
||||
|
|
@ -839,11 +757,13 @@ resume:
|
|||
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN;
|
||||
}
|
||||
ckt->CKTorder = 1;
|
||||
|
||||
/* gtri - end - wbk - Add Breakpoint stuff */
|
||||
#endif
|
||||
|
||||
} else {
|
||||
/* If converged:
|
||||
- go to next time step if this was the first time.
|
||||
- If not the first time step, don not accept, but check the truncation errors,
|
||||
and reduce delta accordingly, thenm redo the step, to bound the error. */
|
||||
if (firsttime) {
|
||||
#ifdef WANT_SENSE2
|
||||
if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){
|
||||
|
|
@ -860,16 +780,17 @@ resume:
|
|||
}
|
||||
#endif
|
||||
firsttime = 0;
|
||||
#if !defined CLUSTER && !defined SHARED_MODULE
|
||||
goto nextTime; /* no check on
|
||||
* first time point
|
||||
*/
|
||||
#if !defined SHARED_MODULE
|
||||
/* no check on first time point */
|
||||
goto nextTime; /* line 373 */
|
||||
#else
|
||||
redostep = 0;
|
||||
goto chkStep;
|
||||
goto chkStep; /* line 987 */
|
||||
#endif
|
||||
}
|
||||
newdelta = ckt->CKTdelta;
|
||||
/* Scan through all devices, estimate the truncation error,
|
||||
and reduce the time step, if necessary.*/
|
||||
error = CKTtrunc(ckt,&newdelta);
|
||||
if(error) {
|
||||
UPDATE_STATS(DOING_TRAN);
|
||||
|
|
@ -891,13 +812,12 @@ resume:
|
|||
EVTcall_hybrids(ckt);
|
||||
if (g_mif_info.breakpoint.current < ckt->CKTtime) {
|
||||
/* A hybrid requested a breakpoint in the past. */
|
||||
|
||||
goto past_breakpoint;
|
||||
goto past_breakpoint; /* line 786 */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { /* don't rise the order for backward Euler */
|
||||
/* don't raise the order for backward Euler */
|
||||
if ((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) {
|
||||
newdelta = ckt->CKTdelta;
|
||||
ckt->CKTorder = 2;
|
||||
error = CKTtrunc(ckt, &newdelta);
|
||||
|
|
@ -947,30 +867,33 @@ resume:
|
|||
}
|
||||
#endif
|
||||
|
||||
#if !defined CLUSTER && !defined SHARED_MODULE
|
||||
/* go to 650 - trapezoidal */
|
||||
goto nextTime;
|
||||
#if !defined SHARED_MODULE
|
||||
/* trapezoidal */
|
||||
goto nextTime; /* line 373 */
|
||||
#else
|
||||
redostep = 0;
|
||||
goto chkStep;
|
||||
goto chkStep; /* line 987 */
|
||||
#endif
|
||||
} else {
|
||||
#ifndef CLUSTER
|
||||
/* not (newdelta > .9 * ckt->CKTdelta): reject the step
|
||||
- redo the time
|
||||
- apply the new (reduced) delta */
|
||||
#ifndef SHARED_MODULE
|
||||
ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta;
|
||||
ckt->CKTstat->STATrejected ++;
|
||||
#else
|
||||
redostep = 1;
|
||||
#endif
|
||||
#endif
|
||||
ckt->CKTdelta = newdelta;
|
||||
#ifdef STEPDEBUG
|
||||
(void)printf(
|
||||
"delta set to truncation error result:point rejected\n");
|
||||
"delta set to truncation error result: point rejected\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the new delta to delmin (minimum delta allowed). However:
|
||||
If the new delta has been less than the minimum delta
|
||||
for the second time, bail out with 'Timestep too small'. */
|
||||
if (ckt->CKTdelta <= ckt->CKTdelmin) {
|
||||
if (olddelta > ckt->CKTdelmin) {
|
||||
ckt->CKTdelta = ckt->CKTdelmin;
|
||||
|
|
@ -983,23 +906,23 @@ resume:
|
|||
SPfrontEnd->OUTendPlot(job->TRANplot);
|
||||
job->TRANplot = NULL;
|
||||
UPDATE_STATS(0);
|
||||
/* return upon convergence failure */
|
||||
return(E_TIMESTEP);
|
||||
}
|
||||
}
|
||||
#ifdef XSPICE
|
||||
/* gtri - begin - wbk - Do event backup */
|
||||
|
||||
/* Do event backup */
|
||||
if(ckt->evt->counts.num_insts > 0) {
|
||||
#ifdef SHARED_MODULE
|
||||
double discard_start_time = ckt->CKTtime + ckt->CKTdelta;
|
||||
// ngspice in executable mode subtracts olddelta from the time
|
||||
// before new delta calculation, but it keeps delta in CKTtime and
|
||||
// postpones subtraction in library mode. Delayed subtraction leads
|
||||
// to incorrect points dropping because ckt->CKTdelta is almost always
|
||||
// less than olddelta if there are convergence issues, and EVTbackup
|
||||
// may drop valid events that need to be processed within
|
||||
// [last_accepted_time, last_accepted_time + ckt->CKTdelta] range
|
||||
// after delta adjustment.
|
||||
/* ngspice in executable mode subtracts olddelta from the time
|
||||
before new delta calculation, but it keeps delta in CKTtime and
|
||||
postpones subtraction in library mode. Delayed subtraction leads
|
||||
to incorrect points dropping because ckt->CKTdelta is almost always
|
||||
less than olddelta if there are convergence issues, and EVTbackup
|
||||
may drop valid events that need to be processed within
|
||||
[last_accepted_time, last_accepted_time + ckt->CKTdelta] range
|
||||
after delta adjustment. */
|
||||
if (redostep && xspice_breakpoints_processed == 0)
|
||||
discard_start_time -= olddelta;
|
||||
EVTbackup(ckt, discard_start_time);
|
||||
|
|
@ -1008,16 +931,6 @@ resume:
|
|||
#endif
|
||||
}
|
||||
|
||||
/* gtri - end - wbk - Do event backup */
|
||||
#endif
|
||||
#ifdef CLUSTER
|
||||
chkStep:
|
||||
if(CLUsync(ckt->CKTtime,&ckt->CKTdelta,redostep)){
|
||||
goto nextTime;
|
||||
} else {
|
||||
ckt->CKTtime -= olddelta;
|
||||
ckt->CKTstat->STATrejected ++;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
|
|
@ -1045,11 +958,11 @@ chkStep:
|
|||
olddelta_for_shared_sync = 0.0;
|
||||
if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta_for_shared_sync, ckt->CKTfinalTime,
|
||||
ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0)
|
||||
goto nextTime;
|
||||
goto nextTime; /* line 373 */
|
||||
#else
|
||||
if(sharedsync(&ckt->CKTtime, &ckt->CKTdelta, olddelta, ckt->CKTfinalTime,
|
||||
ckt->CKTdelmin, redostep, &ckt->CKTstat->STATrejected, 1) == 0)
|
||||
goto nextTime;
|
||||
goto nextTime; /* line 373 */
|
||||
#endif // XSPICE
|
||||
#endif // SHARED_MODULE
|
||||
|
||||
|
|
|
|||
|
|
@ -165,17 +165,12 @@ DCtrCurv(CKTcircuit *ckt, int restart)
|
|||
#endif
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */
|
||||
|
||||
/* Tell the beginPlot routine what mode we're in */
|
||||
g_ipc.anal_type = IPC_ANAL_DCTRCURVE;
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_DC;
|
||||
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
error = CKTnames(ckt, &numNames, &nameList);
|
||||
|
|
@ -383,18 +378,10 @@ DCtrCurv(CKTcircuit *ckt, int restart)
|
|||
ckt->CKTtime = ckt->CKTtemp - CONSTCtoK;
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
||||
|
||||
/* If first time through, call CKTdump to output Operating Point info */
|
||||
/* for Mspice compatibility */
|
||||
|
||||
if (((g_ipc.enabled) || wantevtdata) && firstTime) {
|
||||
ipc_send_dcop_prefix();
|
||||
if (wantevtdata && firstTime) {
|
||||
CKTdump(ckt, 0.0, plot);
|
||||
ipc_send_dcop_suffix();
|
||||
}
|
||||
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
#ifdef WANT_SENSE2
|
||||
|
|
@ -435,25 +422,11 @@ DCtrCurv(CKTcircuit *ckt, int restart)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC delimiters */
|
||||
|
||||
if (g_ipc.enabled)
|
||||
ipc_send_data_prefix(ckt->CKTtime);
|
||||
#endif
|
||||
|
||||
CKTdump(ckt,ckt->CKTtime,plot);
|
||||
|
||||
if (ckt->CKTsoaCheck)
|
||||
error = CKTsoaCheck(ckt);
|
||||
|
||||
#ifdef XSPICE
|
||||
if (g_ipc.enabled)
|
||||
ipc_send_data_suffix();
|
||||
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
if (firstTime) {
|
||||
firstTime = 0;
|
||||
if (ckt->CKTstate1 && ckt->CKTstate0) {
|
||||
|
|
|
|||
|
|
@ -65,16 +65,9 @@ NOISEan(CKTcircuit* ckt, int restart)
|
|||
runDesc* plot = NULL;
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */
|
||||
|
||||
/* Tell the beginPlot routine what mode we're in */
|
||||
g_ipc.anal_type = IPC_ANAL_NOI;
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_DC;
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
#ifdef KLU
|
||||
|
|
@ -189,19 +182,18 @@ NOISEan(CKTcircuit* ckt, int restart)
|
|||
EVTop_save(ckt, MIF_TRUE, 0.0);
|
||||
}
|
||||
else
|
||||
{ // start of no XSPICE event-driven instances
|
||||
#endif
|
||||
|
||||
{ // start of no XSPICE event-driven instances
|
||||
#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) ;
|
||||
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 ;
|
||||
}
|
||||
ckt->CKTmatrix->SMPkluMatrix->KLUmatrixIsComplex = KLUmatrixReal ;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If no event-driven instances, do what SPICE normally does */
|
||||
|
|
@ -220,43 +212,8 @@ NOISEan(CKTcircuit* ckt, int restart)
|
|||
else {
|
||||
fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n");
|
||||
}
|
||||
|
||||
#ifdef XSPICE
|
||||
} // end of no XSPICE event-driven instances
|
||||
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
||||
|
||||
/* Send the operating point results for Mspice compatibility */
|
||||
if (g_ipc.enabled)
|
||||
{
|
||||
/* Call CKTnames to get names of nodes/branches used by
|
||||
BeginPlot */
|
||||
/* Probably should free nameList after this block since
|
||||
called again... */
|
||||
error = CKTnames(ckt, &numNames, &nameList);
|
||||
if (error) return(error);
|
||||
|
||||
/* We have to do a beginPlot here since the data to return is
|
||||
* different for the DCOP than it is for the AC analysis.
|
||||
* Moreover the begin plot has not even been done yet at this
|
||||
* point...
|
||||
*/
|
||||
SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob,
|
||||
ckt->CKTcurJob->JOBname,
|
||||
NULL, IF_REAL,
|
||||
numNames, nameList, IF_REAL,
|
||||
&noiPlot);
|
||||
txfree(nameList);
|
||||
|
||||
ipc_send_dcop_prefix();
|
||||
CKTdump(ckt, 0.0, noiPlot);
|
||||
ipc_send_dcop_suffix();
|
||||
|
||||
SPfrontEnd->OUTendPlot(noiPlot);
|
||||
}
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
/* Patch to noisean.c by Richard D. McRoberts. */
|
||||
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
|
||||
error = CKTload(ckt);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ static bool nooptran = TRUE;
|
|||
we firstly fill the static vars opstepsize, opfinaltime,
|
||||
and opramptime. Later from inp.c we call com_optran again and set the
|
||||
data in ft_curckt->ci_defTask.
|
||||
|
||||
com_optran is called from cp_init() as 'optran 1 1 1 100n 10u 0'.
|
||||
*/
|
||||
void com_optran(wordlist* wl) {
|
||||
wordlist* wltmp = wl;
|
||||
|
|
@ -177,8 +179,10 @@ void com_optran(wordlist* wl) {
|
|||
goto bugquit;
|
||||
}
|
||||
/* optran deselected by setting opstepsize to 0 */
|
||||
if (opstepsize == 0)
|
||||
if (opstepsize == 0) {
|
||||
nooptran = TRUE;
|
||||
fprintf(stdout, "Note: Optran is deselected");
|
||||
}
|
||||
|
||||
dataset = TRUE;
|
||||
if (errno == 0)
|
||||
|
|
@ -311,8 +315,8 @@ OPtran(CKTcircuit *ckt, int oldconverged)
|
|||
int redostep;
|
||||
#endif
|
||||
|
||||
/* if optran command has not been given (in .spiceinit or in .control section),
|
||||
we don' use optran */
|
||||
/* if optran command with step size 0 has been set in in .spiceinit or in .control section,
|
||||
we don't use optran */
|
||||
if (nooptran)
|
||||
return oldconverged;
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -386,18 +386,9 @@ SPan(CKTcircuit* ckt, int restart)
|
|||
}
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */
|
||||
|
||||
/* Tell the beginPlot routine what mode we're in */
|
||||
|
||||
// For now, let's keep this as IPC_ANAL_AC (TBD)
|
||||
g_ipc.anal_type = IPC_ANAL_AC;
|
||||
|
||||
/* Tell the code models what mode we're in */
|
||||
g_mif_info.circuit.anal_type = MIF_DC;
|
||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
/* start at beginning */
|
||||
|
|
@ -475,40 +466,6 @@ SPan(CKTcircuit* ckt, int restart)
|
|||
else
|
||||
fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n");
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
||||
|
||||
/* Send the operating point results for Mspice compatibility */
|
||||
if (g_ipc.enabled)
|
||||
{
|
||||
/* Call CKTnames to get names of nodes/branches used by
|
||||
BeginPlot */
|
||||
/* Probably should free nameList after this block since
|
||||
called again... */
|
||||
error = CKTnames(ckt, &numNames, &nameList);
|
||||
if (error) return(error);
|
||||
|
||||
/* We have to do a beginPlot here since the data to return is
|
||||
* different for the DCOP than it is for the AC analysis.
|
||||
* Moreover the begin plot has not even been done yet at this
|
||||
* point...
|
||||
*/
|
||||
SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob,
|
||||
ckt->CKTcurJob->JOBname,
|
||||
NULL, IF_REAL,
|
||||
numNames, nameList, IF_REAL,
|
||||
&spPlot);
|
||||
txfree(nameList);
|
||||
|
||||
ipc_send_dcop_prefix();
|
||||
CKTdump(ckt, 0.0, spPlot);
|
||||
ipc_send_dcop_suffix();
|
||||
|
||||
SPfrontEnd->OUTendPlot(spPlot);
|
||||
}
|
||||
/* gtri - end - wbk */
|
||||
#endif
|
||||
|
||||
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
|
||||
error = CKTload(ckt);
|
||||
if (error) return(error);
|
||||
|
|
@ -937,22 +894,8 @@ SPan(CKTcircuit* ckt, int restart)
|
|||
data->lstFreq = freq;
|
||||
}
|
||||
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
||||
|
||||
if (g_ipc.enabled)
|
||||
ipc_send_data_prefix(freq);
|
||||
|
||||
error = CKTspDump(ckt, freq, spPlot, job->SPdoNoise);
|
||||
|
||||
if (g_ipc.enabled)
|
||||
ipc_send_data_suffix();
|
||||
|
||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
||||
#else
|
||||
error = CKTspDump(ckt, freq, spPlot, job->SPdoNoise);
|
||||
#endif
|
||||
if (error) {
|
||||
UPDATE_STATS(DOING_AC);
|
||||
tfree(internalNoiseAN);
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOPU( "tnom",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"),
|
||||
IOPUR("tref",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"),
|
||||
IOP( "rs", DIO_MOD_RS, IF_REAL, "Ohmic resistance"),
|
||||
IOP( "rsw", DIO_MOD_RSW, IF_REAL, "Ohmic resistance sidewall"),
|
||||
IOP( "trs", DIO_MOD_TRS, IF_REAL, "Ohmic resistance 1st order temp. coeff."),
|
||||
IOPR( "trs1", DIO_MOD_TRS, IF_REAL, "Ohmic resistance 1st order temp. coeff."),
|
||||
IOP( "trs2", DIO_MOD_TRS2, IF_REAL, "Ohmic resistance 2nd order temp. coeff."),
|
||||
|
|
@ -80,6 +81,7 @@ IFparm DIOmPTable[] = { /* model parameters */
|
|||
IOP( "ikf", DIO_MOD_IKF, IF_REAL, "Forward Knee current"),
|
||||
IOPR( "ik", DIO_MOD_IKF, IF_REAL, "Forward Knee current"),
|
||||
IOP( "ikr", DIO_MOD_IKR, IF_REAL, "Reverse Knee current"),
|
||||
IOP( "ikp", DIO_MOD_IKP, IF_REAL, "Forward Sw Knee current"),
|
||||
IOP( "nbv", DIO_MOD_NBV, IF_REAL, "Breakdown Emission Coefficient"),
|
||||
IOPR( "nz", DIO_MOD_NBV, IF_REAL, "Breakdown Emission Coefficient"),
|
||||
IOP("area", DIO_MOD_AREA, IF_REAL, "Area factor"),
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ int
|
|||
DIOacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
||||
{
|
||||
DIOmodel *model = (DIOmodel*)inModel;
|
||||
double gspr;
|
||||
double gspr, gsprsw;
|
||||
double geq;
|
||||
double xceq;
|
||||
DIOinstance *here;
|
||||
|
|
@ -42,6 +42,23 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(here->DIOposPrimePosPtr ) -= gspr;
|
||||
*(here->DIOposPrimeNegPtr ) -= geq;
|
||||
*(here->DIOposPrimeNegPtr +1 ) -= xceq;
|
||||
if (model->DIOresistSWGiven) {
|
||||
gsprsw=here->DIOtConductanceSW;
|
||||
geq= *(ckt->CKTstate0 + here->DIOconductSW);
|
||||
xceq= *(ckt->CKTstate0 + here->DIOcapCurrentSW) * ckt->CKTomega;
|
||||
*(here->DIOposPosPtr) += gsprsw;
|
||||
*(here->DIOnegNegPtr) += geq;
|
||||
*(here->DIOnegNegPtr + 1) += xceq;
|
||||
*(here->DIOposSwPrimePosSwPrimePtr) += (geq + gsprsw);
|
||||
*(here->DIOposSwPrimePosSwPrimePtr + 1) += xceq;
|
||||
*(here->DIOposPosSwPrimePtr) -= gsprsw;
|
||||
*(here->DIOnegPosSwPrimePtr) -= geq;
|
||||
*(here->DIOnegPosSwPrimePtr + 1) -= xceq;
|
||||
*(here->DIOposSwPrimePosPtr) -= gsprsw;
|
||||
*(here->DIOposSwPrimeNegPtr) -= geq;
|
||||
*(here->DIOposSwPrimeNegPtr + 1) -= xceq;
|
||||
}
|
||||
|
||||
int selfheat = ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given));
|
||||
if (selfheat) {
|
||||
double dIth_dVrs = here->DIOdIth_dVrs;
|
||||
|
|
@ -60,6 +77,19 @@ DIOacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
|
||||
double xgcTt= *(ckt->CKTstate0 + here->DIOcqth) * ckt->CKTomega;
|
||||
(*(here->DIOtempTempPtr + 1) += xgcTt);
|
||||
|
||||
if (model->DIOresistSWGiven) {
|
||||
double dIth_dVrssw = here->DIOdIth_dVrs;
|
||||
double dIth_dVdioSw = here->DIOdIth_dVdio;
|
||||
double dIrssw_dT = here->DIOdIrs_dT;
|
||||
double dIdioSw_dT = *(ckt->CKTstate0 + here->DIOdIdio_dT);
|
||||
(*(here->DIOtempPosPtr) += -dIth_dVrssw);
|
||||
(*(here->DIOtempPosSwPrimePtr) += -dIth_dVdioSw + dIth_dVrssw);
|
||||
(*(here->DIOtempNegPtr) += dIth_dVdioSw);
|
||||
(*(here->DIOposTempPtr) += dIrssw_dT);
|
||||
(*(here->DIOposSwPrimeTempPtr) += dIdioSw_dT - dIrssw_dT);
|
||||
(*(here->DIOnegTempPtr) += -dIdioSw_dT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CREATE_KLU_BINDING_TABLE(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode);
|
||||
/* separate sidewall */
|
||||
CREATE_KLU_BINDING_TABLE(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode);
|
||||
if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) {
|
||||
CREATE_KLU_BINDING_TABLE(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode);
|
||||
|
|
@ -40,6 +46,9 @@ DIObindCSC (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CREATE_KLU_BINDING_TABLE(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode);
|
||||
/* separate sidewall */
|
||||
CREATE_KLU_BINDING_TABLE(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode);
|
||||
CREATE_KLU_BINDING_TABLE(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -68,6 +77,12 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode);
|
||||
/* separate sidewall */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode);
|
||||
if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode);
|
||||
|
|
@ -76,6 +91,9 @@ DIObindCSCComplex (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode);
|
||||
/* separate sidewall */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -104,6 +122,12 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosPtr, DIOposPosBinding, DIOposNode, DIOposNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegNegPtr, DIOnegNegBinding, DIOnegNode, DIOnegNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimePosPrimePtr, DIOposPrimePosPrimeBinding, DIOposPrimeNode, DIOposPrimeNode);
|
||||
/* separate sidewall */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPosSwPrimePtr,DIOposPosSwPrimeBinding,DIOposNode,DIOposSwPrimeNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegPosSwPrimePtr,DIOnegPosSwPrimeBinding,DIOnegNode,DIOposSwPrimeNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosPtr,DIOposSwPrimePosBinding,DIOposSwPrimeNode,DIOposNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeNegPtr,DIOposSwPrimeNegBinding,DIOposSwPrimeNode,DIOnegNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimePosSwPrimeBinding,DIOposSwPrimeNode,DIOposSwPrimeNode);
|
||||
if ((here->DIOtempNode > 0) && (here->DIOthermal) && (model->DIOrth0Given)) {
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosPtr, DIOtempPosBinding, DIOtempNode, DIOposNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosPrimePtr, DIOtempPosPrimeBinding, DIOtempNode, DIOposPrimeNode);
|
||||
|
|
@ -112,6 +136,9 @@ DIObindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposTempPtr, DIOposTempBinding, DIOposNode, DIOtempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposPrimeTempPtr, DIOposPrimeTempBinding, DIOposPrimeNode, DIOtempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOnegTempPtr, DIOnegTempBinding, DIOnegNode, DIOtempNode);
|
||||
/* separate sidewall */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOtempPosSwPrimePtr, DIOtempPosSwPrimeBinding, DIOtempNode, DIOposSwPrimeNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(DIOposSwPrimeTempPtr, DIOposSwPrimeTempBinding, DIOposSwPrimeNode, DIOtempNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
{
|
||||
DIOmodel *model = (DIOmodel*)inModel;
|
||||
DIOinstance *here;
|
||||
double delvd,vd,cdhat,cd;
|
||||
double delvd,vd,cdhat,cd,vdsw,cdhatsw=0.0,cdsw=0.0;
|
||||
double tol;
|
||||
double delTemp, deldelTemp;
|
||||
/* loop through all the diode models */
|
||||
|
|
@ -46,11 +46,23 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
deldelTemp = delTemp - *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
|
||||
cdhat= *(ckt->CKTstate0 + here->DIOcurrent) +
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd +
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd +
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp;
|
||||
|
||||
cd= *(ckt->CKTstate0 + here->DIOcurrent);
|
||||
|
||||
if (model->DIOresistSWGiven) {
|
||||
vdsw = *(ckt->CKTrhsOld+here->DIOposSwPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
|
||||
delvd=vdsw- *(ckt->CKTstate0 + here->DIOvoltageSW);
|
||||
|
||||
cdhatsw= *(ckt->CKTstate0 + here->DIOcurrentSW) +
|
||||
*(ckt->CKTstate0 + here->DIOconductSW) * delvd +
|
||||
*(ckt->CKTstate0 + here->DIOdIdioSW_dT) * deldelTemp;
|
||||
|
||||
cdsw= *(ckt->CKTstate0 + here->DIOcurrentSW);
|
||||
}
|
||||
/*
|
||||
* check convergence
|
||||
*/
|
||||
|
|
@ -61,6 +73,15 @@ DIOconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* don't need to check any more device */
|
||||
}
|
||||
if (model->DIOresistSWGiven) {
|
||||
tol=ckt->CKTreltol*
|
||||
MAX(fabs(cdhatsw),fabs(cdsw))+ckt->CKTabstol;
|
||||
if (fabs(cdhatsw-cdsw) > tol) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
return(OK); /* no reason to continue - we've failed... */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ enum {
|
|||
DIORSNOIZ = 0,
|
||||
DIOIDNOIZ,
|
||||
DIOFLNOIZ,
|
||||
DIORSSWNOIZ,
|
||||
DIOIDSWNOIZ,
|
||||
DIOFLSWNOIZ,
|
||||
DIOTOTNOIZ,
|
||||
/* finally, the number of noise sources */
|
||||
DIONSRCS
|
||||
|
|
@ -40,6 +43,7 @@ typedef struct sDIOinstance {
|
|||
const int DIOnegNode; /* number of negative node of diode */
|
||||
const int DIOtempNode; /* number of the temperature node of the diode */
|
||||
int DIOposPrimeNode; /* number of positive prime node of diode */
|
||||
int DIOposSwPrimeNode; /* number of positive prime node of diode sidewall */
|
||||
|
||||
double *DIOposPosPrimePtr; /* pointer to sparse matrix at
|
||||
* (positive,positive prime) */
|
||||
|
|
@ -55,6 +59,17 @@ typedef struct sDIOinstance {
|
|||
* (negative,negative) */
|
||||
double *DIOposPrimePosPrimePtr; /* pointer to sparse matrix at
|
||||
* (positive prime,positive prime) */
|
||||
/* separate sidewall */
|
||||
double *DIOposPosSwPrimePtr; /* pointer to sparse matrix at
|
||||
* (positive,positive prime sidewall) */
|
||||
double *DIOnegPosSwPrimePtr; /* pointer to sparse matrix at
|
||||
* (negative,positive prime sidewall) */
|
||||
double *DIOposSwPrimePosPtr; /* pointer to sparse matrix at
|
||||
* (positive prime sidewall,positive) */
|
||||
double *DIOposSwPrimeNegPtr; /* pointer to sparse matrix at
|
||||
* (positive prime sidewall,negative) */
|
||||
double *DIOposSwPrimePosSwPrimePtr; /* pointer to sparse matrix at
|
||||
* (positive prime sidewall,positive prime sidewall) */
|
||||
|
||||
/* self heating */
|
||||
double *DIOtempPosPtr;
|
||||
|
|
@ -64,8 +79,12 @@ typedef struct sDIOinstance {
|
|||
double *DIOposTempPtr;
|
||||
double *DIOposPrimeTempPtr;
|
||||
double *DIOnegTempPtr;
|
||||
/* separate sidewall */
|
||||
double *DIOtempPosSwPrimePtr;
|
||||
double *DIOposSwPrimeTempPtr;
|
||||
|
||||
double DIOcap; /* stores the diode capacitance */
|
||||
double DIOcapSW; /* stores the diode Sw capacitance */
|
||||
|
||||
double *DIOsens; /* stores the perturbed values of geq and ceq in ac
|
||||
sensitivity analyis */
|
||||
|
|
@ -114,6 +133,8 @@ typedef struct sDIOinstance {
|
|||
double DIOtGradingCoeff; /* temperature adjusted grading coefficient (MJ) */
|
||||
double DIOtConductance; /* temperature adjusted series conductance */
|
||||
double DIOtConductance_dT; /* temperature adjusted series conductance temperature derivative */
|
||||
double DIOtConductanceSW; /* temperature adjusted sw series conductance */
|
||||
double DIOtConductanceSW_dT; /* temperature adjusted sw series conductance temperature derivative */
|
||||
|
||||
double DIOtDepCap; /* temperature adjusted transition point in */
|
||||
/* the curve matching (Fc * Vj ) */
|
||||
|
|
@ -129,6 +150,7 @@ typedef struct sDIOinstance {
|
|||
double DIOtTunSatSWCur_dT; /* sidewall tunneling saturation current temperature derivative */
|
||||
|
||||
double DIOtVcrit; /* temperature adjusted V crit */
|
||||
double DIOtVcritSW; /* temperature adjusted V crit sidewall*/
|
||||
double DIOtF1; /* temperature adjusted f1 */
|
||||
double DIOtBrkdwnV; /* temperature adjusted breakdown voltage */
|
||||
|
||||
|
|
@ -139,17 +161,21 @@ typedef struct sDIOinstance {
|
|||
|
||||
double DIOforwardKneeCurrent; /* Forward Knee current */
|
||||
double DIOreverseKneeCurrent; /* Reverse Knee current */
|
||||
double DIOforwardSWKneeCurrent; /* Forward Sw Knee current */
|
||||
double DIOjunctionCap; /* geometry adjusted junction capacitance */
|
||||
double DIOjunctionSWCap; /* geometry adjusted junction sidewall capacitance */
|
||||
double DIOtRecSatCur; /* temperature adjusted recombination saturation current */
|
||||
double DIOtRecSatCur_dT; /* temperature adjusted recombination saturation current */
|
||||
|
||||
double DIOdIth_dVrs;
|
||||
double DIOdIth_dVrssw;
|
||||
double DIOdIth_dVdio;
|
||||
double DIOdIth_dT;
|
||||
double DIOgcTt;
|
||||
double DIOdIrs_dT;
|
||||
double DIOdIrssw_dT;
|
||||
double DIOdIdio_dT;
|
||||
double DIOdIdioSW_dT;
|
||||
|
||||
double DIOcmetal; /* parasitic metal overlap capacitance */
|
||||
double DIOcpoly; /* parasitic polysilicon overlap capacitance */
|
||||
|
|
@ -194,6 +220,12 @@ typedef struct sDIOinstance {
|
|||
BindElement *DIOposPosBinding ;
|
||||
BindElement *DIOnegNegBinding ;
|
||||
BindElement *DIOposPrimePosPrimeBinding ;
|
||||
/* separate sidewall */
|
||||
BindElement *DIOposPosSwPrimeBinding ;
|
||||
BindElement *DIOnegPosSwPrimeBinding ;
|
||||
BindElement *DIOposSwPrimePosBinding ;
|
||||
BindElement *DIOposSwPrimeNegBinding ;
|
||||
BindElement *DIOposSwPrimePosSwPrimeBinding ;
|
||||
/* self heating */
|
||||
BindElement *DIOtempPosBinding;
|
||||
BindElement *DIOtempPosPrimeBinding;
|
||||
|
|
@ -216,18 +248,24 @@ typedef struct sDIOinstance {
|
|||
#define DIOvoltage DIOstate
|
||||
#define DIOcurrent DIOstate+1
|
||||
#define DIOconduct DIOstate+2
|
||||
#define DIOcapCharge DIOstate+3
|
||||
#define DIOcapCurrent DIOstate+4
|
||||
#define DIOvoltageSW DIOstate+3
|
||||
#define DIOcurrentSW DIOstate+4
|
||||
#define DIOconductSW DIOstate+5
|
||||
#define DIOcapCharge DIOstate+6
|
||||
#define DIOcapCurrent DIOstate+7
|
||||
#define DIOcapChargeSW DIOstate+8
|
||||
#define DIOcapCurrentSW DIOstate+9
|
||||
|
||||
#define DIOqth DIOstate+5 /* thermal capacitor charge */
|
||||
#define DIOcqth DIOstate+6 /* thermal capacitor current */
|
||||
#define DIOqth DIOstate+10 /* thermal capacitor charge */
|
||||
#define DIOcqth DIOstate+11 /* thermal capacitor current */
|
||||
|
||||
#define DIOdeltemp DIOstate+7 /* thermal voltage over rth0 */
|
||||
#define DIOdIdio_dT DIOstate+8
|
||||
#define DIOdeltemp DIOstate+12 /* thermal voltage over rth0 */
|
||||
#define DIOdIdio_dT DIOstate+13
|
||||
#define DIOdIdioSW_dT DIOstate+14
|
||||
|
||||
#define DIOnumStates 9
|
||||
#define DIOnumStates 15
|
||||
|
||||
#define DIOsensxp DIOstate+9 /* charge sensitivities and their derivatives.
|
||||
#define DIOsensxp DIOstate+12 /* charge sensitivities and their derivatives.
|
||||
* +10 for the derivatives - pointer to the
|
||||
* beginning of the array */
|
||||
|
||||
|
|
@ -252,6 +290,7 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
unsigned DIOresistGiven : 1;
|
||||
unsigned DIOresistTemp1Given : 1;
|
||||
unsigned DIOresistTemp2Given : 1;
|
||||
unsigned DIOresistSWGiven : 1;
|
||||
unsigned DIOemissionCoeffGiven : 1;
|
||||
unsigned DIOswEmissionCoeffGiven : 1;
|
||||
unsigned DIObrkdEmissionCoeffGiven : 1;
|
||||
|
|
@ -268,6 +307,7 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
unsigned DIOgradingSWCoeffGiven : 1;
|
||||
unsigned DIOforwardKneeCurrentGiven : 1;
|
||||
unsigned DIOreverseKneeCurrentGiven : 1;
|
||||
unsigned DIOforwardSWKneeCurrentGiven : 1;
|
||||
|
||||
unsigned DIOtlevGiven : 1;
|
||||
unsigned DIOtlevcGiven : 1;
|
||||
|
|
@ -324,6 +364,8 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
double DIOresistTemp1; /* series resistance 1st order temp. coeff. */
|
||||
double DIOresistTemp2; /* series resistance 2nd order temp. coeff. */
|
||||
double DIOconductance; /* conductance corresponding to ohmic R */
|
||||
double DIOresistSW; /* ohmic series resistance sidewall */
|
||||
double DIOconductanceSW; /* conductance corresponding to ohmic R */
|
||||
double DIOemissionCoeff; /* emission coefficient (N) */
|
||||
double DIOswEmissionCoeff; /* Sidewall emission coefficient (NS) */
|
||||
double DIObrkdEmissionCoeff; /* Breakdown emission coefficient (NBV) */
|
||||
|
|
@ -340,6 +382,7 @@ typedef struct sDIOmodel { /* model structure for a diode */
|
|||
double DIOgradingSWCoeff; /* Sidewall grading coefficient (mjsw) */
|
||||
double DIOforwardKneeCurrent; /* Forward Knee current (IKF) */
|
||||
double DIOreverseKneeCurrent; /* Reverse Knee current (IKR) */
|
||||
double DIOforwardSWKneeCurrent; /* Forward Sw Knee current (IKP) */
|
||||
|
||||
int DIOtlev; /* Diode temperature equation selector */
|
||||
int DIOtlevc; /* Diode temperature equation selector */
|
||||
|
|
@ -428,6 +471,7 @@ enum {
|
|||
DIO_MOD_LEVEL = 100,
|
||||
DIO_MOD_IS,
|
||||
DIO_MOD_RS,
|
||||
DIO_MOD_RSW,
|
||||
DIO_MOD_N,
|
||||
DIO_MOD_TT,
|
||||
DIO_MOD_CJO,
|
||||
|
|
@ -451,6 +495,7 @@ enum {
|
|||
DIO_MOD_MJSW,
|
||||
DIO_MOD_IKF,
|
||||
DIO_MOD_IKR,
|
||||
DIO_MOD_IKP,
|
||||
DIO_MOD_FCS,
|
||||
DIO_MOD_TTT1,
|
||||
DIO_MOD_TTT2,
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
DIOinstance *here;
|
||||
double arg;
|
||||
double argsw;
|
||||
double capd;
|
||||
double capd, capdsw=0.0;
|
||||
double cd, cdb, cdsw, cdb_dT, cdsw_dT;
|
||||
double cdeq;
|
||||
double cdhat;
|
||||
double cdhat, cdhatsw=0.0;
|
||||
double ceq;
|
||||
double csat; /* area-scaled saturation current */
|
||||
double csatsw; /* perimeter-scaled saturation current */
|
||||
|
|
@ -37,34 +37,33 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double czeroSW;
|
||||
double czof2SW;
|
||||
double sargSW;
|
||||
double sqrt_ikr;
|
||||
double sqrt_ikf;
|
||||
double ikf_area_m;
|
||||
double ikr_area_m;
|
||||
double sqrt_ikx;
|
||||
|
||||
double delvd; /* change in diode voltage temporary */
|
||||
double delvd, delvdsw=0.0; /* change in diode voltage temporary */
|
||||
double evd;
|
||||
double evrev;
|
||||
double gd, gdb, gdsw, gen_fac, gen_fac_vd;
|
||||
double t1, evd_rec, cdb_rec, gdb_rec, cdb_rec_dT;
|
||||
double geq;
|
||||
double gspr; /* area-scaled conductance */
|
||||
double gsprsw; /* perim-scaled conductance */
|
||||
double sarg;
|
||||
#ifndef NOBYPASS
|
||||
double tol; /* temporary for tolerence calculations */
|
||||
#endif
|
||||
double vd; /* current diode voltage */
|
||||
double vd, vdsw=0.0; /* current diode voltage */
|
||||
double vdtemp;
|
||||
double vt; /* K t / Q */
|
||||
double vte, vtesw, vtetun, vtebrk;
|
||||
int Check_dio=0, Check_th;
|
||||
double vte, vtesw, vtetun, vtebrk, vterec;
|
||||
int Check_dio=0, Check_dio_sw=0, Check_th;
|
||||
int error;
|
||||
int SenCond=0; /* sensitivity condition */
|
||||
double diffcharge, deplcharge, deplchargeSW, diffcap, deplcap, deplcapSW;
|
||||
|
||||
double deldelTemp, delTemp, Temp;
|
||||
double ceqqth=0.0, Ith=0.0, gcTt=0.0, vrs=0.0;
|
||||
double ceqqth=0.0, Ith=0.0, gcTt=0.0, vrs=0.0, vrssw=0.0;
|
||||
double dIdio_dT, dIth_dVdio=0.0, dIrs_dT=0.0, dIth_dVrs=0.0, dIth_dT=0.0;
|
||||
double dIdioSw_dT=0.0, dIth_dVdioSw=0.0, dIth_dVrssw=0.0, dIrssw_dT=0.0;
|
||||
double argsw_dT, csat_dT, csatsw_dT;
|
||||
|
||||
/* loop through all the diode models */
|
||||
|
|
@ -101,8 +100,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
delTemp = 0.0;
|
||||
vt = CONSTKoverQ * here->DIOtemp;
|
||||
vte = model->DIOemissionCoeff * vt;
|
||||
vtesw = model->DIOswEmissionCoeff * vt;
|
||||
vtebrk = model->DIObrkdEmissionCoeff * vt;
|
||||
vterec = model->DIOrecEmissionCoeff*vt;
|
||||
gspr = here->DIOtConductance;
|
||||
gsprsw = here->DIOtConductanceSW;
|
||||
/*
|
||||
* initialization
|
||||
*/
|
||||
|
|
@ -116,9 +118,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
if((ckt->CKTsenInfo->SENmode == TRANSEN)&&
|
||||
(ckt->CKTmode & MODEINITTRAN)) {
|
||||
vd = *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW);
|
||||
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
} else{
|
||||
vd = *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
}
|
||||
|
||||
|
|
@ -128,24 +132,28 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
goto next1;
|
||||
}
|
||||
|
||||
Check_dio=1;
|
||||
Check_dio=1; Check_dio_sw=1;
|
||||
if(ckt->CKTmode & MODEINITSMSIG) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate0 + here->DIOvoltageSW);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
} else if (ckt->CKTmode & MODEINITTRAN) {
|
||||
vd= *(ckt->CKTstate1 + here->DIOvoltage);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTstate1 + here->DIOvoltageSW);
|
||||
delTemp = *(ckt->CKTstate1 + here->DIOdeltemp);
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) &&
|
||||
(ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) {
|
||||
vd=here->DIOinitCond;
|
||||
if (model->DIOresistSWGiven) vdsw = here->DIOinitCond;
|
||||
} else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) {
|
||||
vd=0;
|
||||
vd=vdsw=0;
|
||||
delTemp = 0.0;
|
||||
} else if ( ckt->CKTmode & MODEINITJCT) {
|
||||
vd=here->DIOtVcrit;
|
||||
vdsw=here->DIOtVcritSW;
|
||||
delTemp = 0.0;
|
||||
} else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) {
|
||||
vd=0;
|
||||
vd=vdsw=0;
|
||||
delTemp = 0.0;
|
||||
} else {
|
||||
#ifndef PREDICTOR
|
||||
|
|
@ -164,10 +172,17 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTstate1 + here->DIOdIdio_dT);
|
||||
*(ckt->CKTstate0+here->DIOqth) =
|
||||
*(ckt->CKTstate1+here->DIOqth);
|
||||
if (model->DIOresistSWGiven) {
|
||||
vdsw = DEVpred(ckt,here->DIOvoltageSW);
|
||||
*(ckt->CKTstate0 + here->DIOdIdioSW_dT) =
|
||||
*(ckt->CKTstate1 + here->DIOdIdioSW_dT);
|
||||
}
|
||||
} else {
|
||||
#endif /* PREDICTOR */
|
||||
vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
if (model->DIOresistSWGiven) vdsw = *(ckt->CKTrhsOld+here->DIOposSwPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->DIOnegNode);
|
||||
if (selfheat)
|
||||
delTemp = *(ckt->CKTrhsOld + here->DIOtempNode);
|
||||
else
|
||||
|
|
@ -185,6 +200,11 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
cdhat= *(ckt->CKTstate0 + here->DIOcurrent) +
|
||||
*(ckt->CKTstate0 + here->DIOconduct) * delvd +
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) * deldelTemp;
|
||||
if (model->DIOresistSWGiven) {
|
||||
delvdsw=vdsw - *(ckt->CKTstate0 + here->DIOvoltageSW);
|
||||
cdhatsw = *(ckt->CKTstate0 + here->DIOconductSW) * delvdsw +
|
||||
*(ckt->CKTstate0 + here->DIOdIdioSW_dT) * deldelTemp;
|
||||
}
|
||||
/*
|
||||
* bypass if solution has not changed
|
||||
*/
|
||||
|
|
@ -192,7 +212,7 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) {
|
||||
tol=ckt->CKTvoltTol + ckt->CKTreltol*
|
||||
MAX(fabs(vd),fabs(*(ckt->CKTstate0 +here->DIOvoltage)));
|
||||
if (fabs(delvd) < tol){
|
||||
if (fabs(delvd) < tol) {
|
||||
tol=ckt->CKTreltol* MAX(fabs(cdhat),
|
||||
fabs(*(ckt->CKTstate0 + here->DIOcurrent)))+
|
||||
ckt->CKTabstol;
|
||||
|
|
@ -202,12 +222,25 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
(fabs(deldelTemp) < (ckt->CKTreltol * MAX(fabs(delTemp),
|
||||
fabs(*(ckt->CKTstate0+here->DIOdeltemp)))+
|
||||
ckt->CKTvoltTol*1e4))) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
cd= *(ckt->CKTstate0 + here->DIOcurrent);
|
||||
gd= *(ckt->CKTstate0 + here->DIOconduct);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT);
|
||||
goto load;
|
||||
if ((!model->DIOresistSWGiven) || (fabs(delvdsw) < ckt->CKTvoltTol + ckt->CKTreltol *
|
||||
MAX(fabs(vdsw),fabs(*(ckt->CKTstate0+here->DIOvoltageSW))))) {
|
||||
if ((!model->DIOresistSWGiven) || (fabs(cdhatsw- *(ckt->CKTstate0 + here->DIOcurrentSW))
|
||||
< ckt->CKTreltol* MAX(fabs(cdhatsw),
|
||||
fabs(*(ckt->CKTstate0 + here->DIOcurrentSW)))+ckt->CKTabstol)) {
|
||||
vd= *(ckt->CKTstate0 + here->DIOvoltage);
|
||||
cd= *(ckt->CKTstate0 + here->DIOcurrent);
|
||||
gd= *(ckt->CKTstate0 + here->DIOconduct);
|
||||
delTemp = *(ckt->CKTstate0 + here->DIOdeltemp);
|
||||
dIdio_dT= *(ckt->CKTstate0 + here->DIOdIdio_dT);
|
||||
if (model->DIOresistSWGiven) {
|
||||
vdsw= *(ckt->CKTstate0 + here->DIOvoltageSW);
|
||||
cdsw= *(ckt->CKTstate0 + here->DIOcurrentSW);
|
||||
gdsw= *(ckt->CKTstate0 + here->DIOconductSW);
|
||||
dIdioSw_dT= *(ckt->CKTstate0 + here->DIOdIdioSW_dT);
|
||||
}
|
||||
goto load;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -228,6 +261,20 @@ DIOload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
vd = DEVpnjlim(vd,*(ckt->CKTstate0 + here->DIOvoltage),
|
||||
vte,here->DIOtVcrit,&Check_dio);
|
||||
}
|
||||
if (model->DIOresistSWGiven) {
|
||||
if ( (model->DIObreakdownVoltageGiven) &&
|
||||
(vdsw < MIN(0,-here->DIOtBrkdwnV+10*vtebrk))) {
|
||||
vdtemp = -(vdsw+here->DIOtBrkdwnV);
|
||||
vdtemp = DEVpnjlim(vdtemp,
|
||||
-(*(ckt->CKTstate0 + here->DIOvoltageSW) +
|
||||
here->DIOtBrkdwnV),vtebrk,
|
||||
here->DIOtVcritSW,&Check_dio_sw);
|
||||
vdsw = -(vdtemp+here->DIOtBrkdwnV);
|
||||
} else {
|
||||
vdsw = DEVpnjlim(vdsw,*(ckt->CKTstate0 + here->DIOvoltageSW),
|
||||
vtesw,here->DIOtVcritSW,&Check_dio_sw);
|
||||
}
|
||||
}
|
||||
if (selfheat)
|
||||
delTemp = DEVlimitlog(delTemp,
|
||||
*(ckt->CKTstate0 + here->DIOdeltemp), 100, &Check_th);
|
||||
|
|
@ -253,47 +300,45 @@ next1:
|
|||
csatsw = here->DIOtSatSWCur;
|
||||
csatsw_dT = here->DIOtSatSWCur_dT;
|
||||
gspr = here->DIOtConductance;
|
||||
gsprsw = here->DIOtConductanceSW;
|
||||
|
||||
if (model->DIOsatSWCurGiven) { /* sidewall current */
|
||||
if (model->DIOsatSWCurGiven) { /* sidewall current */
|
||||
double vds;
|
||||
if (model->DIOresistSWGiven)
|
||||
vds = vdsw; /* sidewall voltage used */
|
||||
else
|
||||
vds = vd; /* common voltage used */
|
||||
|
||||
if (model->DIOswEmissionCoeffGiven) { /* current with own characteristic */
|
||||
if (model->DIOswEmissionCoeffGiven) { /* with own characteristic */
|
||||
|
||||
vtesw = model->DIOswEmissionCoeff * vt;
|
||||
if (vds >= -3*vtesw) { /* forward */
|
||||
|
||||
if (vd >= -3*vtesw) { /* forward */
|
||||
|
||||
evd = exp(vd/vtesw);
|
||||
evd = exp(vds/vtesw);
|
||||
cdsw = csatsw*(evd-1);
|
||||
gdsw = csatsw*evd/vtesw;
|
||||
cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vtesw * Temp);
|
||||
cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vds * evd / (vtesw * Temp);
|
||||
|
||||
} else if((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vd >= -here->DIOtBrkdwnV) { /* reverse */
|
||||
} else if ((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vds >= -here->DIOtBrkdwnV) { /* reverse */
|
||||
|
||||
argsw = 3*vtesw/(vd*CONSTe);
|
||||
argsw = 3*vtesw/(vds*CONSTe);
|
||||
argsw = argsw * argsw * argsw;
|
||||
argsw_dT = 3 * argsw / Temp;
|
||||
cdsw = -csatsw*(1+argsw);
|
||||
gdsw = csatsw*3*argsw/vd;
|
||||
gdsw = csatsw*3*argsw/vds;
|
||||
cdsw_dT = -csatsw_dT - (csatsw_dT*argsw + csatsw*argsw_dT);
|
||||
|
||||
} else { /* breakdown */
|
||||
} else if (!model->DIOresistSWGiven){ /* breakdown, but not for separate sidewall diode */
|
||||
double evrev_dT;
|
||||
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk);
|
||||
evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp);
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vds)/vtebrk);
|
||||
evrev_dT = (here->DIOtBrkdwnV+vds)*evrev/(vtebrk*Temp);
|
||||
cdsw = -csatsw*evrev;
|
||||
gdsw = csatsw*evrev/vtebrk;
|
||||
cdsw_dT = -(csatsw_dT*evrev + csatsw*evrev_dT);
|
||||
|
||||
}
|
||||
|
||||
} else { /* merge saturation currents and use same characteristic as bottom diode */
|
||||
|
||||
csat = csat + csatsw;
|
||||
csat_dT = csat_dT + csatsw_dT;
|
||||
cdsw_dT = 0.0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -302,15 +347,19 @@ next1:
|
|||
* temperature dependent diode saturation current and derivative
|
||||
*/
|
||||
|
||||
if (vd >= -3*vte) { /* bottom current forward */
|
||||
|
||||
if (vd >= -3*vte) { /* bottom and sidewall current forward with common voltage */
|
||||
/* and with common characteristic */
|
||||
evd = exp(vd/vte);
|
||||
cdb = csat*(evd-1);
|
||||
gdb = csat*evd/vte;
|
||||
cdb_dT = csat_dT * (evd - 1) - csat * vd * evd / (vte * Temp);
|
||||
if ((model->DIOsatSWCurGiven)&&(!model->DIOswEmissionCoeffGiven)) {
|
||||
cdsw = csatsw*(evd-1);
|
||||
gdsw = csatsw*evd/vte;
|
||||
cdsw_dT = csatsw_dT * (evd - 1) - csatsw * vd * evd / (vte * Temp);
|
||||
}
|
||||
if (model->DIOrecSatCurGiven) { /* recombination current */
|
||||
double vterec = model->DIOrecEmissionCoeff*vt;
|
||||
evd_rec = exp(vd/(vterec));
|
||||
evd_rec = exp(vd/vterec);
|
||||
cdb_rec = here->DIOtRecSatCur*(evd_rec-1);
|
||||
gdb_rec = here->DIOtRecSatCur*evd_rec/vterec;
|
||||
cdb_rec_dT = here->DIOtRecSatCur_dT * (evd_rec - 1)
|
||||
|
|
@ -326,7 +375,7 @@ next1:
|
|||
cdb_dT = cdb_dT + cdb_rec_dT*gen_fac;
|
||||
}
|
||||
|
||||
} else if((!(model->DIObreakdownVoltageGiven)) ||
|
||||
} else if ((!(model->DIObreakdownVoltageGiven)) ||
|
||||
vd >= -here->DIOtBrkdwnV) { /* reverse */
|
||||
|
||||
double darg_dT;
|
||||
|
|
@ -334,18 +383,49 @@ next1:
|
|||
arg = 3*vte/(vd*CONSTe);
|
||||
arg = arg * arg * arg;
|
||||
darg_dT = 3 * arg / Temp;
|
||||
cdb = -csat*(1+arg);
|
||||
if (model->DIOrecSatCurGiven) {
|
||||
evd_rec = exp((-3*vte)/vterec);
|
||||
cdb_rec = here->DIOtRecSatCur*(evd_rec-1);
|
||||
t1 = pow((1-(-3*vte)/here->DIOtJctPot), 2) + 0.005;
|
||||
gen_fac = pow(t1, here->DIOtGradingCoeff/2);
|
||||
cdb = -csat*(1+arg) + gen_fac*cdb_rec;
|
||||
} else {
|
||||
cdb = -csat*(1+arg);
|
||||
}
|
||||
gdb = csat*3*arg/vd;
|
||||
cdb_dT = -csat_dT - (csat_dT*arg + csat*darg_dT);
|
||||
if ((model->DIOsatSWCurGiven)&&(!model->DIOswEmissionCoeffGiven)) {
|
||||
cdsw = -csatsw*(1+arg);
|
||||
gdsw = csatsw*3*arg/vd;
|
||||
cdsw_dT = -csatsw_dT - (csatsw_dT*arg + csatsw*darg_dT);
|
||||
}
|
||||
|
||||
} else { /* breakdown */
|
||||
|
||||
double evrev_dT;
|
||||
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vd)/vtebrk);
|
||||
evrev_dT = (here->DIOtBrkdwnV+vd)*evrev/(vtebrk*Temp);
|
||||
cdb = -csat*evrev;
|
||||
if (model->DIOrecSatCurGiven) {
|
||||
evd_rec = exp((-3*vte)/vterec);
|
||||
cdb_rec = here->DIOtRecSatCur*(evd_rec-1);
|
||||
t1 = pow((1-(-3*vte)/here->DIOtJctPot), 2) + 0.005;
|
||||
gen_fac = pow(t1, here->DIOtGradingCoeff/2);
|
||||
cdb = -csat*evrev + gen_fac*cdb_rec;
|
||||
} else {
|
||||
cdb = -csat*evrev;
|
||||
}
|
||||
gdb = csat*evrev/vtebrk;
|
||||
cdb_dT = -(csat_dT*evrev + csat*evrev_dT);
|
||||
if ((model->DIOsatSWCurGiven)
|
||||
&&(!model->DIOswEmissionCoeffGiven)
|
||||
&&(!model->DIOresistSWGiven)) { /* no breakdown for separate sidewall diode */
|
||||
evrev = exp(-(here->DIOtBrkdwnV+vdsw)/vtebrk);
|
||||
evrev_dT = (here->DIOtBrkdwnV+vdsw)*evrev/(vtebrk*Temp);
|
||||
cdsw = -csatsw*evrev;
|
||||
gdsw = csatsw*evrev/vtebrk;
|
||||
cdsw_dT = -(csatsw_dT*evrev + csatsw*evrev_dT);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -373,36 +453,46 @@ next1:
|
|||
|
||||
}
|
||||
|
||||
cd = cdb + cdsw;
|
||||
gd = gdb + gdsw;
|
||||
dIdio_dT = cdb_dT + cdsw_dT;
|
||||
|
||||
if (vd >= -3*vte) { /* limit forward */
|
||||
|
||||
if( (model->DIOforwardKneeCurrentGiven) && (cd > 1.0e-18) ) {
|
||||
ikf_area_m = here->DIOforwardKneeCurrent;
|
||||
sqrt_ikf = sqrt(cd/ikf_area_m);
|
||||
gd = ((1+sqrt_ikf)*gd - cd*gd/(2*sqrt_ikf*ikf_area_m))/(1+2*sqrt_ikf + cd/ikf_area_m) + ckt->CKTgmin;
|
||||
cd = cd/(1+sqrt_ikf) + ckt->CKTgmin*vd;
|
||||
} else {
|
||||
gd = gd + ckt->CKTgmin;
|
||||
cd = cd + ckt->CKTgmin*vd;
|
||||
if ( (model->DIOforwardKneeCurrentGiven) && (cdb > 1.0e-18) ) {
|
||||
double ikf_area_m = here->DIOforwardKneeCurrent;
|
||||
sqrt_ikx = sqrt(cdb/ikf_area_m);
|
||||
gdb = ((1+sqrt_ikx)*gdb - cdb*gdb/(2*sqrt_ikx*ikf_area_m))/(1+2*sqrt_ikx + cdb/ikf_area_m);
|
||||
cdb = cdb/(1+sqrt_ikx);
|
||||
}
|
||||
|
||||
} else { /* limit reverse */
|
||||
|
||||
if( (model->DIOreverseKneeCurrentGiven) && (cd < -1.0e-18) ) {
|
||||
ikr_area_m = here->DIOreverseKneeCurrent;
|
||||
sqrt_ikr = sqrt(cd/(-ikr_area_m));
|
||||
gd = ((1+sqrt_ikr)*gd + cd*gd/(2*sqrt_ikr*ikr_area_m))/(1+2*sqrt_ikr - cd/ikr_area_m) + ckt->CKTgmin;
|
||||
cd = cd/(1+sqrt_ikr) + ckt->CKTgmin*vd;
|
||||
} else {
|
||||
gd = gd + ckt->CKTgmin;
|
||||
cd = cd + ckt->CKTgmin*vd;
|
||||
if ( (model->DIOreverseKneeCurrentGiven) && (cdb < -1.0e-18) ) {
|
||||
double ikr_area_m = here->DIOreverseKneeCurrent;
|
||||
sqrt_ikx = sqrt(cdb/(-ikr_area_m));
|
||||
gdb = ((1+sqrt_ikx)*gdb + cdb*gdb/(2*sqrt_ikx*ikr_area_m))/(1+2*sqrt_ikx - cdb/ikr_area_m);
|
||||
cdb = cdb/(1+sqrt_ikx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( (model->DIOforwardSWKneeCurrentGiven) && (cdsw > 1.0e-18) ) {
|
||||
double ikp_peri_m = here->DIOforwardSWKneeCurrent;
|
||||
sqrt_ikx = sqrt(cdsw/ikp_peri_m);
|
||||
gdsw = ((1+sqrt_ikx)*gdsw - cdsw*gdsw/(2*sqrt_ikx*ikp_peri_m))/(1+2*sqrt_ikx + cdsw/ikp_peri_m);
|
||||
cdsw = cdsw/(1+sqrt_ikx);
|
||||
}
|
||||
|
||||
if (!model->DIOresistSWGiven) {
|
||||
cd = cdb + cdsw + ckt->CKTgmin*vd;
|
||||
gd = gdb + gdsw + ckt->CKTgmin;
|
||||
dIdio_dT = cdb_dT + cdsw_dT;
|
||||
} else {
|
||||
cd = cdb + ckt->CKTgmin*vd;
|
||||
gd = gdb + ckt->CKTgmin;
|
||||
cdsw = cdsw + ckt->CKTgmin*vdsw;
|
||||
gdsw = gdsw + ckt->CKTgmin;
|
||||
dIdio_dT = cdb_dT;
|
||||
dIdioSw_dT = cdsw_dT;
|
||||
}
|
||||
|
||||
if ((ckt->CKTmode & (MODEDCTRANCURVE | MODETRAN | MODEAC | MODEINITSMSIG)) ||
|
||||
((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) {
|
||||
/*
|
||||
|
|
@ -421,28 +511,40 @@ next1:
|
|||
deplcap = czof2*(here->DIOtF3+here->DIOtGradingCoeff*vd/here->DIOtJctPot);
|
||||
}
|
||||
czeroSW=here->DIOtJctSWCap;
|
||||
if (vd < here->DIOtDepSWCap){
|
||||
argSW=1-vd/here->DIOtJctSWPot;
|
||||
double vdx;
|
||||
if (model->DIOresistSWGiven)
|
||||
vdx = vdsw;
|
||||
else
|
||||
vdx = vd;
|
||||
if (vdx < here->DIOtDepSWCap){
|
||||
argSW=1-vdx/here->DIOtJctSWPot;
|
||||
sargSW=exp(-model->DIOgradingSWCoeff*log(argSW));
|
||||
deplchargeSW = here->DIOtJctSWPot*czeroSW*(1-argSW*sargSW)/(1-model->DIOgradingSWCoeff);
|
||||
deplcapSW = czeroSW*sargSW;
|
||||
} else {
|
||||
czof2SW=czeroSW/here->DIOtF2SW;
|
||||
deplchargeSW = czeroSW*here->DIOtF1+czof2SW*(here->DIOtF3SW*(vd-here->DIOtDepSWCap)+
|
||||
(model->DIOgradingSWCoeff/(here->DIOtJctSWPot+here->DIOtJctSWPot))*(vd*vd-here->DIOtDepSWCap*here->DIOtDepSWCap));
|
||||
deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vd/here->DIOtJctSWPot);
|
||||
deplchargeSW = czeroSW*here->DIOtF1+czof2SW*(here->DIOtF3SW*(vdx-here->DIOtDepSWCap)+
|
||||
(model->DIOgradingSWCoeff/(here->DIOtJctSWPot+here->DIOtJctSWPot))*(vdx*vdx-here->DIOtDepSWCap*here->DIOtDepSWCap));
|
||||
deplcapSW = czof2SW*(here->DIOtF3SW+model->DIOgradingSWCoeff*vdx/here->DIOtJctSWPot);
|
||||
}
|
||||
|
||||
diffcharge = here->DIOtTransitTime*cd;
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) =
|
||||
diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd;
|
||||
|
||||
diffcap = here->DIOtTransitTime*gd;
|
||||
|
||||
capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly;
|
||||
|
||||
here->DIOcap = capd;
|
||||
|
||||
if (!model->DIOresistSWGiven) {
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) =
|
||||
diffcharge + deplcharge + deplchargeSW + (here->DIOcmetal + here->DIOcpoly)*vd;
|
||||
capd = diffcap + deplcap + deplcapSW + here->DIOcmetal + here->DIOcpoly;
|
||||
here->DIOcap = capd;
|
||||
} else {
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge) =
|
||||
diffcharge + deplcharge + (here->DIOcmetal + here->DIOcpoly)*vd;
|
||||
capd = diffcap + deplcap + here->DIOcmetal + here->DIOcpoly;
|
||||
here->DIOcap = capd;
|
||||
*(ckt->CKTstate0 + here->DIOcapChargeSW) =
|
||||
deplcapSW;
|
||||
capdsw = deplcapSW;
|
||||
here->DIOcapSW = capdsw;
|
||||
}
|
||||
/*
|
||||
* store small-signal parameters
|
||||
*/
|
||||
|
|
@ -450,11 +552,18 @@ next1:
|
|||
(!(ckt->CKTmode & MODEUIC)) ) {
|
||||
if (ckt->CKTmode & MODEINITSMSIG){
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrent) = capd;
|
||||
|
||||
if (model->DIOresistSWGiven) {
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrentSW) = capdsw;
|
||||
}
|
||||
if(SenCond){
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
*(ckt->CKTstate0 + here->DIOconduct) = gd;
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT;
|
||||
if (model->DIOresistSWGiven) {
|
||||
*(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw;
|
||||
*(ckt->CKTstate0 + here->DIOconductSW) = gdsw;
|
||||
*(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT;
|
||||
}
|
||||
#ifdef SENSDEBUG
|
||||
printf("storing small signal parameters\n");
|
||||
printf("cd = %.7e,vd = %.7e\n",cd,vd);
|
||||
|
|
@ -469,6 +578,8 @@ next1:
|
|||
*/
|
||||
if(SenCond && (ckt->CKTsenInfo->SENmode == TRANSEN)){
|
||||
*(ckt->CKTstate0 + here->DIOcurrent) = cd;
|
||||
if (model->DIOresistSWGiven)
|
||||
*(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw;
|
||||
#ifdef SENSDEBUG
|
||||
printf("storing parameters for transient sensitivity\n"
|
||||
);
|
||||
|
|
@ -481,21 +592,29 @@ next1:
|
|||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOcapCharge) =
|
||||
*(ckt->CKTstate0 + here->DIOcapCharge);
|
||||
if (model->DIOresistSWGiven)
|
||||
*(ckt->CKTstate1 + here->DIOcapChargeSW) =
|
||||
*(ckt->CKTstate0 + here->DIOcapChargeSW);
|
||||
}
|
||||
error = NIintegrate(ckt,&geq,&ceq,capd,here->DIOcapCharge);
|
||||
if(error) return(error);
|
||||
gd=gd+geq;
|
||||
cd=cd+*(ckt->CKTstate0 + here->DIOcapCurrent);
|
||||
if (model->DIOresistSWGiven) {
|
||||
error = NIintegrate(ckt,&geq,&ceq,capdsw,here->DIOcapChargeSW);
|
||||
if(error) return(error);
|
||||
gdsw=gdsw+geq;
|
||||
cdsw=cdsw+*(ckt->CKTstate0 + here->DIOcapCurrentSW);
|
||||
}
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOcapCurrent) =
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrent);
|
||||
if (model->DIOresistSWGiven)
|
||||
*(ckt->CKTstate1 + here->DIOcapCurrentSW) =
|
||||
*(ckt->CKTstate0 + here->DIOcapCurrentSW);
|
||||
}
|
||||
if (selfheat)
|
||||
{
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
*(ckt->CKTstate1 + here->DIOqth) =
|
||||
*(ckt->CKTstate0 + here->DIOqth);
|
||||
}
|
||||
error = NIintegrate(ckt, &gcTt, &ceqqth, model->DIOcth0, here->DIOqth);
|
||||
if (error) return(error);
|
||||
if (ckt->CKTmode & MODEINITTRAN) {
|
||||
|
|
@ -512,9 +631,16 @@ next1:
|
|||
* check convergence
|
||||
*/
|
||||
if ( (!(ckt->CKTmode & MODEINITFIX)) || (!(here->DIOoff)) ) {
|
||||
if ((Check_th == 1) || (Check_dio == 1)) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
if (!model->DIOresistSWGiven) {
|
||||
if ((Check_th == 1) || (Check_dio == 1)) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
}
|
||||
} else {
|
||||
if ((Check_th == 1) || (Check_dio == 1) || (Check_dio_sw == 1)) {
|
||||
ckt->CKTnoncon++;
|
||||
ckt->CKTtroubleElt = (GENinstance *) here;
|
||||
}
|
||||
}
|
||||
}
|
||||
next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
||||
|
|
@ -522,7 +648,12 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
|||
*(ckt->CKTstate0 + here->DIOconduct) = gd;
|
||||
*(ckt->CKTstate0 + here->DIOdeltemp) = delTemp;
|
||||
*(ckt->CKTstate0 + here->DIOdIdio_dT) = dIdio_dT;
|
||||
|
||||
if (model->DIOresistSWGiven) {
|
||||
*(ckt->CKTstate0 + here->DIOvoltageSW) = vdsw;
|
||||
*(ckt->CKTstate0 + here->DIOcurrentSW) = cdsw;
|
||||
*(ckt->CKTstate0 + here->DIOconductSW) = gdsw;
|
||||
*(ckt->CKTstate0 + here->DIOdIdioSW_dT) = dIdioSw_dT;
|
||||
}
|
||||
if(SenCond) continue;
|
||||
|
||||
#ifndef NOBYPASS
|
||||
|
|
@ -531,20 +662,37 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
|||
if (selfheat) {
|
||||
double dIrs_dVrs, dIrs_dgspr, dIth_dIrs;
|
||||
vrs = *(ckt->CKTrhsOld + here->DIOposNode) - *(ckt->CKTrhsOld + here->DIOposPrimeNode);
|
||||
Ith = vd*cd + vrs*vrs*gspr; /* Diode dissipated power */
|
||||
dIrs_dVrs = gspr;
|
||||
dIrs_dgspr = vrs;
|
||||
dIrs_dT = dIrs_dgspr * here->DIOtConductance_dT;
|
||||
Ith = vd*cd + vrs*vrs*gspr; /* Diode dissipated power */
|
||||
dIth_dVrs = vrs*gspr;
|
||||
dIth_dIrs = vrs;
|
||||
dIth_dVrs = dIth_dVrs + dIth_dIrs*dIrs_dVrs;
|
||||
dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd;
|
||||
dIth_dVdio = cd + vd*gd;
|
||||
here->DIOdIth_dVrs = dIth_dVrs;
|
||||
here->DIOdIth_dVdio = dIth_dVdio;
|
||||
here->DIOdIth_dT = dIth_dT;
|
||||
here->DIOgcTt = gcTt;
|
||||
here->DIOdIrs_dT = dIrs_dT;
|
||||
here->DIOdIth_dVdio = dIth_dVdio;
|
||||
here->DIOdIth_dT = dIth_dT;
|
||||
if (model->DIOresistSWGiven) {
|
||||
double dIrssw_dVrssw, dIrssw_dgsprsw, dIth_dIrssw;
|
||||
vrssw = *(ckt->CKTrhsOld + here->DIOposNode) - *(ckt->CKTrhsOld + here->DIOposSwPrimeNode);
|
||||
dIrssw_dVrssw = gsprsw;
|
||||
dIrssw_dgsprsw = vrssw;
|
||||
dIrssw_dT = dIrssw_dgsprsw * here->DIOtConductanceSW_dT;
|
||||
Ith = Ith + vdsw*cdsw + vrssw*vrssw*gsprsw; /* Diode dissipated power */
|
||||
dIth_dVrssw = vrssw*gsprsw;
|
||||
dIth_dIrssw = vrssw;
|
||||
dIth_dVrssw = dIth_dVrssw + dIth_dIrssw*dIrssw_dVrssw;
|
||||
dIth_dT = dIth_dT + dIth_dIrssw*dIrssw_dT + dIdioSw_dT*vdsw;
|
||||
dIth_dVdioSw = cdsw + vdsw*gdsw;
|
||||
here->DIOdIth_dVrssw = dIth_dVrssw;
|
||||
here->DIOdIth_dVdio = dIth_dVdioSw;
|
||||
here->DIOdIth_dT = dIth_dT;
|
||||
here->DIOdIrssw_dT = dIrssw_dT;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* load current vector
|
||||
|
|
@ -558,6 +706,17 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
|||
*(ckt->CKTrhs + here->DIOnegNode) += -dIdio_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOtempNode) += Ith - dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp - ceqqth;
|
||||
}
|
||||
if (model->DIOresistSWGiven) {
|
||||
cdeq=cdsw-gdsw*vdsw;
|
||||
*(ckt->CKTrhs + here->DIOnegNode) += cdeq;
|
||||
*(ckt->CKTrhs + here->DIOposSwPrimeNode) -= cdeq;
|
||||
if (selfheat) {
|
||||
*(ckt->CKTrhs + here->DIOposNode) += dIrssw_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOposSwPrimeNode) += dIdioSw_dT*delTemp - dIrssw_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOnegNode) += -dIdioSw_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->DIOtempNode) += -dIth_dVdioSw*vdsw - dIth_dVrssw*vrssw;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* load matrix
|
||||
*/
|
||||
|
|
@ -577,6 +736,24 @@ next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd;
|
|||
(*(here->DIOposPrimeTempPtr) += dIdio_dT - dIrs_dT);
|
||||
(*(here->DIOnegTempPtr) += -dIdio_dT);
|
||||
}
|
||||
if (model->DIOresistSWGiven) {
|
||||
*(here->DIOposPosPtr) += gsprsw;
|
||||
*(here->DIOnegNegPtr) += gdsw;
|
||||
*(here->DIOposSwPrimePosSwPrimePtr) += (gdsw + gsprsw);
|
||||
*(here->DIOposPosSwPrimePtr) -= gsprsw;
|
||||
*(here->DIOnegPosSwPrimePtr) -= gdsw;
|
||||
*(here->DIOposSwPrimePosPtr) -= gsprsw;
|
||||
*(here->DIOposSwPrimeNegPtr) -= gdsw;
|
||||
|
||||
if (selfheat) {
|
||||
(*(here->DIOtempPosPtr) += -dIth_dVrssw);
|
||||
(*(here->DIOtempPosSwPrimePtr) += -dIth_dVdioSw + dIth_dVrssw);
|
||||
(*(here->DIOtempNegPtr) += dIth_dVdioSw);
|
||||
(*(here->DIOposTempPtr) += dIrssw_dT);
|
||||
(*(here->DIOposSwPrimeTempPtr) += dIdioSw_dT - dIrssw_dT);
|
||||
(*(here->DIOnegTempPtr) += -dIdioSw_dT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value)
|
|||
case DIO_MOD_RS:
|
||||
value->rValue = model->DIOresist;
|
||||
return(OK);
|
||||
case DIO_MOD_RSW:
|
||||
value->rValue = model->DIOresistSW;
|
||||
return(OK);
|
||||
case DIO_MOD_TRS:
|
||||
value->rValue = model->DIOresistTemp1;
|
||||
return(OK);
|
||||
|
|
@ -93,6 +96,9 @@ DIOmAsk (CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value)
|
|||
case DIO_MOD_IKR:
|
||||
value->rValue = model->DIOreverseKneeCurrent;
|
||||
return(OK);
|
||||
case DIO_MOD_IKP:
|
||||
value->rValue = model->DIOforwardSWKneeCurrent;
|
||||
return(OK);
|
||||
case DIO_MOD_NBV:
|
||||
value->rValue = model->DIObrkdEmissionCoeff;
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel)
|
|||
model->DIOresist = value->rValue;
|
||||
model->DIOresistGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_RSW:
|
||||
model->DIOresistSW = value->rValue;
|
||||
model->DIOresistSWGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_TRS:
|
||||
model->DIOresistTemp1 = value->rValue;
|
||||
model->DIOresistTemp1Given = TRUE;
|
||||
|
|
@ -108,6 +112,10 @@ DIOmParam(int param, IFvalue *value, GENmodel *inModel)
|
|||
model->DIOreverseKneeCurrent = value->rValue;
|
||||
model->DIOreverseKneeCurrentGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_IKP:
|
||||
model->DIOforwardSWKneeCurrent = value->rValue;
|
||||
model->DIOforwardSWKneeCurrentGiven = TRUE;
|
||||
break;
|
||||
case DIO_MOD_NBV:
|
||||
model->DIObrkdEmissionCoeff = value->rValue;
|
||||
model->DIObrkdEmissionCoeffGiven = TRUE;
|
||||
|
|
|
|||
|
|
@ -41,10 +41,13 @@ DIOnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
|
|||
|
||||
static char *DIOnNames[DIONSRCS] = {
|
||||
/* Note that we have to keep the order
|
||||
consistent with thestrchr definitions in DIOdefs.h */
|
||||
consistent with the strchr definitions in DIOdefs.h */
|
||||
"_rs", /* noise due to rs */
|
||||
"_id", /* noise due to id */
|
||||
"_1overf", /* flicker (1/f) noise */
|
||||
"_rsw", /* noise due to rsw */
|
||||
"_idsw", /* noise due to id sw */
|
||||
"_1overfsw", /* flicker (1/f) noise sw */
|
||||
"" /* total diode noise */
|
||||
};
|
||||
|
||||
|
|
@ -108,10 +111,36 @@ DIOnoise(int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
|
|||
noizDens[DIOTOTNOIZ] = noizDens[DIORSNOIZ] +
|
||||
noizDens[DIOIDNOIZ] +
|
||||
noizDens[DIOFLNOIZ];
|
||||
|
||||
if (model->DIOresistSWGiven) {
|
||||
/* sidewall diode */
|
||||
NevalSrcInstanceTemp(&noizDens[DIORSSWNOIZ],&lnNdens[DIORSSWNOIZ],
|
||||
ckt, THERMNOISE, inst->DIOposSwPrimeNode, inst->DIOposNode,
|
||||
inst->DIOtConductanceSW, dtemp);
|
||||
|
||||
NevalSrc(&noizDens[DIOIDSWNOIZ],&lnNdens[DIOIDSWNOIZ],
|
||||
ckt, SHOTNOISE, inst->DIOposSwPrimeNode, inst->DIOnegNode,
|
||||
*(ckt->CKTstate0 + inst->DIOcurrentSW));
|
||||
|
||||
NevalSrc(&noizDens[DIOFLSWNOIZ], NULL, ckt,
|
||||
N_GAIN, inst->DIOposSwPrimeNode, inst->DIOnegNode,
|
||||
(double) 0.0);
|
||||
noizDens[DIOFLSWNOIZ] *= model->DIOfNcoef *
|
||||
exp(model->DIOfNexp *
|
||||
log(MAX(fabs(*(ckt->CKTstate0 + inst->DIOcurrentSW) / inst->DIOm), N_MINLOG))) /
|
||||
data->freq * inst->DIOm;
|
||||
lnNdens[DIOFLSWNOIZ] =
|
||||
log(MAX(noizDens[DIOFLSWNOIZ], N_MINLOG));
|
||||
|
||||
noizDens[DIOTOTNOIZ] += noizDens[DIORSSWNOIZ] +
|
||||
noizDens[DIOIDSWNOIZ] +
|
||||
noizDens[DIOFLSWNOIZ];
|
||||
}
|
||||
|
||||
lnNdens[DIOTOTNOIZ] =
|
||||
log(MAX(noizDens[DIOTOTNOIZ], N_MINLOG));
|
||||
|
||||
*OnDens += noizDens[DIOTOTNOIZ];
|
||||
*OnDens += noizDens[DIOTOTNOIZ];
|
||||
|
||||
if (data->delFreq == 0.0) {
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ int
|
|||
DIOpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
|
||||
{
|
||||
DIOmodel *model = (DIOmodel*)inModel;
|
||||
double gspr;
|
||||
double gspr, gsprsw;
|
||||
double geq;
|
||||
double xceq;
|
||||
DIOinstance *here;
|
||||
|
|
@ -43,6 +43,22 @@ DIOpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s)
|
|||
*(here->DIOposPrimePosPtr ) -= gspr;
|
||||
*(here->DIOposPrimeNegPtr ) -= geq + xceq * s->real;
|
||||
*(here->DIOposPrimeNegPtr +1 ) -= xceq * s->imag;
|
||||
if (model->DIOresistSWGiven) {
|
||||
gsprsw=here->DIOtConductanceSW;
|
||||
geq= *(ckt->CKTstate0 + here->DIOconductSW);
|
||||
xceq= *(ckt->CKTstate0 + here->DIOcapCurrentSW) * ckt->CKTomega;
|
||||
*(here->DIOposPosPtr) += gsprsw;
|
||||
*(here->DIOnegNegPtr) += geq + xceq * s->real;
|
||||
*(here->DIOnegNegPtr + 1) += xceq * s->imag;
|
||||
*(here->DIOposSwPrimePosSwPrimePtr) += geq + gsprsw + xceq * s->real;
|
||||
*(here->DIOposSwPrimePosSwPrimePtr + 1) += xceq * s->imag;
|
||||
*(here->DIOposPosSwPrimePtr) -= gsprsw;
|
||||
*(here->DIOnegPosSwPrimePtr) -= geq;
|
||||
*(here->DIOnegPosSwPrimePtr + 1) -= xceq;
|
||||
*(here->DIOposSwPrimePosPtr) -= gsprsw;
|
||||
*(here->DIOposSwPrimeNegPtr) -= geq + xceq * s->real;
|
||||
*(here->DIOposSwPrimeNegPtr + 1) -= xceq * s->imag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
|
||||
if(!model->DIOlevelGiven) {
|
||||
model->DIOlevel = 1;
|
||||
} else if (model->DIOlevel == 2) {
|
||||
SPfrontEnd->IFerrorf(ERR_FATAL,
|
||||
"%s: Diode model level 2 is not supported.", model->DIOmodName);
|
||||
return(E_BADPARM);
|
||||
}
|
||||
if(!model->DIOemissionCoeffGiven) {
|
||||
model->DIOemissionCoeff = 1;
|
||||
|
|
@ -117,6 +121,13 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
model->DIOmodName);
|
||||
}
|
||||
}
|
||||
if(model->DIOforwardSWKneeCurrentGiven) {
|
||||
if (model->DIOforwardSWKneeCurrent < ckt->CKTepsmin) {
|
||||
model->DIOforwardSWKneeCurrentGiven = FALSE;
|
||||
fprintf(stderr, "Warning: %s: IKP too small - model effect disabled!\n",
|
||||
model->DIOmodName);
|
||||
}
|
||||
}
|
||||
if(!model->DIObrkdEmissionCoeffGiven) {
|
||||
model->DIObrkdEmissionCoeff = model->DIOemissionCoeff;
|
||||
}
|
||||
|
|
@ -238,6 +249,24 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
} else {
|
||||
model->DIOconductance = 1/model->DIOresist;
|
||||
}
|
||||
if((!model->DIOresistSWGiven) || (model->DIOresistSW==0)) {
|
||||
if (newcompat.ps || newcompat.lt) {
|
||||
double rsdiode = 0.;
|
||||
/* to improve convergence (sometimes) */
|
||||
if (cp_getvar("diode_rser", CP_REAL, &rsdiode, 0) && rsdiode > 0) {
|
||||
model->DIOconductanceSW = 1./rsdiode;
|
||||
model->DIOresistSW = rsdiode;
|
||||
if (ft_ngdebug)
|
||||
fprintf(stderr, "Diode sidewall series resistance in model %s set to %e Ohm\n", model->gen.GENmodName, rsdiode);
|
||||
}
|
||||
else
|
||||
model->DIOconductanceSW = 0.0;
|
||||
}
|
||||
else
|
||||
model->DIOconductanceSW = 0.0;
|
||||
} else {
|
||||
model->DIOconductanceSW = 1/model->DIOresistSW;
|
||||
}
|
||||
|
||||
if (!model->DIOrth0Given) {
|
||||
model->DIOrth0 = 0;
|
||||
|
|
@ -329,6 +358,7 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
}
|
||||
here->DIOforwardKneeCurrent = model->DIOforwardKneeCurrent * here->DIOarea * here->DIOm;
|
||||
here->DIOreverseKneeCurrent = model->DIOreverseKneeCurrent * here->DIOarea * here->DIOm;
|
||||
here->DIOforwardSWKneeCurrent = model->DIOforwardSWKneeCurrent * here->DIOpj * here->DIOm;
|
||||
here->DIOjunctionCap = model->DIOjunctionCap * here->DIOarea * here->DIOm;
|
||||
here->DIOjunctionSWCap = model->DIOjunctionSWCap * here->DIOpj * here->DIOm;
|
||||
|
||||
|
|
@ -344,19 +374,41 @@ DIOsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states)
|
|||
|
||||
} else if(here->DIOposPrimeNode == 0) {
|
||||
|
||||
CKTnode *tmpNode;
|
||||
IFuid tmpName;
|
||||
CKTnode *tmpNode;
|
||||
IFuid tmpName;
|
||||
|
||||
error = CKTmkVolt(ckt,&tmp,here->DIOname,"internal");
|
||||
if(error) return(error);
|
||||
here->DIOposPrimeNode = tmp->number;
|
||||
if (ckt->CKTcopyNodesets) {
|
||||
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
|
||||
if (tmpNode->nsGiven) {
|
||||
tmp->nodeset=tmpNode->nodeset;
|
||||
tmp->nsGiven=tmpNode->nsGiven;
|
||||
}
|
||||
}
|
||||
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
|
||||
if (tmpNode->nsGiven) {
|
||||
tmp->nodeset=tmpNode->nodeset;
|
||||
tmp->nsGiven=tmpNode->nsGiven;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!model->DIOresistSWGiven) {
|
||||
|
||||
here->DIOposSwPrimeNode = here->DIOposPrimeNode;
|
||||
|
||||
} else if(here->DIOposSwPrimeNode == 0) {
|
||||
|
||||
CKTnode *tmpNode;
|
||||
IFuid tmpName;
|
||||
|
||||
error = CKTmkVolt(ckt,&tmp,here->DIOname,"internal_sw");
|
||||
if(error) return(error);
|
||||
here->DIOposSwPrimeNode = tmp->number;
|
||||
if (ckt->CKTcopyNodesets) {
|
||||
if (CKTinst2Node(ckt,here,1,&tmpNode,&tmpName)==OK) {
|
||||
if (tmpNode->nsGiven) {
|
||||
tmp->nodeset=tmpNode->nodeset;
|
||||
tmp->nsGiven=tmpNode->nsGiven;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -375,6 +427,14 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
|
|||
TSTALLOC(DIOposPosPtr,DIOposNode,DIOposNode);
|
||||
TSTALLOC(DIOnegNegPtr,DIOnegNode,DIOnegNode);
|
||||
TSTALLOC(DIOposPrimePosPrimePtr,DIOposPrimeNode,DIOposPrimeNode);
|
||||
if(model->DIOresistSWGiven) {
|
||||
/* separate sidewall */
|
||||
TSTALLOC(DIOposPosSwPrimePtr,DIOposNode,DIOposSwPrimeNode);
|
||||
TSTALLOC(DIOnegPosSwPrimePtr,DIOnegNode,DIOposSwPrimeNode);
|
||||
TSTALLOC(DIOposSwPrimePosPtr,DIOposSwPrimeNode,DIOposNode);
|
||||
TSTALLOC(DIOposSwPrimeNegPtr,DIOposSwPrimeNode,DIOnegNode);
|
||||
TSTALLOC(DIOposSwPrimePosSwPrimePtr,DIOposSwPrimeNode,DIOposSwPrimeNode);
|
||||
}
|
||||
|
||||
if (selfheat) {
|
||||
TSTALLOC(DIOtempPosPtr, DIOtempNode, DIOposNode);
|
||||
|
|
@ -384,6 +444,11 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
|
|||
TSTALLOC(DIOposTempPtr, DIOposNode, DIOtempNode);
|
||||
TSTALLOC(DIOposPrimeTempPtr, DIOposPrimeNode, DIOtempNode);
|
||||
TSTALLOC(DIOnegTempPtr, DIOnegNode, DIOtempNode);
|
||||
if(model->DIOresistSWGiven) {
|
||||
/* separate sidewall */
|
||||
TSTALLOC(DIOtempPosSwPrimePtr, DIOtempNode, DIOposSwPrimeNode);
|
||||
TSTALLOC(DIOposSwPrimeTempPtr, DIOposSwPrimeNode, DIOtempNode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -410,6 +475,15 @@ DIOunsetup(
|
|||
&& here->DIOposPrimeNode != here->DIOposNode)
|
||||
CKTdltNNum(ckt, here->DIOposPrimeNode);
|
||||
here->DIOposPrimeNode = 0;
|
||||
|
||||
if(model->DIOresistSWGiven) {
|
||||
/* separate sidewall */
|
||||
if (here->DIOposSwPrimeNode > 0
|
||||
&& here->DIOposSwPrimeNode != here->DIOposNode)
|
||||
CKTdltNNum(ckt, here->DIOposSwPrimeNode);
|
||||
here->DIOposSwPrimeNode = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
double dt;
|
||||
double factor;
|
||||
double tBreakdownVoltage;
|
||||
double totalSatCur;
|
||||
|
||||
double egfet1,arg1,fact1,pbfact1,pbo,gmaold,pboSW,gmaSWold;
|
||||
double fact2,pbfact,arg,egfet,gmanew,gmaSWnew;
|
||||
|
|
@ -196,9 +197,14 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
here->DIOtDepSWCap=model->DIOdepletionSWcapCoeff*
|
||||
here->DIOtJctSWPot;
|
||||
/* and Vcrit */
|
||||
double totalSatCur = here->DIOtSatCur + here->DIOtSatSWCur;
|
||||
here->DIOtVcrit = vte * log(vte/(CONSTroot2*totalSatCur));
|
||||
|
||||
totalSatCur = here->DIOtSatCur + here->DIOtSatSWCur;
|
||||
if(model->DIOresistSWGiven) {
|
||||
here->DIOtVcrit = vte * log(vte/(CONSTroot2*here->DIOtSatCur));
|
||||
here->DIOtVcritSW = vts * log(vts/(CONSTroot2*here->DIOtSatSWCur));
|
||||
} else {
|
||||
here->DIOtVcrit = vte * log(vte/(CONSTroot2*totalSatCur));
|
||||
here->DIOtVcritSW = vts * log(vts/(CONSTroot2*here->DIOtSatSWCur));
|
||||
}
|
||||
/* and now to compute the breakdown voltage, again, using
|
||||
* temperature adjusted basic parameters */
|
||||
if (model->DIObreakdownVoltageGiven){
|
||||
|
|
@ -253,6 +259,14 @@ void DIOtempUpdate(DIOmodel *inModel, DIOinstance *here, double Temp, CKTcircuit
|
|||
here->DIOtConductance_dT = -model->DIOconductance * here->DIOarea * here->DIOm *
|
||||
(model->DIOresistTemp1 + model->DIOresistTemp2 * dt) / (factor*factor);
|
||||
}
|
||||
here->DIOtConductanceSW = model->DIOconductanceSW * here->DIOpj * here->DIOm;
|
||||
if(model->DIOresistSWGiven && model->DIOresistSW!=0.0) {
|
||||
factor = 1.0 + (model->DIOresistTemp1) * dt
|
||||
+ (model->DIOresistTemp2 * dt * dt);
|
||||
here->DIOtConductanceSW = model->DIOconductanceSW * here->DIOpj * here->DIOm / factor;
|
||||
here->DIOtConductanceSW_dT = -model->DIOconductanceSW * here->DIOpj * here->DIOm *
|
||||
(model->DIOresistTemp1 + model->DIOresistTemp2 * dt) / (factor*factor);
|
||||
}
|
||||
|
||||
here->DIOtF2=exp((1+here->DIOtGradingCoeff)*xfc);
|
||||
here->DIOtF3=1-model->DIOdepletionCapCoeff*
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ DIOtrunc(GENmodel *inModel, CKTcircuit *ckt, double *timeStep)
|
|||
for( ; model != NULL; model = DIOnextModel(model)) {
|
||||
for(here=DIOinstances(model);here!=NULL;here = DIOnextInstance(here)){
|
||||
CKTterr(here->DIOcapCharge,ckt,timeStep);
|
||||
if (model->DIOresistSWGiven) CKTterr(here->DIOcapChargeSW,ckt,timeStep);
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
GmT = model->VDMOStype * here->VDMOSgmT;
|
||||
cgT = model->VDMOStype * here->VDMOScgT;
|
||||
cdT = model->VDMOStype * here->VDMOScdT;
|
||||
cTt = model->VDMOScthj;
|
||||
// Everything is computed for m parallel instances... so scale cthj accordingly
|
||||
cTt = here->VDMOSm * model->VDMOScthj;
|
||||
gTtg = here->VDMOSgtempg;
|
||||
gTtdp = here->VDMOSgtempd;
|
||||
gTtt = here->VDMOSgtempT;
|
||||
|
|
@ -57,7 +58,8 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
GmT = -model->VDMOStype * here->VDMOSgmT;
|
||||
cgT = -model->VDMOStype * here->VDMOScgT;
|
||||
cdT = -model->VDMOStype * here->VDMOScdT;
|
||||
cTt = -model->VDMOScthj;
|
||||
// Everything is computed for m parallel instances... so scale cthj accordingly
|
||||
cTt = - here->VDMOSm * model->VDMOScthj;
|
||||
gTtg = -here->VDMOSgtempg;
|
||||
gTtdp = -here->VDMOSgtempd;
|
||||
gTtt = -here->VDMOSgtempT;
|
||||
|
|
@ -131,21 +133,23 @@ VDMOSacLoad(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(here->VDIORPdPtr +1) -= xceq;
|
||||
if (selfheat)
|
||||
{
|
||||
*(here->VDMOSDPtempPtr) += GmT;
|
||||
// Everything is computed for m parallel instances... so scale gthjc and gthja accordingly
|
||||
double gthjc = here->VDMOSm / model->VDMOSrthjc;
|
||||
double gthca = here->VDMOSm / model->VDMOSrthca;
|
||||
*(here->VDMOSDPtempPtr) += GmT;
|
||||
*(here->VDMOSSPtempPtr) += -GmT;
|
||||
|
||||
*(here->VDMOSTemptempPtr) += gTtt + 1/model->VDMOSrthjc;
|
||||
*(here->VDMOSTempgpPtr) += gTtg;
|
||||
*(here->VDMOSTempdpPtr) += gTtdp;
|
||||
*(here->VDMOSTempspPtr) += gTtsp;
|
||||
*(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc;
|
||||
*(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc;
|
||||
*(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca;
|
||||
*(here->VDMOSTptpPtr) += 1/model->VDMOSrthca;
|
||||
*(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca;
|
||||
*(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca;
|
||||
*(here->VDMOSCktTtpPtr) += 1.0;
|
||||
*(here->VDMOSTpcktTPtr) += 1.0;
|
||||
*(here->VDMOSTemptempPtr) += gTtt + gthjc;
|
||||
*(here->VDMOSTempgpPtr) += gTtg;
|
||||
*(here->VDMOSTempdpPtr) += gTtdp;
|
||||
*(here->VDMOSTempspPtr) += gTtsp;
|
||||
*(here->VDMOSTemptcasePtr) += -gthjc;
|
||||
*(here->VDMOSTcasetempPtr) += -gthjc;
|
||||
*(here->VDMOSTcasetcasePtr) += gthjc + gthca;
|
||||
*(here->VDMOSTptpPtr) += gthca;
|
||||
*(here->VDMOSTptcasePtr) += -gthca;
|
||||
*(here->VDMOSTcasetpPtr) += -gthca;
|
||||
*(here->VDMOSDevTtpPtr) += 1.0;
|
||||
*(here->VDMOSTpdevTPtr) += 1.0;
|
||||
|
||||
*(here->VDMOSTemptempPtr + 1) += xcTt;
|
||||
*(here->VDMOSDPtempPtr + 1) += xcdT;
|
||||
|
|
|
|||
|
|
@ -67,18 +67,18 @@ VDMOSbindCSC (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CREATE_KLU_BINDING_TABLE(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode);
|
||||
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime);
|
||||
CREATE_KLU_BINDING_TABLE(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -142,18 +142,18 @@ VDMOSbindCSCComplex (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode);
|
||||
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_COMPLEX(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -217,18 +217,18 @@ VDMOSbindCSCComplexToReal (GENmodel *inModel, CKTcircuit *ckt)
|
|||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTempdPtr, VDMOSTempdBinding, VDMOStempNode, VDMOSdNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDIOPosPrimetempPtr, VDIOPosPrimetempBinding, VDIOposPrimeNode, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDtempPtr, VDMOSDtempBinding, VDMOSdNode, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOStempSPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSSTempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTempsPtr, VDMOStempSBinding, VDMOStempNode, VDMOSsNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSStempPtr, VDMOSSTempBinding, VDMOSsNode, VDMOStempNode);
|
||||
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetcasePtr, VDMOSTcasetcaseBinding, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetempPtr, VDMOSTcasetempBinding, VDMOStcaseNode, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTemptcasePtr, VDMOSTemptcaseBinding, VDMOStempNode, VDMOStcaseNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptpPtr, VDMOSTptpBinding, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStempNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStempNode, VDMOStNodePrime);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSCktTcktTPtr, VDMOSCktTcktTBinding, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSCktTtpPtr, VDMOSCktTtpBinding, VDMOSvcktTbranch, VDMOStNodePrime);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpcktTPtr, VDMOSTpcktTBinding, VDMOStNodePrime, VDMOSvcktTbranch);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTptcasePtr, VDMOSTptcaseBinding, VDMOStNodePrime, VDMOStcaseNode);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTcasetpPtr, VDMOSTcasetpBinding, VDMOStcaseNode, VDMOStNodePrime);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDevTdevTPtr, VDMOSDevTdevTBinding, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=devTemp to gnd */
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSDevTtpPtr, VDMOSDevTtpBinding, VDMOSvdevTbranch, VDMOStNodePrime);
|
||||
CONVERT_KLU_BINDING_TABLE_TO_REAL(VDMOSTpdevTPtr, VDMOSTpdevTBinding, VDMOStNodePrime, VDMOSvdevTbranch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,8 +82,9 @@ VDMOSconvTest(GENmodel *inModel, CKTcircuit *ckt)
|
|||
* initialization
|
||||
*/
|
||||
|
||||
vd = *(ckt->CKTrhsOld+here->VDIOposPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->VDMOSdNode);
|
||||
vd = model->VDMOStype * (
|
||||
*(ckt->CKTrhsOld+here->VDIOposPrimeNode)-
|
||||
*(ckt->CKTrhsOld + here->VDMOSdNode));
|
||||
|
||||
delvd=vd- *(ckt->CKTstate0 + here->VDIOvoltage);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ typedef struct sVDMOSinstance {
|
|||
int VDMOStNodePrime; /* number of the internal temp node between voltage source and Rthca */
|
||||
int VDIOposPrimeNode; /* number of the internal node of the body diode */
|
||||
|
||||
int VDMOSvcktTbranch; /* equation number of branch equation added for cktTemp source */
|
||||
int VDMOSvdevTbranch; /* equation number of branch equation added for cktTemp source */
|
||||
|
||||
double VDMOSm; /* parallel device multiplier */
|
||||
|
||||
|
|
@ -229,8 +229,8 @@ typedef struct sVDMOSinstance {
|
|||
double *VDMOSTempdPtr;
|
||||
double *VDIOPosPrimetempPtr;
|
||||
double *VDMOSDtempPtr;
|
||||
double *VDMOStempSPtr;
|
||||
double *VDMOSSTempPtr;
|
||||
double *VDMOSTempsPtr;
|
||||
double *VDMOSStempPtr;
|
||||
|
||||
double *VDMOSTcasetcasePtr; /* for Rthjc */
|
||||
double *VDMOSTcasetempPtr;
|
||||
|
|
@ -238,9 +238,9 @@ typedef struct sVDMOSinstance {
|
|||
double *VDMOSTptpPtr; /* for Rthca */
|
||||
double *VDMOSTptcasePtr;
|
||||
double *VDMOSTcasetpPtr;
|
||||
double *VDMOSCktTcktTPtr; /* for VcktTemp */
|
||||
double *VDMOSCktTtpPtr;
|
||||
double *VDMOSTpcktTPtr;
|
||||
double *VDMOSDevTdevTPtr; /* for VdevTemp */
|
||||
double *VDMOSDevTtpPtr;
|
||||
double *VDMOSTpdevTPtr;
|
||||
|
||||
#ifdef KLU
|
||||
BindElement *VDMOSDdBinding ;
|
||||
|
|
@ -287,9 +287,9 @@ typedef struct sVDMOSinstance {
|
|||
BindElement *VDMOSTptpBinding ;
|
||||
BindElement *VDMOSTptcaseBinding ;
|
||||
BindElement *VDMOSTcasetpBinding ;
|
||||
BindElement *VDMOSCktTcktTBinding ;
|
||||
BindElement *VDMOSCktTtpBinding ;
|
||||
BindElement *VDMOSTpcktTBinding ;
|
||||
BindElement *VDMOSDevTdevTBinding ;
|
||||
BindElement *VDMOSDevTtpBinding ;
|
||||
BindElement *VDMOSTpdevTBinding ;
|
||||
#endif
|
||||
|
||||
} VDMOSinstance ;
|
||||
|
|
|
|||
|
|
@ -57,26 +57,27 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
int error;
|
||||
|
||||
int selfheat;
|
||||
double rd0T, rd1T, dBeta_dT, dIds_dT;
|
||||
double rd0T, rd1T, dBeta_dT, dIds_dT=0.0;
|
||||
double Vrd=0.0, dIth_dVrd=0.0, dIrd_dT=0.0;
|
||||
double drd0T_dT, drd1T_dT, drd_dT, dgdrain_dT=0.0;
|
||||
double dIrd_dgdrain;
|
||||
double drd0T_dT, drd1T_dT, dgdrain_dT=0.0;
|
||||
double rsT, Vrs=0.0, dIth_dVrs=0.0, dIrs_dT=0.0, dgsource_dT=0.0;
|
||||
double deldelTemp=0.0, delTemp, delTemp1, Temp, Vds, Vgs;
|
||||
double ceqqth=0.0;
|
||||
double GmT, gTtg, gTtdp, gTtt, gTtsp, gcTt=0.0;
|
||||
|
||||
/* loop through all the VDMOS device models */
|
||||
for (; model != NULL; model = VDMOSnextModel(model)) {
|
||||
/* VDMOS capacitance parameters */
|
||||
const double cgdmin = model->VDMOScgdmin;
|
||||
const double cgdmax = model->VDMOScgdmax;
|
||||
const double a = model->VDMOSa;
|
||||
const double cgs = model->VDMOScgs;
|
||||
|
||||
/* loop through all the instances of the model */
|
||||
for (here = VDMOSinstances(model); here != NULL;
|
||||
here = VDMOSnextInstance(here)) {
|
||||
|
||||
/* VDMOS capacitance parameters */
|
||||
const double cgdmin = here->VDMOSm * model->VDMOScgdmin;
|
||||
const double cgdmax = here->VDMOSm * model->VDMOScgdmax;
|
||||
const double a = model->VDMOSa;
|
||||
const double cgs = here->VDMOSm * model->VDMOScgs;
|
||||
|
||||
Temp = here->VDMOStemp;
|
||||
selfheat = (here->VDMOSthermal) && (model->VDMOSrthjcGiven);
|
||||
if (selfheat)
|
||||
|
|
@ -84,16 +85,6 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
else
|
||||
Check_th = 0;
|
||||
|
||||
/* FIXME:
|
||||
this is not a fix, but a hack:
|
||||
with selfheat, op and op for ac don't work, NaN in self heating evaluation of
|
||||
first iteration in CKTop(). Calling CKTop() from acan uses flag MODEDCOP,
|
||||
changing this to MODETRANOP, as used by CKTop() called from dctran, then op is o.k.
|
||||
*/
|
||||
if (selfheat)
|
||||
if(ckt->CKTmode == 528) /* includes MODEDCOP */
|
||||
ckt->CKTmode = 544; /* includes MODETRANOP */
|
||||
|
||||
/* first, we compute a few useful values - these could be
|
||||
* pre-computed, but for historical reasons are still done
|
||||
* here. They may be moved at the expense of instance size
|
||||
|
|
@ -279,7 +270,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
}
|
||||
if (selfheat)
|
||||
delTemp = DEVlimitlog(delTemp,
|
||||
*(ckt->CKTstate0 + here->VDMOSdelTemp),30,&Check_th);
|
||||
*(ckt->CKTstate0 + here->VDMOSdelTemp),10,&Check_th);
|
||||
else
|
||||
delTemp = 0.0;
|
||||
#endif /*NODELIMITING*/
|
||||
|
|
@ -287,7 +278,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
}
|
||||
|
||||
if (selfheat) {
|
||||
Temp = here->VDMOStemp + delTemp;
|
||||
Temp = delTemp + CONSTCtoK;
|
||||
VDMOStempUpdate(model, here, Temp, ckt);
|
||||
} else {
|
||||
Temp = here->VDMOStemp;
|
||||
|
|
@ -296,17 +287,24 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
|
||||
/* Calculate temperature dependent values for self-heating effect */
|
||||
if (selfheat) {
|
||||
double TempRatio = Temp / here->VDMOStemp;
|
||||
Beta = here->VDMOStTransconductance * pow(TempRatio,model->VDMOSmu);
|
||||
Beta = here->VDMOStTransconductance;
|
||||
dBeta_dT = Beta * model->VDMOSmu / Temp;
|
||||
rd0T = here->VDMOSdrainResistance * pow(TempRatio, model->VDMOStexp0);
|
||||
drd0T_dT = rd0T * model->VDMOStexp0 / Temp;
|
||||
rd0T = here->VDMOSdrainResistance;
|
||||
if (model->VDMOStexp0Given)
|
||||
drd0T_dT = rd0T * model->VDMOStexp0 / Temp;
|
||||
else
|
||||
drd0T_dT = model->VDMOSdrainResistance / here->VDMOSm
|
||||
* (model->VDMOStrd1 + 2 * model->VDMOStrd2 * (Temp - model->VDMOStnom));
|
||||
rd1T = 0.0;
|
||||
drd1T_dT = 0.0;
|
||||
if (model->VDMOSqsGiven) {
|
||||
rd1T = here->VDMOSqsResistance * pow(TempRatio, model->VDMOStexp1);
|
||||
rd1T = here->VDMOSqsResistance;
|
||||
drd1T_dT = rd1T * model->VDMOStexp1 / Temp;
|
||||
}
|
||||
rsT = 1 / here->VDMOSsourceConductance;
|
||||
double drsT_dT = model->VDMOSsourceResistance / here->VDMOSm
|
||||
* (model->VDMOStrs1 + 2 * model->VDMOStrs2 * (Temp - model->VDMOStnom));
|
||||
dgsource_dT = -drsT_dT / (rsT*rsT);
|
||||
} else {
|
||||
Beta = here->VDMOStTransconductance;
|
||||
dBeta_dT = 0.0;
|
||||
|
|
@ -316,6 +314,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
drd1T_dT = 0.0;
|
||||
if (model->VDMOSqsGiven)
|
||||
rd1T = here->VDMOSqsResistance;
|
||||
dgsource_dT = 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -368,7 +367,6 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
double betap = Beta*t0/t1;
|
||||
double dbetapdvgs = -Beta*theta*t0/(t1*t1);
|
||||
double dbetapdvds = Beta*lambda/t1;
|
||||
double dbetapdT = dBeta_dT*t0/t1;
|
||||
|
||||
double t2 = exp((vgst-shift)/slope);
|
||||
vgst = slope * log(1 + t2);
|
||||
|
|
@ -379,14 +377,27 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
cdrain = betap * vgst*vgst * .5;
|
||||
here->VDMOSgm = betap*vgst*dvgstdvgs + 0.5*dbetapdvgs*vgst*vgst;
|
||||
here->VDMOSgds = .5*dbetapdvds*vgst*vgst;
|
||||
dIds_dT = dbetapdT * vgst*vgst * .5;
|
||||
}
|
||||
else {
|
||||
/* linear region */
|
||||
cdrain = betap * vdss * (vgst - .5 * vdss);
|
||||
here->VDMOSgm = betap*vdss*dvgstdvgs + vdss*dbetapdvgs*(vgst-.5*vdss);
|
||||
here->VDMOSgds = vdss*dbetapdvds*(vgst-.5*vdss) + betap*mtr*(vgst-.5*vdss) - .5*vdss*betap*mtr;
|
||||
dIds_dT = dbetapdT * vdss * (vgst - .5 * vdss);
|
||||
}
|
||||
if (selfheat) {
|
||||
double dvgst_dT = model->VDMOStype * model->VDMOStcvth;
|
||||
double dvdsat_dT = 0.0;
|
||||
if (vgst > 0) {
|
||||
dvdsat_dT = dvgst_dT;
|
||||
}
|
||||
double dt1_dT = theta * dvdsat_dT;
|
||||
double dbetap_dT = t0 * (t1 * dBeta_dT - Beta * dt1_dT) / (t1 * t1);
|
||||
if (vgst <= vdss) {
|
||||
dIds_dT = .5 * dbetap_dT * vgst*vgst + betap * vgst * dvgst_dT;
|
||||
}
|
||||
else {
|
||||
dIds_dT = vdss * (dbetap_dT * vgst + betap * dvgst_dT) - dbetap_dT * vdss * .5 * vdss;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,7 +429,7 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
*(ckt->CKTrhsOld + here->VDMOSdNode) -
|
||||
*(ckt->CKTrhsOld + here->VDMOSsNode));
|
||||
double rd = rd0T + rd1T * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage)));
|
||||
drd_dT = drd0T_dT + drd1T_dT * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage)));
|
||||
double drd_dT = drd0T_dT + drd1T_dT * (vdsn / (vdsn + fabs(model->VDMOSqsVoltage)));
|
||||
if (rd > 0) {
|
||||
here->VDMOSdrainConductance = 1 / rd + ckt->CKTgmin;
|
||||
dgdrain_dT = -drd_dT / (rd*rd);
|
||||
|
|
@ -451,10 +462,16 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
- here->VDMOSgtempT * delTemp;
|
||||
|
||||
Vrd = *(ckt->CKTrhsOld + here->VDMOSdNode) - *(ckt->CKTrhsOld + here->VDMOSdNodePrime);
|
||||
dIth_dVrd = here->VDMOSdrainConductance * Vrd;
|
||||
dIrd_dgdrain = Vrd;
|
||||
dIth_dVrd = here->VDMOSdrainConductance * 2 * Vrd;
|
||||
double dIrd_dgdrain = Vrd;
|
||||
dIrd_dT = dIrd_dgdrain * dgdrain_dT;
|
||||
here->VDMOScth += here->VDMOSdrainConductance * Vrd*Vrd - dIth_dVrd*Vrd - dIrd_dT*Vrd*delTemp;
|
||||
|
||||
Vrs = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDMOSsNodePrime);
|
||||
dIth_dVrs = here->VDMOSsourceConductance * 2 * Vrs;
|
||||
double dIrs_dgsource = Vrs;
|
||||
dIrs_dT = dIrs_dgsource * dgsource_dT;
|
||||
here->VDMOScth += here->VDMOSsourceConductance * Vrs*Vrs - dIth_dVrs*Vrs - dIrs_dT*Vrs*delTemp;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -475,7 +492,11 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
DevCapVDMOS(vgd, cgdmin, cgdmax, a, cgs,
|
||||
(ckt->CKTstate0 + here->VDMOScapgs),
|
||||
(ckt->CKTstate0 + here->VDMOScapgd));
|
||||
*(ckt->CKTstate0 + here->VDMOScapth) = model->VDMOScthj; /* always constant */
|
||||
/* Everything is computed for m parallel instances... so scale cthj accordingly
|
||||
* Also, take into account Meyer numerical integration style and
|
||||
* halve the value of cthj that gets stored in the state.
|
||||
*/
|
||||
*(ckt->CKTstate0 + here->VDMOScapth) = here->VDMOSm * model->VDMOScthj / 2; /* always constant */
|
||||
|
||||
vgs1 = *(ckt->CKTstate1 + here->VDMOSvgs);
|
||||
vgd1 = vgs1 - *(ckt->CKTstate1 + here->VDMOSvds);
|
||||
|
|
@ -558,8 +579,6 @@ bypass:
|
|||
{
|
||||
error = NIintegrate(ckt, &gcTt, &ceqqth, capth, here->VDMOSqth);
|
||||
if (error) return(error);
|
||||
ceqqth = ceqqth - gcTt*delTemp + ckt->CKTag[0] *
|
||||
*(ckt->CKTstate0 + here->VDMOSqth);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -606,13 +625,16 @@ bypass:
|
|||
*(ckt->CKTrhs + here->VDMOSsNodePrime) += cdreq + model->VDMOStype * ceqgs;
|
||||
if (selfheat) {
|
||||
*(ckt->CKTrhs + here->VDMOSdNode) += dIrd_dT * delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOSsNode) += dIrs_dT * delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOSdNodePrime) += GmT * delTemp - dIrd_dT * delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOSsNodePrime) += -GmT * delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOSsNodePrime) += -GmT * delTemp - dIrs_dT * delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOStempNode) += here->VDMOScth - ceqqth;
|
||||
double vCktTemp = (ckt->CKTtemp-CONSTCtoK); /* ckt temperature */
|
||||
double vDevTemp = (ckt->CKTtemp-CONSTCtoK); /* ckt temperature */
|
||||
if (here->VDMOStempGiven)
|
||||
vDevTemp = (here->VDMOStemp-CONSTCtoK); /* device temperature */
|
||||
if (ckt->CKTmode & MODETRANOP)
|
||||
vCktTemp *= ckt->CKTsrcFact;
|
||||
*(ckt->CKTrhs + here->VDMOSvcktTbranch)+= vCktTemp;
|
||||
vDevTemp *= ckt->CKTsrcFact;
|
||||
*(ckt->CKTrhs + here->VDMOSvdevTbranch)+= vDevTemp;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -649,24 +671,28 @@ bypass:
|
|||
|
||||
if (selfheat)
|
||||
{
|
||||
|
||||
/* Everything is computed for m parallel instances... so scale gthjc and gthja accordingly
|
||||
*/
|
||||
double gthjc = here->VDMOSm / model->VDMOSrthjc;
|
||||
double gthca = here->VDMOSm / model->VDMOSrthca;
|
||||
(*(here->VDMOSDtempPtr) += dIrd_dT);
|
||||
(*(here->VDMOSDPtempPtr) += GmT - dIrd_dT);
|
||||
(*(here->VDMOSSPtempPtr) += -GmT);
|
||||
(*(here->VDMOSGPtempPtr) += 0.0);
|
||||
(*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd + 1/model->VDMOSrthjc + gcTt);
|
||||
(*(here->VDMOSStempPtr) += dIrs_dT);
|
||||
(*(here->VDMOSSPtempPtr) += -GmT - dIrs_dT);
|
||||
(*(here->VDMOSTemptempPtr) += -gTtt - dIrd_dT*Vrd - dIrs_dT*Vrs + gthjc + gcTt);
|
||||
(*(here->VDMOSTempgpPtr) += -gTtg);
|
||||
(*(here->VDMOSTempdPtr) += -dIth_dVrd);
|
||||
(*(here->VDMOSTempsPtr) += -dIth_dVrs);
|
||||
(*(here->VDMOSTempdpPtr) += -gTtdp + dIth_dVrd);
|
||||
(*(here->VDMOSTempspPtr) += -gTtsp);
|
||||
(*(here->VDMOSTemptcasePtr) += -1/model->VDMOSrthjc);
|
||||
(*(here->VDMOSTcasetempPtr) += -1/model->VDMOSrthjc);
|
||||
(*(here->VDMOSTcasetcasePtr) += 1/model->VDMOSrthjc + 1/model->VDMOSrthca);
|
||||
(*(here->VDMOSTptpPtr) += 1/model->VDMOSrthca);
|
||||
(*(here->VDMOSTptcasePtr) += -1/model->VDMOSrthca);
|
||||
(*(here->VDMOSTcasetpPtr) += -1/model->VDMOSrthca);
|
||||
(*(here->VDMOSCktTtpPtr) += 1.0);
|
||||
(*(here->VDMOSTpcktTPtr) += 1.0);
|
||||
(*(here->VDMOSTempspPtr) += -gTtsp + dIth_dVrs);
|
||||
(*(here->VDMOSTemptcasePtr) += -gthjc);
|
||||
(*(here->VDMOSTcasetempPtr) += -gthjc);
|
||||
(*(here->VDMOSTcasetcasePtr) += gthjc + gthca);
|
||||
(*(here->VDMOSTptpPtr) += gthca);
|
||||
(*(here->VDMOSTptcasePtr) += -gthca);
|
||||
(*(here->VDMOSTcasetpPtr) += -gthca);
|
||||
(*(here->VDMOSDevTtpPtr) += 1.0);
|
||||
(*(here->VDMOSTpdevTPtr) += 1.0);
|
||||
}
|
||||
|
||||
/* body diode model
|
||||
|
|
@ -678,18 +704,18 @@ bypass:
|
|||
double vtebrk, vbrknp;
|
||||
double cdb, cdeq;
|
||||
double capd;
|
||||
double gd, gdb, gspr;
|
||||
double gd, gdb, gbpr;
|
||||
double delvd; /* change in diode voltage temporary */
|
||||
double evrev;
|
||||
double Ith=0.0, dIth_dT=0.0;
|
||||
double dIdio_dT=0.0, dIth_dVdio=0.0;
|
||||
double vrs=0.0, dIrs_dT=0.0, dIth_dVrs=0.0;
|
||||
double vrb=0.0, dIrb_dT=0.0, dIth_dVrb=0.0;
|
||||
|
||||
#ifndef NOBYPASS
|
||||
double tol; /* temporary for tolerance calculations */
|
||||
#endif
|
||||
|
||||
gspr = here->VDIOtConductance;
|
||||
gbpr = here->VDIOtConductance;
|
||||
|
||||
vt = CONSTKoverQ * Temp;
|
||||
vte = model->VDIOn * vt;
|
||||
|
|
@ -884,18 +910,18 @@ bypass:
|
|||
load:
|
||||
#endif
|
||||
if (selfheat) {
|
||||
double dIrs_dgspr, dIth_dIrs;
|
||||
vrs = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDIOposPrimeNode);
|
||||
double dIrb_dgbpr, dIth_dIrb;
|
||||
vrb = *(ckt->CKTrhsOld + here->VDMOSsNode) - *(ckt->CKTrhsOld + here->VDIOposPrimeNode);
|
||||
|
||||
Ith = vd*cd + vrs*vrs*gspr;
|
||||
Ith = vd*cd + vrb*vrb*gbpr;
|
||||
|
||||
dIth_dVdio = cd + vd*gd;
|
||||
dIth_dVrs = vrs*gspr;
|
||||
dIth_dVrb = vrb*gbpr;
|
||||
|
||||
dIrs_dgspr = vrs;
|
||||
dIrs_dT = dIrs_dgspr * here->VDIOtConductance_dT;
|
||||
dIth_dIrs = vrs;
|
||||
dIth_dT = dIth_dIrs*dIrs_dT + dIdio_dT*vd;
|
||||
dIrb_dgbpr = vrb;
|
||||
dIrb_dT = dIrb_dgbpr * here->VDIOtConductance_dT;
|
||||
dIth_dIrb = vrb;
|
||||
dIth_dT = dIth_dIrb*dIrb_dT + dIdio_dT*vd;
|
||||
}
|
||||
/*
|
||||
* load current vector
|
||||
|
|
@ -909,28 +935,28 @@ load:
|
|||
*(ckt->CKTrhs + here->VDIOposPrimeNode) += cdeq;
|
||||
}
|
||||
if (selfheat) {
|
||||
*(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrs_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->VDIOposPrimeNode) += dIdio_dT*delTemp - dIrb_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOSdNode) += -dIdio_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOSsNode) += dIrs_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd - dIth_dVrs*vrs - dIth_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOSsNode) += dIrb_dT*delTemp;
|
||||
*(ckt->CKTrhs + here->VDMOStempNode) += Ith - model->VDMOStype*dIth_dVdio*vd - dIth_dVrb*vrb - dIth_dT*delTemp;
|
||||
}
|
||||
/*
|
||||
* load matrix
|
||||
*/
|
||||
*(here->VDMOSSsPtr) += gspr;
|
||||
*(here->VDMOSSsPtr) += gbpr;
|
||||
*(here->VDMOSDdPtr) += gd;
|
||||
*(here->VDIORPrpPtr) += (gd + gspr);
|
||||
*(here->VDIOSrpPtr) -= gspr;
|
||||
*(here->VDIORPrpPtr) += (gd + gbpr);
|
||||
*(here->VDIOSrpPtr) -= gbpr;
|
||||
*(here->VDIODrpPtr) -= gd;
|
||||
*(here->VDIORPsPtr) -= gspr;
|
||||
*(here->VDIORPsPtr) -= gbpr;
|
||||
*(here->VDIORPdPtr) -= gd;
|
||||
if (selfheat) {
|
||||
(*(here->VDMOStempSPtr) += -dIth_dVrs);
|
||||
(*(here->VDIOTempposPrimePtr) += -dIth_dVdio + dIth_dVrs);
|
||||
(*(here->VDMOSTempsPtr) += -dIth_dVrb);
|
||||
(*(here->VDIOTempposPrimePtr) += -dIth_dVdio + dIth_dVrb);
|
||||
(*(here->VDMOSTempdPtr) += dIth_dVdio);
|
||||
(*(here->VDMOSTemptempPtr) += -dIth_dT);
|
||||
(*(here->VDIOPosPrimetempPtr) += dIdio_dT - dIrs_dT);
|
||||
(*(here->VDMOSSTempPtr) += dIrs_dT);
|
||||
(*(here->VDIOPosPrimetempPtr) += dIdio_dT - dIrb_dT);
|
||||
(*(here->VDMOSStempPtr) += dIrb_dT);
|
||||
(*(here->VDMOSDtempPtr) += -dIdio_dT);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,11 +110,12 @@ VDMOSnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt,
|
|||
NevalSrc(&noizDens[VDMOSFLNOIZ], NULL, ckt,
|
||||
N_GAIN,inst->VDMOSdNodePrime, inst->VDMOSsNodePrime,
|
||||
(double)0.0);
|
||||
// VDMOScd is scaled with m, no need to scale coxSquared (which is a constant)
|
||||
// Should be proportional to m
|
||||
noizDens[VDMOSFLNOIZ] *= model->VDMOSfNcoef *
|
||||
exp(model->VDMOSfNexp *
|
||||
log(MAX(fabs(inst->VDMOScd),N_MINLOG))) /
|
||||
(data->freq *
|
||||
inst->VDMOSm * coxSquared);
|
||||
(data->freq * coxSquared);
|
||||
lnNdens[VDMOSFLNOIZ] =
|
||||
log(MAX(noizDens[VDMOSFLNOIZ],N_MINLOG));
|
||||
|
||||
|
|
|
|||
|
|
@ -259,6 +259,13 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
|
|||
here->VDMOSstates = *states;
|
||||
*states += VDMOSnumStates;
|
||||
|
||||
if ((here->VDMOStempGiven) && (here->VDMOSdtempGiven)) {
|
||||
SPfrontEnd->IFerrorf(ERR_WARNING,
|
||||
"%s: temp and dtemp instance parameter given - using dtemp",
|
||||
here->VDMOSname);
|
||||
here->VDMOStempGiven = FALSE;
|
||||
}
|
||||
|
||||
if (!here->VDMOSicVDSGiven) {
|
||||
here->VDMOSicVDS = 0;
|
||||
}
|
||||
|
|
@ -409,10 +416,10 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt,
|
|||
if (error) return(error);
|
||||
here->VDMOStcaseNode = tmp->number;
|
||||
}
|
||||
if(here->VDMOSvcktTbranch == 0) {
|
||||
error = CKTmkCur(ckt,&tmp,here->VDMOSname,"VcktTemp");
|
||||
if(here->VDMOSvdevTbranch == 0) {
|
||||
error = CKTmkCur(ckt,&tmp,here->VDMOSname,"VdevTemp");
|
||||
if(error) return(error);
|
||||
here->VDMOSvcktTbranch = tmp->number;
|
||||
here->VDMOSvdevTbranch = tmp->number;
|
||||
}
|
||||
if (here->VDMOStNodePrime == 0) {
|
||||
error = CKTmkVolt(ckt, &tmp, here->VDMOSname, "cktTemp");
|
||||
|
|
@ -472,18 +479,18 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
|
|||
TSTALLOC(VDMOSTempdPtr, VDMOStempNode, VDMOSdNode);
|
||||
TSTALLOC(VDIOPosPrimetempPtr, VDIOposPrimeNode, VDMOStempNode);
|
||||
TSTALLOC(VDMOSDtempPtr, VDMOSdNode, VDMOStempNode);
|
||||
TSTALLOC(VDMOStempSPtr, VDMOStempNode, VDMOSsNode);
|
||||
TSTALLOC(VDMOSSTempPtr, VDMOSsNode, VDMOStempNode);
|
||||
TSTALLOC(VDMOSTempsPtr, VDMOStempNode, VDMOSsNode);
|
||||
TSTALLOC(VDMOSStempPtr, VDMOSsNode, VDMOStempNode);
|
||||
|
||||
TSTALLOC(VDMOSTcasetcasePtr, VDMOStcaseNode, VDMOStcaseNode); /* Rthjc between tj and tcase*/
|
||||
TSTALLOC(VDMOSTcasetempPtr, VDMOStcaseNode, VDMOStempNode);
|
||||
TSTALLOC(VDMOSTemptcasePtr, VDMOStempNode, VDMOStcaseNode);
|
||||
TSTALLOC(VDMOSTptpPtr, VDMOStNodePrime, VDMOStNodePrime); /* Rthca between tcase and Vsrc */
|
||||
TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStempNode);
|
||||
TSTALLOC(VDMOSTcasetpPtr, VDMOStempNode, VDMOStNodePrime);
|
||||
TSTALLOC(VDMOSCktTcktTPtr, VDMOSvcktTbranch, VDMOSvcktTbranch); /* Vsrc=cktTemp to gnd */
|
||||
TSTALLOC(VDMOSCktTtpPtr, VDMOSvcktTbranch, VDMOStNodePrime);
|
||||
TSTALLOC(VDMOSTpcktTPtr, VDMOStNodePrime, VDMOSvcktTbranch);
|
||||
TSTALLOC(VDMOSTptcasePtr, VDMOStNodePrime, VDMOStcaseNode);
|
||||
TSTALLOC(VDMOSTcasetpPtr, VDMOStcaseNode, VDMOStNodePrime);
|
||||
TSTALLOC(VDMOSDevTdevTPtr, VDMOSvdevTbranch, VDMOSvdevTbranch); /* Vsrc=cktTemp to gnd */
|
||||
TSTALLOC(VDMOSDevTtpPtr, VDMOSvdevTbranch, VDMOStNodePrime);
|
||||
TSTALLOC(VDMOSTpdevTPtr, VDMOStNodePrime, VDMOSvdevTbranch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -526,9 +533,9 @@ VDMOSunsetup(GENmodel *inModel, CKTcircuit *ckt)
|
|||
if (here->VDMOStNodePrime > 0)
|
||||
CKTdltNNum(ckt, here->VDMOStNodePrime);
|
||||
here->VDMOStNodePrime = 0;
|
||||
if (here->VDMOSvcktTbranch > 0)
|
||||
CKTdltNNum(ckt, here->VDMOSvcktTbranch);
|
||||
here->VDMOSvcktTbranch = 0;
|
||||
if (here->VDMOSvdevTbranch > 0)
|
||||
CKTdltNNum(ckt, here->VDMOSvdevTbranch);
|
||||
here->VDMOSvdevTbranch = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,9 +56,15 @@ void VDMOStempUpdate(VDMOSmodel *inModel, VDMOSinstance *here, double Temp, CKTc
|
|||
else
|
||||
here->VDMOSdrainResistance = model->VDMOSdrainResistance / here->VDMOSm * (1.0 + (model->VDMOStrd1 * dt) + (model->VDMOStrd2 * dt * dt));
|
||||
|
||||
here->VDMOSgateConductance = here->VDMOSgateConductance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt));
|
||||
if (model->VDMOSgateResistance > 0)
|
||||
here->VDMOSgateConductance = here->VDMOSm / model->VDMOSgateResistance / (1.0 + (model->VDMOStrg1 * dt) + (model->VDMOStrg2 * dt * dt));
|
||||
else
|
||||
here->VDMOSgateConductance = 0.0;
|
||||
|
||||
here->VDMOSsourceConductance = here->VDMOSsourceConductance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt));
|
||||
if (model->VDMOSsourceResistance > 0)
|
||||
here->VDMOSsourceConductance = here->VDMOSm / model->VDMOSsourceResistance / (1.0 + (model->VDMOStrs1 * dt) + (model->VDMOStrs2 * dt * dt));
|
||||
else
|
||||
here->VDMOSsourceConductance = 0.0;
|
||||
|
||||
if (model->VDMOSqsGiven)
|
||||
here->VDMOSqsResistance = model->VDMOSqsResistance / here->VDMOSm * pow(ratio, model->VDMOStexp1);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task)
|
|||
char *groundname = "0";
|
||||
char *gname;
|
||||
CKTnode *gnode;
|
||||
int error; /* used by the macros defined above */
|
||||
int error; /* used by the macros defined above */
|
||||
#ifdef HAS_PROGREP
|
||||
int linecount = 0, actcount = 0;
|
||||
#endif
|
||||
|
|
@ -45,28 +45,28 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task)
|
|||
#endif
|
||||
|
||||
error = INPgetTok(&groundname, &gname, 1);
|
||||
if (error)
|
||||
data->error =
|
||||
INPerrCat(data->error,
|
||||
INPmkTemp
|
||||
("can't read internal ground node name!\n"));
|
||||
|
||||
if (error) {
|
||||
data->error =
|
||||
INPerrCat(data->error,
|
||||
INPmkTemp
|
||||
("can't read internal ground node name!\n"));
|
||||
}
|
||||
error = INPgndInsert(ckt, &gname, tab, &gnode);
|
||||
if (error && error != E_EXISTS)
|
||||
data->error =
|
||||
INPerrCat(data->error,
|
||||
INPmkTemp
|
||||
("can't insert internal ground node in symbol table!\n"));
|
||||
|
||||
#ifdef TRACE
|
||||
if (error && error != E_EXISTS) {
|
||||
data->error =
|
||||
INPerrCat(data->error,
|
||||
INPmkTemp
|
||||
("can't insert internal ground node in symbol table!\n"));
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
printf("Examining this deck:\n");
|
||||
for (current = data; current != NULL; current = current->nextcard) {
|
||||
printf("%s\n", current->line);
|
||||
printf("%s\n", current->line);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAS_PROGREP
|
||||
for (current = data; current != NULL; current = current->nextcard)
|
||||
linecount++;
|
||||
|
|
@ -75,195 +75,195 @@ void INPpas2(CKTcircuit *ckt, struct card *data, INPtables * tab, TSKtask *task)
|
|||
for (current = data; current != NULL; current = current->nextcard) {
|
||||
|
||||
#ifdef TRACE
|
||||
/* SDB debug statement */
|
||||
printf("In INPpas2, examining card %s . . .\n", current->line);
|
||||
/* SDB debug statement */
|
||||
printf("In INPpas2, examining card %s . . .\n", current->line);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_PROGREP
|
||||
if (linecount > 0) {
|
||||
SetAnalyse( "Parse", (int) (1000.*actcount/linecount));
|
||||
actcount++;
|
||||
}
|
||||
if (linecount > 0) {
|
||||
SetAnalyse( "Parse", (int) (1000.*actcount/linecount));
|
||||
actcount++;
|
||||
}
|
||||
#endif
|
||||
|
||||
Current_parse_line = current->linenum_orig;
|
||||
Sourcefile = current->linesource;
|
||||
Current_parse_line = current->linenum_orig;
|
||||
Sourcefile = current->linesource;
|
||||
|
||||
c = *(current->line);
|
||||
if(islower_c(c))
|
||||
c = toupper_c(c);
|
||||
c = *(current->line);
|
||||
if(islower_c(c))
|
||||
c = toupper_c(c);
|
||||
|
||||
switch (c) {
|
||||
switch (c) {
|
||||
|
||||
case ' ':
|
||||
/* blank line (space leading) */
|
||||
case '\t':
|
||||
/* blank line (tab leading) */
|
||||
break;
|
||||
case ' ':
|
||||
/* blank line (space leading) */
|
||||
case '\t':
|
||||
/* blank line (tab leading) */
|
||||
break;
|
||||
|
||||
#ifdef XSPICE
|
||||
/* gtri - add - wbk - 10/23/90 - add case for 'A' devices */
|
||||
/* gtri - add - wbk - 10/23/90 - add case for 'A' devices */
|
||||
|
||||
case 'A': /* Aname <cm connections> <mname> */
|
||||
MIF_INP2A(ckt, tab, current);
|
||||
ckt->CKTadevFlag = 1; /* an 'A' device is requested */
|
||||
break;
|
||||
case 'A': /* Aname <cm connections> <mname> */
|
||||
MIF_INP2A(ckt, tab, current);
|
||||
ckt->CKTadevFlag = 1; /* an 'A' device is requested */
|
||||
break;
|
||||
|
||||
/* gtri - end - wbk - 10/23/90 */
|
||||
/* gtri - end - wbk - 10/23/90 */
|
||||
#endif
|
||||
|
||||
case 'R':
|
||||
/* Rname <node> <node> [<val>][<mname>][w=<val>][l=<val>] */
|
||||
INP2R(ckt, tab, current);
|
||||
break;
|
||||
case 'R':
|
||||
/* Rname <node> <node> [<val>][<mname>][w=<val>][l=<val>] */
|
||||
INP2R(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
/* Cname <node> <node> <val> [IC=<val>] */
|
||||
INP2C(ckt, tab, current);
|
||||
break;
|
||||
case 'C':
|
||||
/* Cname <node> <node> <val> [IC=<val>] */
|
||||
INP2C(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
/* Lname <node> <node> <val> [IC=<val>] */
|
||||
INP2L(ckt, tab, current);
|
||||
break;
|
||||
case 'L':
|
||||
/* Lname <node> <node> <val> [IC=<val>] */
|
||||
INP2L(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
/* Gname <node> <node> <node> <node> <val> */
|
||||
INP2G(ckt, tab, current);
|
||||
break;
|
||||
case 'G':
|
||||
/* Gname <node> <node> <node> <node> <val> */
|
||||
INP2G(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
/* Ename <node> <node> <node> <node> <val> */
|
||||
INP2E(ckt, tab, current);
|
||||
break;
|
||||
case 'E':
|
||||
/* Ename <node> <node> <node> <node> <val> */
|
||||
INP2E(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
/* Fname <node> <node> <vname> <val> */
|
||||
INP2F(ckt, tab, current);
|
||||
break;
|
||||
case 'F':
|
||||
/* Fname <node> <node> <vname> <val> */
|
||||
INP2F(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
/* Hname <node> <node> <vname> <val> */
|
||||
INP2H(ckt, tab, current);
|
||||
break;
|
||||
case 'H':
|
||||
/* Hname <node> <node> <vname> <val> */
|
||||
INP2H(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
/* Dname <node> <node> <model> [<val>] [OFF] [IC=<val>] */
|
||||
INP2D(ckt, tab, current);
|
||||
break;
|
||||
case 'D':
|
||||
/* Dname <node> <node> <model> [<val>] [OFF] [IC=<val>] */
|
||||
INP2D(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
/* Jname <node> <node> <node> <model> [<val>] [OFF]
|
||||
case 'J':
|
||||
/* Jname <node> <node> <node> <model> [<val>] [OFF]
|
||||
[IC=<val>,<val>] */
|
||||
INP2J(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
/* Zname <node> <node> <node> <model> [<val>] [OFF]
|
||||
[IC=<val>,<val>] */
|
||||
INP2J(ckt, tab, current);
|
||||
break;
|
||||
INP2Z(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
/* Zname <node> <node> <node> <model> [<val>] [OFF]
|
||||
[IC=<val>,<val>] */
|
||||
INP2Z(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
/* Mname <node> <node> <node> <node> <model> [L=<val>]
|
||||
[W=<val>] [AD=<val>] [AS=<val>] [PD=<val>]
|
||||
[PS=<val>] [NRD=<val>] [NRS=<val>] [OFF]
|
||||
[IC=<val>,<val>,<val>] */
|
||||
INP2M(ckt, tab, current);
|
||||
break;
|
||||
case 'M':
|
||||
/* Mname <node> <node> <node> <node> <model> [L=<val>]
|
||||
[W=<val>] [AD=<val>] [AS=<val>] [PD=<val>]
|
||||
[PS=<val>] [NRD=<val>] [NRS=<val>] [OFF]
|
||||
[IC=<val>,<val>,<val>] */
|
||||
INP2M(ckt, tab, current);
|
||||
break;
|
||||
#ifdef OSDI
|
||||
case 'N':
|
||||
/* Nname [<node>...] [<mname>] */
|
||||
INP2N(ckt, tab, current);
|
||||
break;
|
||||
case 'N':
|
||||
/* Nname [<node>...] [<mname>] */
|
||||
INP2N(ckt, tab, current);
|
||||
break;
|
||||
#endif
|
||||
case 'O':
|
||||
/* Oname <node> <node> <node> <node> <model>
|
||||
[IC=<val>,<val>,<val>,<val>] */
|
||||
INP2O(ckt, tab, current);
|
||||
break;
|
||||
case 'O':
|
||||
/* Oname <node> <node> <node> <node> <model>
|
||||
[IC=<val>,<val>,<val>,<val>] */
|
||||
INP2O(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
/* Vname <node> <node> [ [DC] <val>] [AC [<val> [<val> ] ] ]
|
||||
[<tran function>] */
|
||||
INP2V(ckt, tab, current);
|
||||
break;
|
||||
case 'V':
|
||||
/* Vname <node> <node> [ [DC] <val>] [AC [<val> [<val> ] ] ]
|
||||
[<tran function>] */
|
||||
INP2V(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
/* Iname <node> <node> [ [DC] <val>] [AC [<val> [<val> ] ] ]
|
||||
[<tran function>] */
|
||||
INP2I(ckt, tab, current);
|
||||
break;
|
||||
case 'I':
|
||||
/* Iname <node> <node> [ [DC] <val>] [AC [<val> [<val> ] ] ]
|
||||
[<tran function>] */
|
||||
INP2I(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
/* Qname <node> <node> <node> [<node>] <model> [<val>] [OFF]
|
||||
[IC=<val>,<val>] */
|
||||
INP2Q(ckt, tab, current, gnode);
|
||||
break;
|
||||
case 'Q':
|
||||
/* Qname <node> <node> <node> [<node>] <model> [<val>] [OFF]
|
||||
[IC=<val>,<val>] */
|
||||
INP2Q(ckt, tab, current, gnode);
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
/* Tname <node> <node> <node> <node> [TD=<val>]
|
||||
[F=<val> [NL=<val>]][IC=<val>,<val>,<val>,<val>] */
|
||||
INP2T(ckt, tab, current);
|
||||
break;
|
||||
case 'T':
|
||||
/* Tname <node> <node> <node> <node> [TD=<val>]
|
||||
[F=<val> [NL=<val>]][IC=<val>,<val>,<val>,<val>] */
|
||||
INP2T(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
/* Sname <node> <node> <node> <node> [<modname>] [IC] */
|
||||
INP2S(ckt, tab, current);
|
||||
break;
|
||||
case 'S':
|
||||
/* Sname <node> <node> <node> <node> [<modname>] [IC] */
|
||||
INP2S(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
/* Wname <node> <node> <vctrl> [<modname>] [IC] */
|
||||
/* CURRENT CONTROLLED SWITCH */
|
||||
INP2W(ckt, tab, current);
|
||||
break;
|
||||
case 'W':
|
||||
/* Wname <node> <node> <vctrl> [<modname>] [IC] */
|
||||
/* CURRENT CONTROLLED SWITCH */
|
||||
INP2W(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
/* Uname <node> <node> <model> [l=<val>] [n=<val>] */
|
||||
INP2U(ckt, tab, current);
|
||||
break;
|
||||
case 'U':
|
||||
/* Uname <node> <node> <model> [l=<val>] [n=<val>] */
|
||||
INP2U(ckt, tab, current);
|
||||
break;
|
||||
|
||||
/* Kspice addition - saj */
|
||||
case 'P':
|
||||
/* Pname <node> <node> ... <gnd> <node> <node> ... <gnd> [<modname>] */
|
||||
/* R=<vector> L=<matrix> G=<vector> C=<matrix> len=<val> */
|
||||
INP2P(ckt, tab, current);
|
||||
break;
|
||||
case 'Y':
|
||||
/* Yname <node> <node> R=<val> L=<val> G=<val> C=<val> len=<val> */
|
||||
INP2Y(ckt, tab, current);
|
||||
break;
|
||||
/* end Kspice */
|
||||
/* Kspice addition - saj */
|
||||
case 'P':
|
||||
/* Pname <node> <node> ... <gnd> <node> <node> ... <gnd> [<modname>] */
|
||||
/* R=<vector> L=<matrix> G=<vector> C=<matrix> len=<val> */
|
||||
INP2P(ckt, tab, current);
|
||||
break;
|
||||
case 'Y':
|
||||
/* Yname <node> <node> R=<val> L=<val> G=<val> C=<val> len=<val> */
|
||||
INP2Y(ckt, tab, current);
|
||||
break;
|
||||
/* end Kspice */
|
||||
|
||||
case 'K':
|
||||
/* Kname Lname Lname <val> */
|
||||
INP2K(ckt, tab, current);
|
||||
break;
|
||||
case 'K':
|
||||
/* Kname Lname Lname <val> */
|
||||
INP2K(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case '*': case '$':
|
||||
/* *<anything> - a comment - ignore */
|
||||
break;
|
||||
case '*': case '$':
|
||||
/* *<anything> - a comment - ignore */
|
||||
break;
|
||||
|
||||
case 'B':
|
||||
/* Bname <node> <node> [V=expr] [I=expr] */
|
||||
/* Arbitrary source. */
|
||||
INP2B(ckt, tab, current);
|
||||
break;
|
||||
case 'B':
|
||||
/* Bname <node> <node> [V=expr] [I=expr] */
|
||||
/* Arbitrary source. */
|
||||
INP2B(ckt, tab, current);
|
||||
break;
|
||||
|
||||
case '.': /* .<something> Many possibilities */
|
||||
if (INP2dot(ckt,tab,current,task,gnode))
|
||||
return;
|
||||
break;
|
||||
case '.': /* .<something> Many possibilities */
|
||||
if (INP2dot(ckt,tab,current,task,gnode))
|
||||
return;
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
|
||||
default:
|
||||
/* the un-implemented device */
|
||||
LITERR(" unknown device type - error \n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
default:
|
||||
/* the un-implemented device */
|
||||
LITERR(" unknown device type - error \n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ EXTRA_DIST = README examples icm xspice.c .gitignore \
|
|||
tlines/msline_common.c tlines/msline_common.h \
|
||||
tlines/tline_common.c tlines/tline_common.h
|
||||
|
||||
SUBDIRS = mif cm enh evt ipc idn cmpp icm verilog vhdl
|
||||
SUBDIRS = mif cm enh evt idn cmpp icm verilog vhdl
|
||||
|
||||
dist-hook:
|
||||
rm -f "$(distdir)/icm/makedefs"
|
||||
|
|
|
|||
|
|
@ -53,10 +53,6 @@ NON-STANDARD FEATURES
|
|||
#include "ngspice/evtproto.h"
|
||||
#include "ngspice/evtudn.h"
|
||||
|
||||
#include "ngspice/ipc.h"
|
||||
#include "ngspice/ipctiein.h"
|
||||
#include "ngspice/ipcproto.h"
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
/* global flag, TRUE if callback is used */
|
||||
extern bool wantevtdata;
|
||||
|
|
@ -76,13 +72,6 @@ static void EVTsharedsend_line(
|
|||
int mode); /* mode (op, dc, tran) we are in */
|
||||
#endif
|
||||
|
||||
static void EVTsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
double step, /* The analysis step */
|
||||
void *node_value, /* The node value */
|
||||
int udn_index); /* The user-defined node index */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTdump
|
||||
|
|
@ -129,250 +118,25 @@ void EVTdump(
|
|||
double step) /* The sweep step for a DCTRCURVE analysis, or */
|
||||
/* 0.0 for DCOP and TRAN */
|
||||
{
|
||||
static evtdump_dict_t *node_dict = NULL;
|
||||
static int num_send_nodes;
|
||||
|
||||
int i;
|
||||
int j;
|
||||
int num_nodes;
|
||||
int num_modified;
|
||||
int index;
|
||||
|
||||
char *name;
|
||||
int name_len;
|
||||
|
||||
Mif_Boolean_t firstcall;
|
||||
|
||||
Evt_Node_Data_t *node_data;
|
||||
|
||||
Evt_Node_t *rhsold;
|
||||
Evt_Node_t **head;
|
||||
Evt_Node_t *here;
|
||||
|
||||
Evt_Node_Info_t **node_table;
|
||||
|
||||
char buff[10000];
|
||||
|
||||
Mif_Boolean_t equal;
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
if((! g_ipc.enabled) && (!wantevtdata))
|
||||
if (!wantevtdata)
|
||||
return;
|
||||
if ((!g_ipc.enabled) && (wantevtdata)) {
|
||||
else {
|
||||
EVTshareddump(ckt, mode, step);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
/* Return immediately if IPC is not enabled */
|
||||
if(! g_ipc.enabled)
|
||||
return;
|
||||
(void)*ckt;
|
||||
(void)mode;
|
||||
(void)step;
|
||||
|
||||
/* Return immediately */
|
||||
return;
|
||||
#endif
|
||||
/* Get number of event-driven nodes */
|
||||
num_nodes = ckt->evt->counts.num_nodes;
|
||||
|
||||
/* Exit immediately if no event-driven nodes in circuit */
|
||||
if(num_nodes <= 0)
|
||||
return;
|
||||
|
||||
|
||||
/* Get pointers for fast access to event data */
|
||||
node_data = ckt->evt->data.node;
|
||||
node_table = ckt->evt->info.node_table;
|
||||
rhsold = node_data->rhsold;
|
||||
head = node_data->head;
|
||||
|
||||
|
||||
/* Determine if this is the first call */
|
||||
if(node_dict == NULL)
|
||||
firstcall = MIF_TRUE;
|
||||
else
|
||||
firstcall = MIF_FALSE;
|
||||
|
||||
|
||||
/* If this is the first call, get the dictionary info */
|
||||
if(firstcall) {
|
||||
|
||||
/* Allocate local data structure used to process nodes */
|
||||
node_dict = TMALLOC(evtdump_dict_t, num_nodes);
|
||||
|
||||
/* Loop through all nodes to determine which nodes should be sent. */
|
||||
/* Only nodes not within subcircuits qualify. */
|
||||
|
||||
num_send_nodes = 0;
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
|
||||
/* Get the name of the node. */
|
||||
name = node_table[i]->name;
|
||||
|
||||
/* If name is in a subcircuit, mark that node should not be sent */
|
||||
/* and continue to next node. */
|
||||
name_len = (int) strlen(name);
|
||||
for(j = 0; j < name_len; j++) {
|
||||
if(name[j] == ':')
|
||||
break;
|
||||
}
|
||||
if(j < name_len) {
|
||||
node_dict[i].send = MIF_FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Otherwise, fill in info in dictionary. */
|
||||
node_dict[i].send = MIF_TRUE;
|
||||
node_dict[i].ipc_index = num_send_nodes;
|
||||
node_dict[i].node_name_str = name;
|
||||
node_dict[i].udn_type_str = g_evt_udn_info[node_table[i]->udn_index]->name;
|
||||
|
||||
/* Increment the count of nodes to be sent. */
|
||||
num_send_nodes++;
|
||||
} /* end for */
|
||||
} /* end if first call */
|
||||
|
||||
|
||||
/* Exit if there are no nodes to be sent */
|
||||
if(num_send_nodes <= 0)
|
||||
return;
|
||||
|
||||
|
||||
/* If this is the first call, send the dictionary */
|
||||
if(firstcall) {
|
||||
ipc_send_evtdict_prefix();
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
if(node_dict[i].send) {
|
||||
sprintf(buff, "%d %s %s", node_dict[i].ipc_index,
|
||||
node_dict[i].node_name_str,
|
||||
node_dict[i].udn_type_str);
|
||||
ipc_send_line(buff);
|
||||
}
|
||||
}
|
||||
ipc_send_evtdict_suffix();
|
||||
}
|
||||
|
||||
/* If this is the first call, send the operating point solution */
|
||||
/* and return. */
|
||||
if(firstcall) {
|
||||
ipc_send_evtdata_prefix();
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
if(node_dict[i].send) {
|
||||
EVTsend_line(node_dict[i].ipc_index,
|
||||
step,
|
||||
rhsold[i].node_value,
|
||||
node_table[i]->udn_index);
|
||||
}
|
||||
}
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, this must be DCTRCURVE or TRAN mode and we need to */
|
||||
/* send only stuff that has changed since the last call. */
|
||||
/* The determination of what to send is modeled after code in */
|
||||
/* EVTop_save() for DCTRCURVE and EVTaccept() for TRAN. */
|
||||
|
||||
if(mode == IPC_ANAL_DCTRCURVE) {
|
||||
/* Send data prefix */
|
||||
ipc_send_evtdata_prefix();
|
||||
/* Loop through event nodes */
|
||||
for(i = 0; i < num_nodes; i++) {
|
||||
/* If dictionary indicates this node should be sent */
|
||||
if(node_dict[i].send) {
|
||||
/* Locate end of node data */
|
||||
here = head[i];
|
||||
for(;;) {
|
||||
if(here->next)
|
||||
here = here->next;
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* Compare entry at end of list to rhsold */
|
||||
g_evt_udn_info[node_table[i]->udn_index]->compare (
|
||||
rhsold[i].node_value,
|
||||
here->node_value,
|
||||
&equal);
|
||||
/* If value in rhsold is different, send it */
|
||||
if(!equal) {
|
||||
EVTsend_line(node_dict[i].ipc_index,
|
||||
step,
|
||||
rhsold[i].node_value,
|
||||
node_table[i]->udn_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send data suffix and return */
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(mode == IPC_ANAL_TRAN) {
|
||||
/* Send data prefix */
|
||||
ipc_send_evtdata_prefix();
|
||||
/* Loop through list of nodes modified since last time */
|
||||
num_modified = node_data->num_modified;
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
/* Get the index of the node modified */
|
||||
index = node_data->modified_index[i];
|
||||
/* If dictionary indicates this node should be sent */
|
||||
if(node_dict[index].send) {
|
||||
/* Scan through new events and send the data for each event */
|
||||
here = *(node_data->last_step[index]);
|
||||
while((here = here->next) != NULL) {
|
||||
EVTsend_line(node_dict[index].ipc_index,
|
||||
here->step,
|
||||
here->node_value,
|
||||
node_table[index]->udn_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Send data suffix and return */
|
||||
ipc_send_evtdata_suffix();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
EVTsend_line
|
||||
|
||||
This function formats the event node data and sends it to the IPC channel.
|
||||
*/
|
||||
|
||||
|
||||
static void EVTsend_line(
|
||||
int ipc_index, /* The index used in the dictionary */
|
||||
double step, /* The analysis step */
|
||||
void *node_value, /* The node value */
|
||||
int udn_index) /* The user-defined node index */
|
||||
{
|
||||
double dvalue;
|
||||
char *svalue;
|
||||
void *pvalue;
|
||||
int len;
|
||||
|
||||
/* Get the data to send */
|
||||
if(g_evt_udn_info[udn_index]->plot_val)
|
||||
g_evt_udn_info[udn_index]->plot_val (node_value, "", &dvalue);
|
||||
else
|
||||
dvalue = 0.0;
|
||||
|
||||
if(g_evt_udn_info[udn_index]->print_val)
|
||||
g_evt_udn_info[udn_index]->print_val (node_value, "", &svalue);
|
||||
else
|
||||
svalue = "";
|
||||
|
||||
if(g_evt_udn_info[udn_index]->ipc_val)
|
||||
g_evt_udn_info[udn_index]->ipc_val (node_value, &pvalue, &len);
|
||||
else {
|
||||
pvalue = NULL;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
/* Send it to the IPC channel */
|
||||
ipc_send_event(ipc_index, step, dvalue, svalue, pvalue, len);
|
||||
}
|
||||
|
||||
|
||||
#ifdef SHARED_MODULE
|
||||
static void EVTshareddump(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
## Process this file with automake to produce Makefile.in
|
||||
#
|
||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
||||
|
||||
noinst_LTLIBRARIES = libipcxsp.la
|
||||
|
||||
libipcxsp_la_SOURCES = \
|
||||
ipcaegis.c \
|
||||
ipc.c \
|
||||
ipcsockets.c \
|
||||
ipcstdio.c \
|
||||
ipctiein.c
|
||||
|
||||
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices
|
||||
AM_CFLAGS = $(STATIC)
|
||||
|
||||
MAINTAINERCLEANFILES = Makefile.in
|
||||
|
|
@ -1,978 +0,0 @@
|
|||
/*============================================================================
|
||||
FILE IPC.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Public Domain
|
||||
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
6/13/92 Bill Kuhn Added some comments
|
||||
|
||||
SUMMARY
|
||||
|
||||
Provides compatibility for the new SPICE simulator to both the MSPICE user
|
||||
interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE
|
||||
v.2 Simulator Interface and BCP (via Bsd Sockets).
|
||||
|
||||
The Interprocess Communications package provides functions
|
||||
called to receive XSPICE decks from the ATESSE Simulator Interface
|
||||
or Batch Control processes, and to return results to those
|
||||
processes. Functions callable from the simulator packages include:
|
||||
|
||||
ipc_initialize_server
|
||||
ipc_terminate_server
|
||||
ipc_get_line
|
||||
ipc_send_line
|
||||
ipc_send_data_prefix
|
||||
ipc_send_data_suffix
|
||||
ipc_send_dcop_prefix
|
||||
ipc_send_dcop_suffix
|
||||
ipc_send_evtdict_prefix
|
||||
ipc_send_evtdict_suffix
|
||||
ipc_send_evtdata_prefix
|
||||
ipc_send_evtdata_suffix
|
||||
ipc_send_errchk
|
||||
ipc_send_end
|
||||
ipc_send_boolean
|
||||
ipc_send_int
|
||||
ipc_send_double
|
||||
ipc_send_complex
|
||||
ipc_send_event
|
||||
ipc_flush
|
||||
|
||||
These functions communicate with a set of transport-level functions
|
||||
that implement the interprocess communications under one of
|
||||
the following protocol types determined by a compile-time option:
|
||||
|
||||
BSD UNIX Sockets
|
||||
HP/Apollo Mailboxes
|
||||
|
||||
For each transport protocol, the following functions are written:
|
||||
|
||||
ipc_transport_initialize_server
|
||||
ipc_transport_get_line
|
||||
ipc_transport_terminate_server
|
||||
ipc_transport_send_line
|
||||
|
||||
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include "ngspice/memory.h" /* NOTE: I think this is a Sys5ism (there is not man
|
||||
* page for it under Bsd, but it's in /usr/include
|
||||
* and it has a BSD copyright header. Go figure.
|
||||
*/
|
||||
|
||||
#include "ngspice/ipc.h"
|
||||
#include "ngspice/ipctiein.h"
|
||||
#include "ngspice/ipcproto.h"
|
||||
|
||||
|
||||
/*
|
||||
* Conditional compilation sanity check:
|
||||
*/
|
||||
#if !defined (IPC_AEGIS_MAILBOXES) && !defined (IPC_UNIX_SOCKETS)\
|
||||
&& !defined (IPC_DEBUG_VIA_STDIO)
|
||||
" compiler error - must specify a transport mechanism";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* static 'globals'
|
||||
*/
|
||||
|
||||
/* typedef unsigned char Buffer_Char_t; */
|
||||
typedef char Buffer_Char_t;
|
||||
|
||||
#define OUT_BUFFER_SIZE 1000
|
||||
#define MAX_NUM_RECORDS 200
|
||||
static int end_of_record_index [MAX_NUM_RECORDS];
|
||||
static int num_records;
|
||||
static Buffer_Char_t out_buffer [OUT_BUFFER_SIZE];
|
||||
static int fill_count;
|
||||
|
||||
static Ipc_Mode_t mode;
|
||||
static Ipc_Protocol_t protocol;
|
||||
static Ipc_Boolean_t end_of_deck_seen;
|
||||
static int batch_fd;
|
||||
|
||||
#define FMT_BUFFER_SIZE 80
|
||||
static char fmt_buffer [FMT_BUFFER_SIZE];
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
Ipc_Boolean_t
|
||||
kw_match (char *keyword, char *str)
|
||||
/*
|
||||
* returns IPC_TRUE if the first `strlen(keyword)' characters of `str' match
|
||||
* the ones in `keyword' - case sensitive
|
||||
*/
|
||||
{
|
||||
char *k = keyword;
|
||||
char *s = str;
|
||||
|
||||
/*
|
||||
* quit if we run off the end of either string:
|
||||
*/
|
||||
while (*s && *k) {
|
||||
if (*s != *k) {
|
||||
return IPC_FALSE;
|
||||
}
|
||||
s++;
|
||||
k++;
|
||||
}
|
||||
/*
|
||||
* if we get this far, it sould be because we ran off the end of the
|
||||
* keyword else we didn't match:
|
||||
*/
|
||||
return (*k == '\0');
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_initialize_server
|
||||
|
||||
This function creates the interprocess communication channel
|
||||
server mailbox or socket.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_initialize_server (
|
||||
char *server_name, /* Mailbox path or host/portnumber pair */
|
||||
Ipc_Mode_t m, /* Interactive or batch */
|
||||
Ipc_Protocol_t p ) /* Type of IPC protocol */
|
||||
/*
|
||||
* For mailboxes, `server_name' would be the mailbox pathname; for
|
||||
* sockets, this needs to be a host/portnumber pair. Maybe this should be
|
||||
* automatically generated by the routine...
|
||||
*/
|
||||
{
|
||||
Ipc_Status_t status;
|
||||
char batch_filename [1025];
|
||||
|
||||
mode = m;
|
||||
protocol = p;
|
||||
end_of_deck_seen = IPC_FALSE;
|
||||
|
||||
num_records = 0;
|
||||
fill_count = 0;
|
||||
|
||||
status = ipc_transport_initialize_server (server_name, m, p,
|
||||
batch_filename);
|
||||
|
||||
if (status != IPC_STATUS_OK) {
|
||||
fprintf (stderr, "ERROR: IPC: error initializing server\n");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (mode == IPC_MODE_BATCH) {
|
||||
#ifdef IPC_AEGIS_MAILBOXES
|
||||
strcat (batch_filename, ".log");
|
||||
#endif
|
||||
batch_fd = open (batch_filename, O_WRONLY | O_CREAT, 0666);
|
||||
if (batch_fd < 0) {
|
||||
/* fprintf (stderr, "ERROR: IPC: Error opening batch output file: %s\n",batch_filename); */
|
||||
perror ("IPC");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_terminate_server
|
||||
|
||||
This function deallocates the interprocess communication channel
|
||||
mailbox or socket.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_terminate_server (void)
|
||||
{
|
||||
return ipc_transport_terminate_server ();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_get_line
|
||||
|
||||
This function gets a SPICE deck input line from the interprocess
|
||||
communication channel. Any special control commands in the deck
|
||||
beginning with a ``>'' or ``#'' character are processed internally by
|
||||
this function and not returned to SPICE.
|
||||
*/
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_get_line (
|
||||
char *str, /* Text retrieved from IPC channel */
|
||||
int *len, /* Length of text string */
|
||||
Ipc_Wait_t wait ) /* Select blocking or non-blocking */
|
||||
/*
|
||||
* Reads one SPICE line from the connection. Strips any control lines
|
||||
* which cannot be interpretted by the simulator (e.g. >INQCON) and
|
||||
* processes them. If such a line is read, it is processed and the next
|
||||
* line is read. `ipc_get_line' does not return until a non-interceptable
|
||||
* line is read or end of file.
|
||||
*
|
||||
* If `wait' is IPC_NO_WAIT and there is no data available on the
|
||||
* connection, `ipc_get_line' returns IPC_STATUS_NO_DATA. If `wait' is
|
||||
* IPC_WAIT, `ipc_get_line' will not return until there is data available
|
||||
* or and end of file condition is reached or an error occurs.
|
||||
*
|
||||
* Intercepts and processes the following commands:
|
||||
* #RETURNI, #MINTIME, #VTRANS,
|
||||
* >PAUSE, >CONT, >STOP, >INQCON, >NETLIST, >ENDNET
|
||||
* Other > records are silently ignored.
|
||||
*
|
||||
* Intercepts old-style .TEMP card generated by MSPICE
|
||||
*
|
||||
* Returns:
|
||||
* IPC_STATUS_OK - for successful reads
|
||||
* IPC_STATUS_NO_DATA - when NO_WAIT and no data available
|
||||
* IPC_STATUS_END_OF_DECK - at end of deck (>ENDNET seen)
|
||||
* IPC_STATUS_ERROR - otherwise
|
||||
*/
|
||||
{
|
||||
Ipc_Status_t status;
|
||||
Ipc_Boolean_t need_another = IPC_TRUE;
|
||||
|
||||
do {
|
||||
|
||||
status = ipc_transport_get_line (str, len, wait);
|
||||
|
||||
switch (status) {
|
||||
case IPC_STATUS_NO_DATA:
|
||||
case IPC_STATUS_ERROR:
|
||||
need_another = IPC_FALSE;
|
||||
break;
|
||||
case IPC_STATUS_END_OF_DECK:
|
||||
assert (0); /* should never get this from the low-level get-line */
|
||||
status = IPC_STATUS_ERROR;
|
||||
need_another = IPC_FALSE;
|
||||
break;
|
||||
case IPC_STATUS_OK:
|
||||
/*
|
||||
* Got a good line - check to see if it's one of the ones we need to
|
||||
* intercept
|
||||
*/
|
||||
if (str[0] == '>') {
|
||||
if (kw_match (">STOP", str)) {
|
||||
ipc_handle_stop();
|
||||
} else if (kw_match (">PAUSE", str)) {
|
||||
/* assert (need_another); */
|
||||
/*
|
||||
* once more around the loop to do a blocking wait for the >CONT
|
||||
*/
|
||||
need_another = IPC_TRUE;
|
||||
wait = IPC_WAIT;
|
||||
} else if (kw_match (">INQCON", str)) {
|
||||
ipc_send_line (">ABRTABL");
|
||||
ipc_send_line (">PAUSABL");
|
||||
ipc_send_line (">KEEPABL");
|
||||
status = ipc_flush ();
|
||||
if (IPC_STATUS_OK != status) {
|
||||
need_another = IPC_FALSE;
|
||||
}
|
||||
} else if (kw_match (">ENDNET", str)) {
|
||||
end_of_deck_seen = IPC_TRUE;
|
||||
need_another = IPC_FALSE;
|
||||
status = IPC_STATUS_END_OF_DECK;
|
||||
} else {
|
||||
/* silently ignore */
|
||||
}
|
||||
} else if (str[0] == '#') {
|
||||
if (kw_match ("#RETURNI", str)) {
|
||||
ipc_handle_returni ();
|
||||
} else if (kw_match ("#MINTIME", str)) {
|
||||
double d1/*,d2*/;
|
||||
if (1 != sscanf (&str[8], "%lg", &d1)) {
|
||||
status = IPC_STATUS_ERROR;
|
||||
need_another = IPC_FALSE;
|
||||
} else {
|
||||
ipc_handle_mintime (d1);
|
||||
}
|
||||
} else if (kw_match ("#VTRANS", str)) {
|
||||
char *tok1;
|
||||
char *tok2;
|
||||
char *tok3;
|
||||
|
||||
tok1 = &str[8];
|
||||
for (tok2 = tok1; *tok2; tok2++) {
|
||||
if (isspace_c(*tok2)) {
|
||||
*tok2 = '\0';
|
||||
tok2++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(tok3 = tok2; *tok3; tok3++) {
|
||||
if(isspace_c(*tok3)) {
|
||||
*tok3 = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
ipc_handle_vtrans (tok1, tok2);
|
||||
} else {
|
||||
/* silently ignore */
|
||||
}
|
||||
} else if (str[0] == '.') {
|
||||
if (kw_match (".TEMP", str)) {
|
||||
/* don't pass .TEMP card to caller */
|
||||
printf("Old-style .TEMP card found - ignored\n");
|
||||
}
|
||||
else {
|
||||
/* pass all other . cards to the caller */
|
||||
need_another = IPC_FALSE;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Not a '>' or '#' record - let the caller deal with it
|
||||
*/
|
||||
need_another = IPC_FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* some unknown status value!
|
||||
*/
|
||||
assert (0);
|
||||
status = IPC_STATUS_ERROR;
|
||||
need_another = IPC_FALSE;
|
||||
break;
|
||||
}
|
||||
} while (need_another);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_flush
|
||||
|
||||
This function flushes the interprocess communication channel
|
||||
buffer contents.
|
||||
*/
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_flush (void)
|
||||
/*
|
||||
* Flush all buffered messages out the connection.
|
||||
*/
|
||||
{
|
||||
Ipc_Status_t status;
|
||||
int last = 0;
|
||||
/*int bytes;*/
|
||||
int i;
|
||||
|
||||
/* if batch mode */
|
||||
if (mode == IPC_MODE_BATCH) {
|
||||
|
||||
assert (batch_fd >= 0);
|
||||
|
||||
/* for number of records in buffer */
|
||||
for (i = 0; i < num_records; i++) {
|
||||
|
||||
/* write the records to the .log file */
|
||||
if ((end_of_record_index [i] - last) !=
|
||||
write (batch_fd, &out_buffer[last], (size_t) (end_of_record_index [i] - last))) {
|
||||
/* fprintf (stderr,"ERROR: IPC: Error writing to batch output file\n"); */
|
||||
perror ("IPC");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/* If the record is one of the batch simulation status messages, */
|
||||
/* send it over the ipc channel too */
|
||||
if( kw_match("#ERRCHK", &out_buffer[last]) ||
|
||||
kw_match(">ENDANAL", &out_buffer[last]) ||
|
||||
kw_match(">ABORTED", &out_buffer[last]) ) {
|
||||
|
||||
status = ipc_transport_send_line (&out_buffer[last],
|
||||
end_of_record_index [i] - last);
|
||||
if (IPC_STATUS_OK != status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
last = end_of_record_index [i];
|
||||
}
|
||||
|
||||
/* else, must be interactive mode */
|
||||
} else {
|
||||
/* send the full buffer over the ipc channel */
|
||||
status = ipc_transport_send_line (&out_buffer[0],
|
||||
end_of_record_index [num_records - 1]);
|
||||
if (IPC_STATUS_OK != status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/* reset counts to zero and return */
|
||||
num_records = 0;
|
||||
fill_count = 0;
|
||||
return IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
Ipc_Status_t
|
||||
ipc_send_line_binary (
|
||||
char *str,
|
||||
int len )
|
||||
/*
|
||||
* Same as `ipc_send_line' except does not expect the str to be null
|
||||
* terminated. Sends exactly `len' characters. Use this for binary data
|
||||
* strings that may have embedded nulls.
|
||||
*
|
||||
* Modified by wbk to append newlines for compatibility with
|
||||
* ATESSE 1.0
|
||||
*
|
||||
*/
|
||||
{
|
||||
int length = len + 1;
|
||||
/*int diff;*/
|
||||
Ipc_Status_t status;
|
||||
|
||||
/*
|
||||
* If we can't add the whole str to the buffer, or if there are no more
|
||||
* record indices free, flush the buffer:
|
||||
*/
|
||||
if (((fill_count + length) >= OUT_BUFFER_SIZE) ||
|
||||
(num_records >= MAX_NUM_RECORDS)) {
|
||||
status = ipc_flush ();
|
||||
if (IPC_STATUS_OK != status) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* make sure that the str will fit:
|
||||
*/
|
||||
if (length + fill_count > OUT_BUFFER_SIZE) {
|
||||
/* fprintf (stderr,"ERROR: IPC: String too long to fit in output buffer (> %d bytes) - truncated\n",OUT_BUFFER_SIZE); */
|
||||
length = OUT_BUFFER_SIZE - fill_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* finally, concatenate the str to the end of the buffer and add the newline:
|
||||
*/
|
||||
memcpy (&out_buffer[fill_count], str, (size_t) len);
|
||||
fill_count += len;
|
||||
|
||||
out_buffer[fill_count] = '\n';
|
||||
fill_count++;
|
||||
|
||||
end_of_record_index [num_records++] = fill_count;
|
||||
|
||||
return IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_line
|
||||
|
||||
This function sends a line of text over the interprocess
|
||||
communication channel.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_line (char *str ) /* The text to send */
|
||||
{
|
||||
int len;
|
||||
int send_len;
|
||||
|
||||
char *s;
|
||||
|
||||
Ipc_Status_t status= IPC_STATUS_OK;
|
||||
|
||||
|
||||
len = (int) strlen(str);
|
||||
|
||||
/* if short string, send it immediately */
|
||||
if(len < 80)
|
||||
status = ipc_send_line_binary (str, len);
|
||||
else {
|
||||
/* otherwise, we have to send it as multiple strings */
|
||||
/* because Mspice cannot handle things longer than 80 chars */
|
||||
s = str;
|
||||
while(len > 0) {
|
||||
if(len < 80)
|
||||
send_len = len;
|
||||
else
|
||||
send_len = 79;
|
||||
status = ipc_send_line_binary (str, send_len);
|
||||
if(status != IPC_STATUS_OK)
|
||||
break;
|
||||
s += send_len;
|
||||
len -= send_len;
|
||||
}
|
||||
}
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_data_prefix
|
||||
|
||||
This function sends a ``>DATAB'' line over the interprocess
|
||||
communication channel to signal that this is the beginning of a
|
||||
results dump for the current analysis point.
|
||||
*/
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_data_prefix (double time ) /* The analysis point for this data set */
|
||||
{
|
||||
char buffer[40];
|
||||
|
||||
sprintf (buffer, ">DATAB %.5E", time);
|
||||
return ipc_send_line (buffer);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_data_suffix
|
||||
|
||||
This function sends a ``>ENDDATA'' line over the interprocess
|
||||
communication channel to signal that this is the end of a results
|
||||
dump from a particular analysis point.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_data_suffix (void)
|
||||
{
|
||||
Ipc_Status_t status;
|
||||
|
||||
status = ipc_send_line (">ENDDATA");
|
||||
|
||||
if(status != IPC_STATUS_OK)
|
||||
return(status);
|
||||
|
||||
return(ipc_flush());
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_dcop_prefix
|
||||
|
||||
This function sends a ``>DCOPB'' line over the interprocess
|
||||
communication channel to signal that this is the beginning of a
|
||||
results dump from a DC operating point analysis.
|
||||
*/
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_dcop_prefix (void)
|
||||
{
|
||||
return ipc_send_line (">DCOPB");
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_dcop_suffix
|
||||
|
||||
This function sends a ``>ENDDATA'' line over the interprocess
|
||||
communication channel to signal that this is the end of a results
|
||||
dump from a particular analysis point.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_dcop_suffix (void)
|
||||
{
|
||||
Ipc_Status_t status;
|
||||
|
||||
status = ipc_send_line (">ENDDCOP");
|
||||
|
||||
if(status != IPC_STATUS_OK)
|
||||
return(status);
|
||||
|
||||
return(ipc_flush());
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_evtdict_prefix
|
||||
|
||||
This function sends a ``>EVTDICT'' line over the interprocess
|
||||
communication channel to signal that this is the beginning of an
|
||||
event-driven node dictionary.
|
||||
|
||||
The line is sent only if the IPC is configured
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
||||
*/
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_evtdict_prefix (void)
|
||||
{
|
||||
#ifdef IPC_AEGIS_MAILBOXES
|
||||
return IPC_STATUS_OK;
|
||||
#else
|
||||
return ipc_send_line (">EVTDICT");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_evtdict_suffix
|
||||
|
||||
This function sends a ``>ENDDICT'' line over the interprocess
|
||||
communication channel to signal that this is the end of an
|
||||
event-driven node dictionary.
|
||||
|
||||
The line is sent only if the IPC is configured
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_evtdict_suffix (void)
|
||||
{
|
||||
#ifdef IPC_AEGIS_MAILBOXES
|
||||
return IPC_STATUS_OK;
|
||||
#else
|
||||
Ipc_Status_t status;
|
||||
|
||||
status = ipc_send_line (">ENDDICT");
|
||||
|
||||
if(status != IPC_STATUS_OK)
|
||||
return(status);
|
||||
|
||||
return(ipc_flush());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_evtdata_prefix
|
||||
|
||||
This function sends a ``>EVTDATA'' line over the interprocess
|
||||
communication channel to signal that this is the beginning of an
|
||||
event-driven node data block.
|
||||
|
||||
The line is sent only if the IPC is configured
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
||||
*/
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_evtdata_prefix (void)
|
||||
{
|
||||
#ifdef IPC_AEGIS_MAILBOXES
|
||||
return IPC_STATUS_OK;
|
||||
#else
|
||||
return ipc_send_line (">EVTDATA");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_evtdata_suffix
|
||||
|
||||
This function sends a ``>ENDDATA'' line over the interprocess
|
||||
communication channel to signal that this is the end of an
|
||||
event-driven node data block.
|
||||
|
||||
The line is sent only if the IPC is configured
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_evtdata_suffix (void)
|
||||
{
|
||||
#ifdef IPC_AEGIS_MAILBOXES
|
||||
return IPC_STATUS_OK;
|
||||
#else
|
||||
Ipc_Status_t status;
|
||||
|
||||
status = ipc_send_line (">ENDDATA");
|
||||
|
||||
if(status != IPC_STATUS_OK)
|
||||
return(status);
|
||||
|
||||
return(ipc_flush());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_errchk
|
||||
|
||||
This function sends a ``\ERRCHK [GO|NOGO]'' message over the
|
||||
interprocess communication channel to signal that the initial
|
||||
parsing of the input deck has been completed and to indicate
|
||||
whether or not errors were detected.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_errchk(void)
|
||||
{
|
||||
char str[IPC_MAX_LINE_LEN+1];
|
||||
Ipc_Status_t status;
|
||||
|
||||
if(g_ipc.errchk_sent)
|
||||
return(IPC_STATUS_OK);
|
||||
|
||||
if(g_ipc.syntax_error)
|
||||
sprintf(str, "#ERRCHK NOGO");
|
||||
else
|
||||
sprintf(str, "#ERRCHK GO");
|
||||
|
||||
g_ipc.errchk_sent = IPC_TRUE;
|
||||
|
||||
status = ipc_send_line(str);
|
||||
if(status != IPC_STATUS_OK)
|
||||
return(status);
|
||||
|
||||
return(ipc_flush());
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_end
|
||||
|
||||
This function sends either an ``>ENDANAL'' or an ``>ABORTED'' message
|
||||
over the interprocess communication channel together with the
|
||||
total CPU time used to indicate whether or not the simulation
|
||||
completed normally.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_end(void)
|
||||
{
|
||||
char str[IPC_MAX_LINE_LEN+1];
|
||||
Ipc_Status_t status;
|
||||
|
||||
if(g_ipc.syntax_error || g_ipc.run_error)
|
||||
sprintf(str, ">ABORTED %.4f", g_ipc.cpu_time);
|
||||
else
|
||||
sprintf(str, ">ENDANAL %.4f", g_ipc.cpu_time);
|
||||
|
||||
status = ipc_send_line(str);
|
||||
if(status != IPC_STATUS_OK)
|
||||
return(status);
|
||||
|
||||
return(ipc_flush());
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int
|
||||
stuff_binary_v1 (
|
||||
double d1, double d2, /* doubles to be stuffed */
|
||||
int n, /* how many of d1, d2 ( 1 <= n <= 2 ) */
|
||||
char *buf, /* buffer to stuff to */
|
||||
int pos ) /* index at which to stuff */
|
||||
{
|
||||
union {
|
||||
float float_val[2];
|
||||
char ch[32];
|
||||
} trick;
|
||||
int i, j;
|
||||
|
||||
assert (protocol == IPC_PROTOCOL_V1);
|
||||
assert (sizeof(float) == 4);
|
||||
assert (sizeof(char) == 1);
|
||||
assert ((n >= 1) && (n <= 2));
|
||||
|
||||
trick.float_val[0] = (float)d1;
|
||||
if (n > 1) {
|
||||
trick.float_val[1] = (float)d2;
|
||||
}
|
||||
for (i = 0, j = pos; i < n * (int) sizeof(float); j++, i++)
|
||||
buf[j] = trick.ch[i];
|
||||
buf[0] = (char) ('A' + j - 1);
|
||||
return j;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*
|
||||
ipc_send_double
|
||||
|
||||
This function sends a double data value over the interprocess
|
||||
communication channel preceded by a character string that
|
||||
identifies the simulation variable.
|
||||
*/
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_double (
|
||||
char *tag, /* The node or instance */
|
||||
double value ) /* The data value to send */
|
||||
{
|
||||
int len = 0;
|
||||
|
||||
switch (protocol) {
|
||||
case IPC_PROTOCOL_V1:
|
||||
strcpy (fmt_buffer, " "); /* save room for the length byte */
|
||||
strcat (fmt_buffer, tag);
|
||||
strcat (fmt_buffer, " ");
|
||||
|
||||
/* If talking to Mentor tools, must force upper case for Mspice 7.0 */
|
||||
strtoupper(fmt_buffer);
|
||||
|
||||
len = stuff_binary_v1 (value, 0.0, 1, fmt_buffer, (int) strlen(fmt_buffer));
|
||||
break;
|
||||
case IPC_PROTOCOL_V2:
|
||||
break;
|
||||
}
|
||||
return ipc_send_line_binary (fmt_buffer, len);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_complex
|
||||
|
||||
This function sends a complex data value over the interprocess
|
||||
communication channel preceded by a character string that
|
||||
identifies the simulation variable.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_complex (
|
||||
char *tag, /* The node or instance */
|
||||
Ipc_Complex_t value ) /* The data value to send */
|
||||
{
|
||||
int len=0;
|
||||
|
||||
switch (protocol) {
|
||||
case IPC_PROTOCOL_V1:
|
||||
strcpy (fmt_buffer, " "); /* save room for the length byte */
|
||||
strcat (fmt_buffer, tag);
|
||||
strcat (fmt_buffer, " ");
|
||||
|
||||
/* If talking to Mentor tools, must force upper case for Mspice 7.0 */
|
||||
strtoupper(fmt_buffer);
|
||||
|
||||
len = stuff_binary_v1 (value.real, value.imag, 2, fmt_buffer,
|
||||
(int) strlen(fmt_buffer));
|
||||
break;
|
||||
case IPC_PROTOCOL_V2:
|
||||
break;
|
||||
}
|
||||
return ipc_send_line_binary (fmt_buffer, len);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_send_event
|
||||
|
||||
This function sends data from an event-driven node over the interprocess
|
||||
communication channel. The data is sent only if the IPC is configured
|
||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_send_event (
|
||||
int ipc_index, /* Index used in EVTDICT */
|
||||
double step, /* Analysis point or timestep (0.0 for DC) */
|
||||
double plot_val, /* The value for plotting purposes */
|
||||
char *print_val, /* The value for printing purposes */
|
||||
void *ipc_val, /* The binary representation of the node data */
|
||||
int len ) /* The length of the binary representation */
|
||||
{
|
||||
#ifdef IPC_AEGIS_MAILBOXES
|
||||
return IPC_STATUS_OK;
|
||||
#else
|
||||
char buff[OUT_BUFFER_SIZE];
|
||||
int i;
|
||||
int buff_len;
|
||||
char *buff_ptr;
|
||||
char *temp_ptr;
|
||||
float fvalue;
|
||||
|
||||
/* Report error if size of data is too big for IPC channel block size */
|
||||
if((len + (int) strlen(print_val) + 100) >= OUT_BUFFER_SIZE) {
|
||||
printf("ERROR - Size of event-driven data too large for IPC channel\n");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/* Place the index into the buffer with a trailing space */
|
||||
sprintf(buff, "%d ", ipc_index);
|
||||
|
||||
assert(sizeof(float) == 4);
|
||||
assert(sizeof(int) == 4);
|
||||
|
||||
/* Put the analysis step bytes in */
|
||||
buff_len = (int) strlen(buff);
|
||||
buff_ptr = buff + buff_len;
|
||||
fvalue = (float)step;
|
||||
temp_ptr = (char *) &fvalue;
|
||||
for(i = 0; i < 4; i++) {
|
||||
*buff_ptr = temp_ptr[i];
|
||||
buff_ptr++;
|
||||
buff_len++;
|
||||
}
|
||||
|
||||
/* Put the plot value in */
|
||||
fvalue = (float)plot_val;
|
||||
temp_ptr = (char *) &fvalue;
|
||||
for(i = 0; i < 4; i++) {
|
||||
*buff_ptr = temp_ptr[i];
|
||||
buff_ptr++;
|
||||
buff_len++;
|
||||
}
|
||||
|
||||
/* Put the length of the binary representation in */
|
||||
temp_ptr = (char *) &len;
|
||||
for(i = 0; i < 4; i++) {
|
||||
*buff_ptr = temp_ptr[i];
|
||||
buff_ptr++;
|
||||
buff_len++;
|
||||
}
|
||||
|
||||
/* Put the binary representation bytes in last */
|
||||
temp_ptr = (char*) ipc_val;
|
||||
for(i = 0; i < len; i++)
|
||||
buff_ptr[i] = temp_ptr[i];
|
||||
buff_ptr += len;
|
||||
buff_len += len;
|
||||
|
||||
/* Put the print value in */
|
||||
strcpy(buff_ptr, print_val);
|
||||
buff_ptr += strlen(print_val);
|
||||
buff_len += (int) strlen(print_val);
|
||||
|
||||
/* Send the data to the IPC channel */
|
||||
return ipc_send_line_binary(buff, buff_len);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,309 +0,0 @@
|
|||
/*============================================================================
|
||||
FILE IPCaegis.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Public Domain
|
||||
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Steve Tynor
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
Provides compatibility for the new XSPICE simulator to both the MSPICE user
|
||||
interface and BCP via ATESSE v.1 style AEGIS mailboxes.
|
||||
|
||||
INTERFACES
|
||||
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
#ifdef IPC_AEGIS_MAILBOXES
|
||||
|
||||
#include <assert.h>
|
||||
#include <apollo/base.h>
|
||||
#include <apollo/mbx.h>
|
||||
#include <apollo/error.h>
|
||||
#include "ngspice/memory.h"
|
||||
|
||||
#include "ngspice/ipc.h"
|
||||
|
||||
|
||||
typedef unsigned char Buffer_char_t;
|
||||
|
||||
static status_$t status;
|
||||
typedef enum {
|
||||
IPC_MBX_UNINITIALIZED,
|
||||
IPC_MBX_INITIALIZED,
|
||||
IPC_MBX_CONNECTED_TO_CLIENT,
|
||||
} Ipc_Mbx_State_t;
|
||||
|
||||
static void *mbx_handle;
|
||||
static Ipc_Mbx_State_t mbx_state = IPC_MBX_UNINITIALIZED;
|
||||
static mbx_$server_msg_t mbx_send_msg_buf;
|
||||
static mbx_$server_msg_t mbx_recieve_msg_buf;
|
||||
static mbx_$server_msg_t *mbx_ret_ptr;
|
||||
static int mbx_ret_len;
|
||||
static short mbx_chan;
|
||||
|
||||
#include "ngspice/ipcproto.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_transport_initialize_server
|
||||
|
||||
This function creates an Aegis mailbox, and if successful,
|
||||
calls ipc_get_line to wait for the first record sent which is
|
||||
assumed to be the batch output filename.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Ipc_Status_t ipc_transport_initialize_server (server_name, m, p,
|
||||
batch_filename)
|
||||
char *server_name; /* The mailbox pathname */
|
||||
Ipc_Mode_t m; /* Mode - interactive or batch */
|
||||
Ipc_Protocol_t p; /* Protocol type */
|
||||
char *batch_filename; /* Batch filename returned */
|
||||
{
|
||||
int len;
|
||||
/* extern void *malloc(); */
|
||||
|
||||
assert (p == IPC_PROTOCOL_V1);
|
||||
|
||||
mbx_$create_server (server_name, strlen (server_name), mbx_$serv_msg_max,
|
||||
1, &mbx_handle, &status);
|
||||
|
||||
if (status.all != status_$ok) {
|
||||
fprintf (stderr,
|
||||
"ERROR: IPC: Error creating mailbox server \"%s\"\n",
|
||||
server_name);
|
||||
error_$print (status);
|
||||
mbx_state = IPC_MBX_UNINITIALIZED;
|
||||
return IPC_STATUS_ERROR;
|
||||
} else {
|
||||
mbx_state = IPC_MBX_INITIALIZED;
|
||||
/*
|
||||
* First record is the name of the batch filename - whether we're in
|
||||
* batch mode or not:
|
||||
*/
|
||||
return ipc_get_line (batch_filename, &len, IPC_WAIT);
|
||||
}
|
||||
/*
|
||||
* shouldn't get here
|
||||
*/
|
||||
assert (0);
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
Ipc_Status_t extract_msg (str, len)
|
||||
char *str;
|
||||
int *len;
|
||||
{
|
||||
*len = mbx_ret_len - mbx_$serv_msg_hdr_len;
|
||||
assert (*len >= 0);
|
||||
|
||||
/*
|
||||
* null terminate before copy:
|
||||
*/
|
||||
mbx_ret_ptr->data [*len] = '\0';
|
||||
strcpy (str, mbx_ret_ptr->data);
|
||||
|
||||
return IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_transport_get_line
|
||||
|
||||
This function reads data sent by a client over the mailbox
|
||||
channel. It also handles the initial opening of the
|
||||
mailbox channel when requested by a client.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
Ipc_Status_t ipc_transport_get_line (str, len, wait)
|
||||
char *str; /* The string text read from IPC channel */
|
||||
int *len; /* The length of str */
|
||||
Ipc_Wait_t wait; /* Blocking or non-blocking */
|
||||
{
|
||||
if (mbx_state == IPC_MBX_UNINITIALIZED) {
|
||||
fprintf (stderr,
|
||||
"ERROR: IPC: Attempted to read from non-initialized mailbox\n");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
assert ((mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) ||
|
||||
(mbx_state == IPC_MBX_INITIALIZED));
|
||||
|
||||
for (;;) {
|
||||
if (wait == IPC_WAIT) {
|
||||
mbx_$get_rec (mbx_handle, &mbx_recieve_msg_buf, mbx_$serv_msg_max,
|
||||
&mbx_ret_ptr, &mbx_ret_len, &status);
|
||||
} else {
|
||||
mbx_$get_conditional (mbx_handle, &mbx_recieve_msg_buf,
|
||||
mbx_$serv_msg_max, &mbx_ret_ptr, &mbx_ret_len,
|
||||
&status);
|
||||
if (status.all == mbx_$channel_empty) {
|
||||
return IPC_STATUS_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (status.all != status_$ok) {
|
||||
fprintf (stderr, "ERROR: IPC: Error reading from mailbox\n");
|
||||
error_$print (status);
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
switch (mbx_ret_ptr->mt) {
|
||||
case mbx_$channel_open_mt:
|
||||
if (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) {
|
||||
/*
|
||||
* we're already connected to a client... refuse the connection
|
||||
*/
|
||||
mbx_send_msg_buf.mt = mbx_$reject_open_mt;
|
||||
} else {
|
||||
mbx_send_msg_buf.mt = mbx_$accept_open_mt;
|
||||
mbx_state = IPC_MBX_CONNECTED_TO_CLIENT;
|
||||
}
|
||||
mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len;
|
||||
mbx_chan = mbx_ret_ptr->chan;
|
||||
mbx_send_msg_buf.chan = mbx_chan;
|
||||
|
||||
mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, mbx_$serv_msg_hdr_len,
|
||||
&status);
|
||||
|
||||
if (status.all != status_$ok) {
|
||||
fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n");
|
||||
error_$print (status);
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* check to see if there was a message buried in the open request:
|
||||
*/
|
||||
if (mbx_ret_len > mbx_$serv_msg_hdr_len) {
|
||||
return extract_msg (str, len);
|
||||
}
|
||||
break;
|
||||
case mbx_$eof_mt:
|
||||
mbx_chan = mbx_ret_ptr->chan;
|
||||
mbx_$deallocate(mbx_handle, mbx_chan, &status);
|
||||
|
||||
if (status.all != status_$ok) {
|
||||
fprintf (stderr, "ERROR: IPC: Error deallocating mailbox\n");
|
||||
error_$print (status);
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
mbx_state = IPC_MBX_INITIALIZED;
|
||||
return IPC_STATUS_EOF;
|
||||
break;
|
||||
case mbx_$data_mt:
|
||||
assert (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT);
|
||||
return extract_msg (str, len);
|
||||
break;
|
||||
case mbx_$data_partial_mt:
|
||||
fprintf (stderr, "ERROR: IPC: Recieved partial data message - ignored\n");
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr, "ERROR: IPC: Bad message type (0x%x) recieved\n",
|
||||
mbx_ret_ptr->mt);
|
||||
}
|
||||
}
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_transport_terminate_server
|
||||
|
||||
This function calls ipc\_transport\_get\_line until it
|
||||
receives an EOF from the client, which concludes the
|
||||
communication.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t ipc_transport_terminate_server ()
|
||||
{
|
||||
char buffer[300];
|
||||
int len;
|
||||
Ipc_Status_t status;
|
||||
|
||||
do {
|
||||
status = ipc_transport_get_line (buffer, &len, IPC_WAIT);
|
||||
} while ((status != IPC_STATUS_ERROR) &&
|
||||
(status != IPC_STATUS_EOF));
|
||||
return status;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
ipc_transport_send_line
|
||||
|
||||
This function sends a message to the current client through
|
||||
the mailbox channel.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Status_t ipc_transport_send_line (str, len)
|
||||
char *str; /* The bytes to send */
|
||||
int len; /* The number of bytes from str to send */
|
||||
{
|
||||
long cnt;
|
||||
|
||||
if (mbx_state != IPC_MBX_CONNECTED_TO_CLIENT) {
|
||||
fprintf (stderr,
|
||||
"ERROR: IPC: Attempted to write to non-open mailbox\n");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
mbx_send_msg_buf.mt = mbx_$data_mt;
|
||||
if (mbx_$serv_msg_hdr_len + len > mbx_$serv_msg_max) {
|
||||
fprintf (stderr,
|
||||
"ERROR: IPC: send_line message too long - truncating\n");
|
||||
len = mbx_$serv_msg_max - mbx_$serv_msg_hdr_len;
|
||||
}
|
||||
|
||||
mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len + len;
|
||||
mbx_send_msg_buf.chan = mbx_chan;
|
||||
memcpy (mbx_send_msg_buf.data, str, len);
|
||||
|
||||
cnt = mbx_send_msg_buf.cnt;
|
||||
mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, cnt, &status);
|
||||
|
||||
if (status.all != status_$ok) {
|
||||
fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n");
|
||||
error_$print (status);
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
return IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int intDummy1;
|
||||
|
||||
#endif /* IPC_AEGIS_MAILBOXES */
|
||||
|
|
@ -1,756 +0,0 @@
|
|||
/*=============================================================================
|
||||
|
||||
FILE IPCsockets.c
|
||||
|
||||
Public Domain
|
||||
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHOR
|
||||
Stefan Roth July 1991
|
||||
|
||||
MODIFICATIONS
|
||||
none
|
||||
|
||||
SUMMARY
|
||||
Generic Interprocess Communication module
|
||||
Provides compatibility for the new SPICE simulator to both the MSPICE user
|
||||
interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE
|
||||
v.2 Simulator Interface and BCP (via BSD Sockets). This file contains the
|
||||
BSD sockets version.
|
||||
The Simulator is the server, while the SI and BCP will be the clients.
|
||||
|
||||
|
||||
INTERFACES
|
||||
|
||||
FILE ROUTINE CALLED
|
||||
|
||||
IPC.c ipc_get_line();
|
||||
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
Outputs to stderr.
|
||||
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
DESCRIPTION OF FUNCTIONALITY:
|
||||
|
||||
Outline of Initialize_Server function:
|
||||
create socket;
|
||||
bind name to socket;
|
||||
getsockname;
|
||||
listen;
|
||||
sock_state = IPC_SOCK_INITIALIZED;
|
||||
return ipc_get_line ();
|
||||
|
||||
|
||||
Format of a message line:
|
||||
bytes description
|
||||
----- -------------------
|
||||
0 recognition character for beginning of line; value is BOL_CHAR.
|
||||
1-4 message length (not including bytes 0-4); 32 bits in htonl
|
||||
format;
|
||||
if value = -1, then EOF and socket should be closed.
|
||||
5-N+5 message body of length specified in bytes 1-4.
|
||||
|
||||
The bytes before the message body are the message header. The header
|
||||
length is specified as SOCK_MSG_HDR_LEN bytes.
|
||||
|
||||
|
||||
Outline of Get_Line function:
|
||||
read 5 characters;
|
||||
verify that first char is BOL_CHAR;
|
||||
interpret message length (N) from bytes 1-4;
|
||||
do error checking on message header bytes;
|
||||
read N characters as message body;
|
||||
do error checking on message body read;
|
||||
|
||||
|
||||
Outline of Send_Line function:
|
||||
write BOL_CHAR;
|
||||
write 4-byte message body length
|
||||
write message body (N bytes)
|
||||
do error checking after each write operation
|
||||
|
||||
|
||||
Outline of Terminate_Server function:
|
||||
Continue to read lines (with ipc_transport_get_line) and ignore
|
||||
them until socket EOF is reached;
|
||||
Close the socket.
|
||||
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
|
||||
#ifdef IPC_UNIX_SOCKETS
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ngspice/ipc.h"
|
||||
#include "ngspice/ipctiein.h"
|
||||
|
||||
|
||||
/*=== TYPE DEFINITIONS ===*/
|
||||
|
||||
typedef enum {
|
||||
IPC_SOCK_UNINITIALIZED,
|
||||
IPC_SOCK_INITIALIZED,
|
||||
IPC_SOCK_CONNECTED_TO_CLIENT
|
||||
} Ipc_Sock_State_t;
|
||||
|
||||
|
||||
/*=== LOCAL VARIABLES ===*/
|
||||
|
||||
static int sock_desc; /* socket descriptor */
|
||||
static int msg_stream; /* socket stream */
|
||||
static Ipc_Sock_State_t sock_state = IPC_SOCK_UNINITIALIZED;
|
||||
|
||||
|
||||
/*=== INCLUDE FILES ===*/
|
||||
|
||||
#include "ngspice/ipcproto.h"
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
FUNCTION ipc_transport_initialize_server
|
||||
|
||||
AUTHORS
|
||||
|
||||
July 1991 Stefan Roth
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
NONE
|
||||
|
||||
SUMMARY
|
||||
|
||||
Creates and opens the BSD socket of the server. Listens for requests
|
||||
by a client and then reads the first line message.
|
||||
|
||||
INTERFACES
|
||||
|
||||
Called by: (IPC.c) ipc_initialize_server();
|
||||
|
||||
RETURNED VALUE
|
||||
|
||||
Ipc_Status_t - returns status of the socket connection.
|
||||
|
||||
GLOBAL VARIABLES
|
||||
|
||||
NONE
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
NONE
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_transport_initialize_server (
|
||||
char *server_name, /* not used */
|
||||
Ipc_Mode_t mode, /* not used */
|
||||
Ipc_Protocol_t protocol, /* IN - only used in assert */
|
||||
char *batch_filename ) /* OUT - returns a value */
|
||||
/* Note that unused parameters are required to maintain compatibility */
|
||||
/* with version 1 (mailboxes) functions of the same names. */
|
||||
{
|
||||
struct sockaddr_in server; /* Server specifications for socket*/
|
||||
socklen_t server_length; /* Size of server structure */
|
||||
int port_num; /* Port number converted from server_name */
|
||||
|
||||
NG_IGNORE(mode);
|
||||
NG_IGNORE(protocol);
|
||||
|
||||
/* assert (protocol == IPC_PROTOCOL_V2); */ /* allow v1 protocol - wbk */
|
||||
assert (sock_state == IPC_SOCK_UNINITIALIZED);
|
||||
|
||||
/* convert server_name (from atesse_xspice invocation line) to a port */
|
||||
/* number */
|
||||
port_num = atoi(server_name);
|
||||
if((port_num > 0) && (port_num < 1024)) {
|
||||
/* Reserved port number */
|
||||
perror ("ERROR: IPC Port numbers below 1024 are reserved");
|
||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
sock_desc = socket (AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
if (sock_desc < 0) {
|
||||
/* Unsuccessful socket opening */
|
||||
perror ("ERROR: IPC Creating socket");
|
||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/* Socket opened successfully */
|
||||
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = INADDR_ANY;
|
||||
server.sin_port = SOCKET_PORT;
|
||||
|
||||
server_length = sizeof (server);
|
||||
if (bind (sock_desc, (struct sockaddr *)&server, server_length)
|
||||
< 0) {
|
||||
fprintf (stderr, "ERROR: IPC: Bind unsuccessful\n");
|
||||
perror ("ERROR: IPC");
|
||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (getsockname (sock_desc, (struct sockaddr *)&server, &server_length)
|
||||
< 0) {
|
||||
fprintf (stderr, "ERROR: IPC: getting socket name\n");
|
||||
perror ("ERROR: IPC");
|
||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
fprintf (stderr, "Socket port %d.\n", ntohs(server.sin_port));
|
||||
|
||||
listen (sock_desc, 5);
|
||||
|
||||
sock_state = IPC_SOCK_INITIALIZED;
|
||||
|
||||
/* Socket ok to use now */
|
||||
|
||||
/*
|
||||
* First record is the name of the batch filename if we're in batch mode.
|
||||
*/
|
||||
|
||||
if(g_ipc.mode == IPC_MODE_BATCH) {
|
||||
int len;
|
||||
return ipc_get_line (batch_filename, &len, IPC_WAIT);
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return IPC_STATUS_OK;
|
||||
|
||||
} /* end ipc_transport_initialize_server */
|
||||
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
FUNCTION bytes_to_integer
|
||||
|
||||
AUTHORS
|
||||
|
||||
July 1991 Stefan Roth
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
NONE
|
||||
|
||||
SUMMARY
|
||||
|
||||
Convert four bytes at START in the string STR
|
||||
to a 32-bit unsigned integer. The string is assumed
|
||||
to be in network byte order and the returned value
|
||||
is converted to host byte order (with ntohl).
|
||||
|
||||
INTERFACES
|
||||
|
||||
Local to this file.
|
||||
Called by: ipc_transport_get_line();
|
||||
|
||||
RETURNED VALUE
|
||||
|
||||
u_long - unsigned 32 bit integer
|
||||
|
||||
GLOBAL VARIABLES
|
||||
|
||||
NONE
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
NONE
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
/* FIXME,
|
||||
* this is seriously broken,
|
||||
* once it was probably based upon htonl(),
|
||||
* yet with broken types
|
||||
* then the game has changed and strtoul() was used
|
||||
* with a ascii representation of the length
|
||||
* (probably as a hacky workaround, because it proved unreliable)
|
||||
* but the buffer is not terminated properly
|
||||
* Fix this when needed, currently this functionality looks like
|
||||
* an unused ancient artefact
|
||||
* Fix it with regard to ipc_transport_get_line() and ipc_transport_send_line()
|
||||
* and in concert with the actual user at the other side of the socket
|
||||
*/
|
||||
static u_long
|
||||
bytes_to_integer (
|
||||
char *str, /* IN - string that contains the bytes to convert */
|
||||
int start ) /* IN - index into string where bytes are */
|
||||
{
|
||||
uint32_t u; /* Value to be returned */
|
||||
char buff[4]; /* Transfer str into buff to word align reqd data */
|
||||
int index; /* Index into str and buff for transfer */
|
||||
|
||||
/* Get the str+start character and cast it into a u_long and put
|
||||
the value through the network-to-host-short converter and store
|
||||
it in the variable u. */
|
||||
|
||||
index = 0;
|
||||
while (index < (int) sizeof(u)) {
|
||||
buff[index] = str[index+start];
|
||||
index++;
|
||||
}
|
||||
/* u = ntohl (*((u_long *) buff)); */
|
||||
u = (uint32_t) strtoul(buff, NULL, 10);
|
||||
|
||||
return u;
|
||||
} /* end bytes_to_integer */
|
||||
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
FUNCTION handle_socket_eof
|
||||
|
||||
AUTHORS
|
||||
|
||||
July 1991 Stefan Roth
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
NONE
|
||||
|
||||
SUMMARY
|
||||
|
||||
Do processing when the socket reaches EOF or when a message from the
|
||||
client states that EOF has been reached.
|
||||
|
||||
INTERFACES
|
||||
|
||||
Local to this file.
|
||||
Called by: ipc_transport_get_line();
|
||||
|
||||
RETURNED VALUE
|
||||
|
||||
Ipc_Status_t - always IPC_STATUS_EOF
|
||||
|
||||
GLOBAL VARIABLES
|
||||
|
||||
NONE
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
NONE
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
|
||||
static Ipc_Status_t
|
||||
handle_socket_eof (void)
|
||||
{
|
||||
close (msg_stream);
|
||||
close (sock_desc);
|
||||
|
||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
||||
|
||||
return IPC_STATUS_EOF;
|
||||
} /* handle_socket_eof */
|
||||
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
FUNCTION read_sock
|
||||
|
||||
AUTHORS
|
||||
|
||||
July 1991 Stefan Roth
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
NONE
|
||||
|
||||
SUMMARY
|
||||
|
||||
Read N bytes from a socket. Only returns when the read had an error,
|
||||
when 0 bytes (EOF) could be read, or LENGTH bytes are read.
|
||||
|
||||
INTERFACES
|
||||
|
||||
Local to this file.
|
||||
Called by: ipc_transport_get_line();
|
||||
|
||||
RETURNED VALUE
|
||||
|
||||
int - Returns the total number of bytes read.
|
||||
|
||||
GLOBAL VARIABLES
|
||||
|
||||
NONE
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
NONE
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
|
||||
static int
|
||||
read_sock (
|
||||
int stream, /* IN - Socket stream */
|
||||
char *buffer, /* OUT - buffer to store incoming data */
|
||||
int length, /* IN - Number of bytes to be read */
|
||||
Ipc_Wait_t wait, /* IN - type of read operation */
|
||||
int flags ) /* IN - Original socket flags for blocking read */
|
||||
{
|
||||
int count; /* Number of bytes read with last `read` */
|
||||
int totalcount; /* total number of bytes read */
|
||||
char *buf2;
|
||||
|
||||
/* count = 0; */
|
||||
/* while (count < length) { */
|
||||
/* buffer[count] = 'x'; */
|
||||
/* count++; */
|
||||
/* } */
|
||||
count = (int) read (stream, buffer, (size_t) length);
|
||||
if (wait == IPC_NO_WAIT) {
|
||||
fcntl (stream, F_SETFL, flags); /* Revert to blocking read */
|
||||
}
|
||||
if ((count <= 0) || (count == length)) {
|
||||
/* If error or if read in reqd number of bytes: */
|
||||
return count;
|
||||
} else {
|
||||
/* Only got some of the bytes requested */
|
||||
totalcount = count;
|
||||
buf2 = &buffer[totalcount];
|
||||
length = length - count;
|
||||
while (length > 0) {
|
||||
count = (int) read (stream, buf2, (size_t) length);
|
||||
if (count <= 0) /* EOF or read error */
|
||||
break;
|
||||
totalcount = totalcount + count;
|
||||
buf2 = &buffer[totalcount];
|
||||
length = length - count;
|
||||
}
|
||||
if (length != 0) {
|
||||
fprintf (stderr, "WARNING: READ_SOCK read %d bytes instead of %d\n",
|
||||
totalcount, totalcount + length);
|
||||
}
|
||||
return totalcount;
|
||||
}
|
||||
} /* end read_sock */
|
||||
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
FUNCTION ipc_transport_get_line
|
||||
|
||||
AUTHORS
|
||||
|
||||
July 1991 Stefan Roth
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
NONE
|
||||
|
||||
SUMMARY
|
||||
|
||||
Main function for reading one line from a socket. Requires that the
|
||||
socket be open. Lines are mostly SPICE code, but commands may also
|
||||
be embedded in the socket data and they are interpreted by this function.
|
||||
Therefore, this function may cause the socket to be closed.
|
||||
|
||||
INTERFACES
|
||||
|
||||
Called by: ipc_transport_terminate_server();
|
||||
(IPC.c) ipc_get_line();
|
||||
|
||||
RETURNED VALUE
|
||||
|
||||
Ipc_Status_t - returns status of the read operation
|
||||
|
||||
GLOBAL VARIABLES
|
||||
|
||||
NONE
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
NONE
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_transport_get_line (
|
||||
char *str, /* returns the result, null terminated */
|
||||
int *len, /* length of str passed IN and passed OUT */
|
||||
Ipc_Wait_t wait ) /* IN - wait or dont wait on incoming msg */
|
||||
{
|
||||
int count = 0; /* number of bytes read */
|
||||
int message_length; /* extracted from message header */
|
||||
|
||||
if (sock_state == IPC_SOCK_UNINITIALIZED) {
|
||||
fprintf (stderr,
|
||||
"ERROR: IPC: Attempted to read from uninitialized socket\n");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
assert ((sock_state == IPC_SOCK_CONNECTED_TO_CLIENT) ||
|
||||
(sock_state == IPC_SOCK_INITIALIZED));
|
||||
|
||||
if (sock_state == IPC_SOCK_INITIALIZED) {
|
||||
/* We have an open socket but have not connected to a client. */
|
||||
/* Accept a connection from a client. */
|
||||
msg_stream = accept (sock_desc, (struct sockaddr *)0, (socklen_t*)0);
|
||||
|
||||
if (msg_stream == -1) {
|
||||
fprintf (stderr, "ERROR: IPC: Server accepting request\n");
|
||||
perror ("ERROR: IPC");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
sock_state = IPC_SOCK_CONNECTED_TO_CLIENT;
|
||||
}
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* First read in the message header. */
|
||||
{
|
||||
int flags;
|
||||
flags = fcntl(msg_stream, F_GETFL, NULL); /* Blocking read mode */
|
||||
|
||||
if (wait == IPC_WAIT) {
|
||||
/* Block here and wait for the next message */
|
||||
count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags);
|
||||
if (count == 0) {
|
||||
/* EOF, will this ever happen? */
|
||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */
|
||||
return handle_socket_eof ();
|
||||
}
|
||||
} else if (wait == IPC_NO_WAIT) {
|
||||
/* Read message, but do not wait if none available. */
|
||||
|
||||
fcntl (msg_stream, F_SETFL, flags | O_NDELAY);
|
||||
count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags);
|
||||
|
||||
if (count == 0) {
|
||||
/* EOF, will this ever happen? */
|
||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */
|
||||
return handle_socket_eof ();
|
||||
} else if (count == -1) {
|
||||
if (errno == EWOULDBLOCK) {
|
||||
return IPC_STATUS_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Serious problem, since it is not reading anything. */
|
||||
fprintf (stderr,
|
||||
"ERROR: IPC: invalid wait arg to ipc_transport_get_line\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Do more error checking on the read in values of the message header: */
|
||||
if (count == -1) {
|
||||
fprintf (stderr, "ERROR: IPC: Reading from socket\n");
|
||||
perror ("ERROR: IPC");
|
||||
return IPC_STATUS_ERROR;
|
||||
} else if (str[0] != BOL_CHAR) {
|
||||
fprintf (stderr,
|
||||
"ERROR: IPC: Did not find beginning of message header (%c)\n",
|
||||
str[0]);
|
||||
return IPC_STATUS_ERROR;
|
||||
} else if ((message_length = (int) bytes_to_integer (str, 1)) == -1) {
|
||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */
|
||||
return handle_socket_eof ();
|
||||
} else if (message_length == 0) {
|
||||
*len = 0;
|
||||
return IPC_STATUS_NO_DATA;
|
||||
|
||||
/* Invalid test... delete - wbk
|
||||
} else if (message_length > *len) {
|
||||
fprintf (stderr,
|
||||
"ERROR: IPC: Buffer (%d) is too short for message (%d)\n",
|
||||
*len, message_length);
|
||||
return IPC_STATUS_ERROR;
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Now read in the message body. */
|
||||
/* Always block here since the message header was already read and */
|
||||
/* we must get the body. */
|
||||
|
||||
*len = message_length;
|
||||
count = read_sock (msg_stream, str, message_length, IPC_WAIT, 0);
|
||||
if (count == 0) {
|
||||
/* EOF, will this ever happen? */
|
||||
/* fprintf (stderr, */
|
||||
/* "WARNING: IPC: Reached eof in message body on socket\n");*/
|
||||
return handle_socket_eof ();
|
||||
} else if (count == -1) {
|
||||
fprintf (stderr, "ERROR: IPC: reading message body from socket\n");
|
||||
perror ("ERROR: IPC");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/* Looks like we have a valid message here. Put in the string terminator. */
|
||||
*len = count;
|
||||
str[count] = '\0';
|
||||
|
||||
return IPC_STATUS_OK;
|
||||
|
||||
} /* end ipc_transport_get_line */
|
||||
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
FUNCTION ipc_transport_send_line
|
||||
|
||||
AUTHORS
|
||||
|
||||
July 1991 Stefan Roth
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
NONE
|
||||
|
||||
SUMMARY
|
||||
Send a line of information. First sends a message header and
|
||||
then the actual message body.
|
||||
Error checking is done to make reasonably sure that the data was sent.
|
||||
|
||||
|
||||
INTERFACES
|
||||
|
||||
Called by: (IPC.c) ipc_flush ();
|
||||
|
||||
RETURNED VALUE
|
||||
|
||||
Ipc_Status_t - returns status of the send operation (typically
|
||||
IPC_STATUS_ERROR or IPC_STATUS_OK).
|
||||
|
||||
|
||||
GLOBAL VARIABLES
|
||||
|
||||
NONE
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
NONE
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_transport_send_line (
|
||||
char *str, /* IN - String to write */
|
||||
int len ) /* IN - Number of characters out of STR to write */
|
||||
{
|
||||
int count; /* Counts how many bytes were actually written */
|
||||
u_long u; /* 32-bit placeholder for transmission of LEN */
|
||||
char hdr_buff[5]; /* Buffer for building header message in */
|
||||
int i; /* Temporary counter */
|
||||
char *char_ptr; /* Pointer for int to bytes conversion */
|
||||
|
||||
if (sock_state != IPC_SOCK_CONNECTED_TO_CLIENT) {
|
||||
fprintf (stderr, "ERROR: IPC: Attempt to write to non-open socket\n");
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/* Write message body header with length: */
|
||||
hdr_buff[0] = BOL_CHAR;
|
||||
u = htonl ((uint32_t) len);
|
||||
char_ptr = (char *) &u;
|
||||
for(i = 0; i < 4; i++)
|
||||
hdr_buff[i+1] = char_ptr[i];
|
||||
|
||||
count = (int) write (msg_stream, hdr_buff, 5);
|
||||
if (count != 5) {
|
||||
fprintf (stderr, "ERROR: IPC: (%d) send line error 1\n", count);
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
/* Write message body: */
|
||||
count = (int) write (msg_stream, str, (size_t) len);
|
||||
if (count != len) {
|
||||
fprintf (stderr, "ERROR: IPC: (%d) send line error 2\n", count);
|
||||
return IPC_STATUS_ERROR;
|
||||
}
|
||||
|
||||
return IPC_STATUS_OK;
|
||||
} /* end ipc_transport_send_line */
|
||||
|
||||
|
||||
|
||||
/*=============================================================================
|
||||
|
||||
FUNCTION ipc_transport_terminate_server
|
||||
|
||||
AUTHORS
|
||||
|
||||
July 1991 Stefan Roth
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
NONE
|
||||
|
||||
SUMMARY
|
||||
|
||||
This function reads all pending incoming messages and discards them.
|
||||
Reading continues until a read error occurs or EOF is reached, at which
|
||||
time the socket is closed.
|
||||
Note that this function does not actually close the socket. This is
|
||||
done in ipc_transport_get_line, which is called in this function.
|
||||
|
||||
In this function, the incoming line length is limited. See buffer below.
|
||||
|
||||
INTERFACES
|
||||
|
||||
Called by: (IPC.c) ipc_terminate_server();
|
||||
|
||||
RETURNED VALUE
|
||||
|
||||
Ipc_Status_t - returns status of last read operation (always
|
||||
IPC_STATUS_ERROR or IPC_STATUS_EOF).
|
||||
|
||||
GLOBAL VARIABLES
|
||||
|
||||
NONE
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
NONE
|
||||
|
||||
=============================================================================*/
|
||||
|
||||
|
||||
Ipc_Status_t
|
||||
ipc_transport_terminate_server (void)
|
||||
{
|
||||
char buffer[17000]; /* temp buffer for incoming data */
|
||||
int len; /* placeholder var to as arg to function */
|
||||
Ipc_Status_t status; /* value to be returned from function */
|
||||
int max_size; /* Max length of buffer */
|
||||
|
||||
max_size = sizeof (buffer);
|
||||
do {
|
||||
len = max_size;
|
||||
status = ipc_transport_get_line (buffer, &len, IPC_WAIT);
|
||||
} while ((status != IPC_STATUS_ERROR) &&
|
||||
(status != IPC_STATUS_EOF));
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif /* IPC_UNIX_SOCKETS */
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Steve Tynor
|
||||
*
|
||||
* Generic Interprocess Communication module
|
||||
*
|
||||
* Used for debugging in absense of IPC interface.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
|
||||
#ifdef IPC_DEBUG_VIA_STDIO
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include "ngspice/ipc.h"
|
||||
|
||||
#include "ngspice/ipcproto.h"
|
||||
|
||||
#include <assert.h> /* 12/1/97 jg */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
Ipc_Status_t ipc_transport_initialize_server (
|
||||
char *server_name,
|
||||
Ipc_Mode_t m,
|
||||
Ipc_Protocol_t p,
|
||||
char *batch_filename )
|
||||
{
|
||||
NG_IGNORE(server_name);
|
||||
NG_IGNORE(p);
|
||||
NG_IGNORE(batch_filename);
|
||||
|
||||
assert (m == IPC_MODE_INTERACTIVE);
|
||||
printf ("INITIALIZE_SERVER\n");
|
||||
return IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
Ipc_Status_t ipc_transport_get_line (
|
||||
char *str,
|
||||
int *len,
|
||||
Ipc_Wait_t wait )
|
||||
{
|
||||
NG_IGNORE(wait);
|
||||
|
||||
printf ("GET_LINE\n");
|
||||
fgets (str, 512, stdin);
|
||||
char *tmp = strchr(str, '\n');
|
||||
if (tmp)
|
||||
*tmp = '\0';
|
||||
*len = (int) strlen (str);
|
||||
return IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
Ipc_Status_t ipc_transport_send_line (
|
||||
char *str,
|
||||
int len )
|
||||
{
|
||||
int i;
|
||||
|
||||
printf ("SEND_LINE: /");
|
||||
for (i = 0; i < len; i++)
|
||||
putchar (str[i]);
|
||||
printf ("/\n");
|
||||
return IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
Ipc_Status_t ipc_transport_terminate_server (void)
|
||||
{
|
||||
return IPC_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif /* IPC_DEBUG_VIA_STDIO */
|
||||
|
|
@ -1,520 +0,0 @@
|
|||
/*============================================================================
|
||||
FILE IPCtiein.c
|
||||
|
||||
MEMBER OF process XSPICE
|
||||
|
||||
Public Domain
|
||||
|
||||
Georgia Tech Research Corporation
|
||||
Atlanta, Georgia 30332
|
||||
PROJECT A-8503
|
||||
|
||||
AUTHORS
|
||||
|
||||
9/12/91 Bill Kuhn
|
||||
|
||||
MODIFICATIONS
|
||||
|
||||
<date> <person name> <nature of modifications>
|
||||
|
||||
SUMMARY
|
||||
|
||||
Provides a protocol independent interface between the simulator
|
||||
and the IPC method used to interface to CAE packages.
|
||||
|
||||
INTERFACES
|
||||
|
||||
g_ipc (global variable)
|
||||
|
||||
ipc_handle_stop()
|
||||
ipc_handle_returni()
|
||||
ipc_handle_mintime()
|
||||
ipc_handle_vtrans()
|
||||
ipc_send_stdout()
|
||||
ipc_send_stderr()
|
||||
ipc_send_std_files()
|
||||
ipc_screen_name()
|
||||
ipc_get_devices()
|
||||
ipc_free_devices()
|
||||
ipc_check_pause_stop()
|
||||
|
||||
REFERENCED FILES
|
||||
|
||||
None.
|
||||
|
||||
NON-STANDARD FEATURES
|
||||
|
||||
None.
|
||||
|
||||
============================================================================*/
|
||||
|
||||
|
||||
#define CONFIG
|
||||
|
||||
#include "ngspice/ngspice.h"
|
||||
#include "ngspice/inpdefs.h"
|
||||
#include "ngspice/gendefs.h"
|
||||
#include "ngspice/cktdefs.h"
|
||||
#include "bjt/bjtdefs.h"
|
||||
#include "jfet/jfetdefs.h"
|
||||
#include "mos1/mos1defs.h"
|
||||
#include "mos2/mos2defs.h"
|
||||
#include "mos3/mos3defs.h"
|
||||
#include "ngspice/mifproto.h"
|
||||
#include "ngspice/ipc.h"
|
||||
#include "ngspice/ipctiein.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Global variable g_ipc is used by the SPICE mods that take care of
|
||||
interprocess communications activities.
|
||||
*/
|
||||
|
||||
|
||||
Ipc_Tiein_t g_ipc = {
|
||||
IPC_FALSE, /* enabled */
|
||||
IPC_MODE_INTERACTIVE, /* mode */
|
||||
IPC_ANAL_DCOP, /* analysis mode */
|
||||
IPC_FALSE, /* parse_error */
|
||||
IPC_FALSE, /* run_error */
|
||||
IPC_FALSE, /* errchk_sent */
|
||||
IPC_FALSE, /* returni */
|
||||
0.0, /* mintime */
|
||||
0.0, /* lasttime */
|
||||
0.0, /* cpu time */
|
||||
NULL, /* send array */
|
||||
NULL, /* log file */
|
||||
{ /* vtrans struct */
|
||||
0, /* size */
|
||||
NULL, /* vsrc_name array */
|
||||
NULL, /* device_name array */
|
||||
},
|
||||
IPC_FALSE, /* stop analysis */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
ipc_handle_stop
|
||||
|
||||
This function sets a flag in the g_ipc variable to signal that
|
||||
a stop message has been received over the IPC channel.
|
||||
*/
|
||||
|
||||
void ipc_handle_stop(void)
|
||||
{
|
||||
g_ipc.stop_analysis = IPC_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ipc_handle_returni
|
||||
|
||||
This function sets a flag in the g_ipc variable to signal that
|
||||
a message has been received over the IPC channel specifying that
|
||||
current values are to be returned in the results data sets.
|
||||
*/
|
||||
|
||||
void ipc_handle_returni(void)
|
||||
{
|
||||
g_ipc.returni = IPC_TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ipc_handle_mintime
|
||||
|
||||
This function sets a value in the g_ipc variable that specifies
|
||||
how often data is to be returned as it is computed. If the
|
||||
simulator takes timestep backups, data may still be returned
|
||||
more often that that specified by 'mintime' so that glitches
|
||||
are not missed.
|
||||
*/
|
||||
|
||||
void ipc_handle_mintime(double time)
|
||||
{
|
||||
g_ipc.mintime = time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
ipc_handle_vtrans
|
||||
|
||||
This function processes arguments from a #VTRANS card received over
|
||||
the IPC channel. The data on the card specifies that a particular
|
||||
zero-valued voltage source name should be translated to the specified
|
||||
instance name for which it was setup to monitor currents.
|
||||
*/
|
||||
|
||||
void ipc_handle_vtrans(
|
||||
char *vsrc, /* The name of the voltage source to be translated */
|
||||
char *dev) /* The device name the vsource name should be translated to */
|
||||
{
|
||||
int i;
|
||||
int size;
|
||||
|
||||
|
||||
if(g_ipc.vtrans.size == 0) {
|
||||
g_ipc.vtrans.size = 1;
|
||||
g_ipc.vtrans.vsrc_name = TMALLOC(char *, 1);
|
||||
g_ipc.vtrans.device_name = TMALLOC(char *, 1);
|
||||
g_ipc.vtrans.vsrc_name[0] = MIFcopy(vsrc);
|
||||
g_ipc.vtrans.device_name[0] = MIFcopy(dev);
|
||||
}
|
||||
else {
|
||||
g_ipc.vtrans.size++;
|
||||
|
||||
size = g_ipc.vtrans.size;
|
||||
i = g_ipc.vtrans.size - 1;
|
||||
|
||||
g_ipc.vtrans.vsrc_name = TREALLOC(char *, g_ipc.vtrans.vsrc_name, size);
|
||||
g_ipc.vtrans.device_name = TREALLOC(char *, g_ipc.vtrans.device_name, size);
|
||||
g_ipc.vtrans.vsrc_name[i] = MIFcopy(vsrc);
|
||||
g_ipc.vtrans.device_name[i] = MIFcopy(dev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
ipc_send_stdout
|
||||
|
||||
This function sends the data written to stdout over the IPC channel.
|
||||
This stream was previously redirected to a temporary file during
|
||||
the simulation.
|
||||
*/
|
||||
|
||||
void ipc_send_stdout(void)
|
||||
{
|
||||
int c;
|
||||
int len;
|
||||
|
||||
char buf[IPC_MAX_LINE_LEN+1];
|
||||
|
||||
/* rewind the redirected stdout stream */
|
||||
rewind(stdout);
|
||||
|
||||
/* Begin reading from the top of file and send lines */
|
||||
/* over the IPC channel. */
|
||||
|
||||
/* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */
|
||||
/* we must wrap it because Mspice can't handle it */
|
||||
|
||||
len = 0;
|
||||
while( (c=fgetc(stdout)) != EOF) {
|
||||
if(c != '\n') {
|
||||
buf[len] = (char) c;
|
||||
len++;
|
||||
}
|
||||
if((c == '\n') || (len == IPC_MAX_LINE_LEN)) {
|
||||
buf[len] = '\0';
|
||||
ipc_send_line(buf);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
if(len > 0) {
|
||||
buf[len] = '\0';
|
||||
ipc_send_line(buf);
|
||||
}
|
||||
|
||||
/* Finally, rewind file again to discard the data already sent */
|
||||
rewind(stdout);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ipc_send_stderr
|
||||
|
||||
This function sends the data written to stderr over the IPC channel.
|
||||
This stream was previously redirected to a temporary file during
|
||||
the simulation.
|
||||
*/
|
||||
|
||||
void ipc_send_stderr(void)
|
||||
{
|
||||
int c;
|
||||
int len;
|
||||
|
||||
char buf[IPC_MAX_LINE_LEN+1];
|
||||
|
||||
/* rewind the redirected stderr stream */
|
||||
rewind(stderr);
|
||||
|
||||
/* Begin reading from the top of file and send lines */
|
||||
/* over the IPC channel. */
|
||||
|
||||
/* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */
|
||||
/* we must wrap it because Mspice can't handle it */
|
||||
|
||||
len = 0;
|
||||
while( (c=fgetc(stderr)) != EOF) {
|
||||
if(c != '\n') {
|
||||
buf[len] = (char) c;
|
||||
len++;
|
||||
}
|
||||
if((c == '\n') || (len == IPC_MAX_LINE_LEN)) {
|
||||
buf[len] = '\0';
|
||||
ipc_send_line(buf);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
if(len > 0) {
|
||||
buf[len] = '\0';
|
||||
ipc_send_line(buf);
|
||||
}
|
||||
|
||||
/* Finally, rewind file again to discard the data already sent */
|
||||
rewind(stderr);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ipc_send_std_files
|
||||
|
||||
This function sends the data written to stdout and stderr over the
|
||||
IPC channel. These streams were previously redirected to temporary
|
||||
files during the simulation.
|
||||
*/
|
||||
|
||||
Ipc_Status_t ipc_send_std_files(void)
|
||||
{
|
||||
ipc_send_stdout();
|
||||
ipc_send_stderr();
|
||||
|
||||
return(ipc_flush());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
ipc_screen_name
|
||||
|
||||
This function screens names of instances and nodes to limit the
|
||||
data returned over the IPC channel.
|
||||
*/
|
||||
|
||||
Ipc_Boolean_t ipc_screen_name(char *name, char *mapped_name)
|
||||
{
|
||||
char *endp;
|
||||
int i;
|
||||
int len;
|
||||
long l;
|
||||
|
||||
/* Return FALSE if name is in a subcircuit */
|
||||
for(i = 0; name[i] != '\0'; i++) {
|
||||
if(name[i] == ':')
|
||||
return(IPC_FALSE);
|
||||
}
|
||||
|
||||
/* Determine if name is numeric and what value is */
|
||||
l = strtol(name, &endp, 10);
|
||||
|
||||
/* If numeric */
|
||||
if(*endp == '\0') {
|
||||
/* Return FALSE if >100,000 -> added by ms_server in ATESSE 1.0 */
|
||||
if(l >= 100000)
|
||||
return(IPC_FALSE);
|
||||
/* Otherwise, copy name to mapped name and return true */
|
||||
else {
|
||||
strcpy(mapped_name,name);
|
||||
return(IPC_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* If node is an internal node from a semiconductor (indicated by a */
|
||||
/* trailing #collector, #source, ...), do not return its current. */
|
||||
/* Otherwise, map to upper case and eliminate trailing "#branch" if any. */
|
||||
for(i = 0; name[i]; i++) {
|
||||
if(name[i] == '#') {
|
||||
if(strcmp(name + i, "#branch") == 0)
|
||||
break;
|
||||
else
|
||||
return(IPC_FALSE);
|
||||
}
|
||||
else {
|
||||
if(islower_c(name[i]))
|
||||
mapped_name[i] = toupper_c(name[i]);
|
||||
else
|
||||
mapped_name[i] = name[i];
|
||||
}
|
||||
}
|
||||
mapped_name[i] = '\0';
|
||||
len = i;
|
||||
|
||||
/* If len != 8 or 6'th char not equal to $, then doesn't need vtrans */
|
||||
/* Otherwise, translate to device name that it monitors */
|
||||
if(len != 8)
|
||||
return(IPC_TRUE);
|
||||
else if(name[5] != '$')
|
||||
return(IPC_TRUE);
|
||||
else {
|
||||
/* Scan list of prefixes in VTRANS table and convert name */
|
||||
for(i = 0; i < g_ipc.vtrans.size; i++) {
|
||||
if(strncmp(mapped_name, g_ipc.vtrans.vsrc_name[i], 5) == 0) {
|
||||
strcpy(mapped_name, g_ipc.vtrans.device_name[i]);
|
||||
return(IPC_TRUE);
|
||||
}
|
||||
}
|
||||
return(IPC_TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
ipc_get_devices
|
||||
|
||||
This function is used to setup the OUTinterface data structure that
|
||||
determines what instances will have data returned over the IPC channel.
|
||||
*/
|
||||
|
||||
|
||||
int ipc_get_devices(
|
||||
CKTcircuit *ckt, /* The circuit structure */
|
||||
char *device, /* The device name as it appears in the info struct */
|
||||
char ***names, /* Array of name strings to be built */
|
||||
double **modtypes) /* Array of types to be built */
|
||||
{
|
||||
int index;
|
||||
int num_instances;
|
||||
GENmodel *model;
|
||||
GENinstance *here;
|
||||
char *inst_name;
|
||||
int inst_name_len;
|
||||
int i;
|
||||
|
||||
BJTmodel *BJTmod;
|
||||
JFETmodel *JFETmod;
|
||||
MOS1model *MOS1mod;
|
||||
MOS2model *MOS2mod;
|
||||
MOS3model *MOS3mod;
|
||||
|
||||
/* Initialize local variables */
|
||||
num_instances = 0;
|
||||
|
||||
/* Get the index into the circuit structure linked list of models */
|
||||
index = INPtypelook(device);
|
||||
|
||||
/* Iterate through all models of this type */
|
||||
for(model = ckt->CKThead[index]; model; model = model->GENnextModel) {
|
||||
|
||||
/* Iterate through all instance of this model */
|
||||
for(here = model->GENinstances; here; here = here->GENnextInstance) {
|
||||
|
||||
/* Get the name of the instance */
|
||||
inst_name = here->GENname;
|
||||
inst_name_len = (int) strlen(inst_name);
|
||||
|
||||
/* Skip if it is a inside a subcircuit */
|
||||
for(i = 0; i < inst_name_len; i++)
|
||||
if(inst_name[i] == ':')
|
||||
break;
|
||||
if(i < inst_name_len)
|
||||
continue;
|
||||
|
||||
/* Otherwise, add the name to the list */
|
||||
num_instances++;
|
||||
if(num_instances == 1)
|
||||
*names = TMALLOC(char *, 1);
|
||||
else
|
||||
*names = TREALLOC(char *, *names, num_instances);
|
||||
(*names)[num_instances-1] = MIFcopy(inst_name);
|
||||
|
||||
/* Then get the type if it is a Q J or M */
|
||||
if(num_instances == 1)
|
||||
*modtypes = TMALLOC(double, 1);
|
||||
else
|
||||
*modtypes = TREALLOC(double, *modtypes, num_instances);
|
||||
|
||||
if(strcmp(device,"BJT") == 0) {
|
||||
BJTmod = (BJTmodel *) model;
|
||||
(*modtypes)[num_instances-1] = BJTmod->BJTtype;
|
||||
}
|
||||
else if(strcmp(device,"JFET") == 0) {
|
||||
JFETmod = (JFETmodel *) model;
|
||||
(*modtypes)[num_instances-1] = JFETmod->JFETtype;
|
||||
}
|
||||
else if(strcmp(device,"Mos1") == 0) {
|
||||
MOS1mod = (MOS1model *) model;
|
||||
(*modtypes)[num_instances-1] = MOS1mod->MOS1type;
|
||||
}
|
||||
else if(strcmp(device,"Mos2") == 0) {
|
||||
MOS2mod = (MOS2model *) model;
|
||||
(*modtypes)[num_instances-1] = MOS2mod->MOS2type;
|
||||
}
|
||||
else if(strcmp(device,"Mos3") == 0) {
|
||||
MOS3mod = (MOS3model *) model;
|
||||
(*modtypes)[num_instances-1] = MOS3mod->MOS3type;
|
||||
}
|
||||
else {
|
||||
(*modtypes)[num_instances-1] = 1.0;
|
||||
}
|
||||
|
||||
} /* end for all instances */
|
||||
} /* end for all models */
|
||||
|
||||
return(num_instances);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
ipc_free_devices
|
||||
|
||||
This function frees temporary data created by ipc_get_devices().
|
||||
*/
|
||||
|
||||
|
||||
void ipc_free_devices(
|
||||
int num_items, /* Number of things to free */
|
||||
char **names, /* Array of name strings to be built */
|
||||
double *modtypes) /* Array of types to be built */
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < num_items; i++)
|
||||
{
|
||||
FREE(names[i]);
|
||||
names[i] = NULL;
|
||||
}
|
||||
|
||||
if(num_items > 0)
|
||||
{
|
||||
FREE(names);
|
||||
FREE(modtypes);
|
||||
|
||||
names = NULL;
|
||||
modtypes = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ipc_check_pause_stop
|
||||
|
||||
This function is called at various times during a simulation to check
|
||||
for incoming messages of the form >STOP or >PAUSE signaling that
|
||||
simulation should be stopped or paused. Processing of the messages
|
||||
is handled by ipc_get_line().
|
||||
*/
|
||||
|
||||
void ipc_check_pause_stop(void)
|
||||
{
|
||||
char buf[1025];
|
||||
int len;
|
||||
|
||||
/* If already seen stop analysis, don't call ipc_get_line, just return. */
|
||||
/* This is provided so that the function can be called multiple times */
|
||||
/* during the process of stopping */
|
||||
if(g_ipc.stop_analysis)
|
||||
return;
|
||||
|
||||
/* Otherwise do a non-blocking call to ipc_get_line() to check for messages. */
|
||||
/* We assume that the only possible messages at this point are >PAUSE */
|
||||
/* and >STOP, so we don't do anything with the returned text if any */
|
||||
ipc_get_line(buf, &len, IPC_NO_WAIT);
|
||||
}
|
||||
|
||||
|
|
@ -740,7 +740,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClInclude Include="..\src\include\ngspice\ciderinp.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cidersupt.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cktdefs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cluster.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cm.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cmconstants.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cmproto.h" />
|
||||
|
|
@ -795,8 +794,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClInclude Include="..\src\include\ngspice\inpmacs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipc.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipcproto.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipctiein.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\jobdefs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
||||
|
|
@ -1544,7 +1541,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClCompile Include="..\src\spicelib\analysis\ckttroub.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\ckttrunc.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\ckttyplk.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\cluster.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\daskq.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\dcoaskq.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\dcop.c" />
|
||||
|
|
@ -2614,11 +2610,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClCompile Include="..\src\xspice\evt\evtshared.c" />
|
||||
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
||||
<ClCompile Include="..\src\xspice\idn\idndig.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipc.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcaegis.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcsockets.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcstdio.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipctiein.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mif.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
||||
|
|
|
|||
|
|
@ -47,9 +47,6 @@
|
|||
/* Define to 1 if the `closedir' function returns void instead of `int'. */
|
||||
/* #undef CLOSEDIR_VOID */
|
||||
|
||||
/* Spice cluster support */
|
||||
/* #undef CLUSTER */
|
||||
|
||||
/* Define if you want to debug ngspice shell */
|
||||
/* #undef CPDEBUG */
|
||||
|
||||
|
|
|
|||
|
|
@ -956,7 +956,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClInclude Include="..\src\include\ngspice\ciderinp.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cidersupt.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cktdefs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cluster.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cm.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cmconstants.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cmproto.h" />
|
||||
|
|
@ -1012,8 +1011,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClInclude Include="..\src\include\ngspice\inpmacs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipc.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipcproto.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipctiein.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\jobdefs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
||||
|
|
@ -1765,7 +1762,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClCompile Include="..\src\spicelib\analysis\ckttroub.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\ckttrunc.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\ckttyplk.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\cluster.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\daskq.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\dcoaskq.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\dcop.c" />
|
||||
|
|
@ -2835,11 +2831,6 @@ lib /machine:x64 /def:..\..\fftw-3.3-dll64\libfftw3-3.def /out:$(IntDir)libfftw3
|
|||
<ClCompile Include="..\src\xspice\evt\evtsetup.c" />
|
||||
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
||||
<ClCompile Include="..\src\xspice\idn\idndig.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipc.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcaegis.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcsockets.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcstdio.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipctiein.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mif.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
||||
|
|
|
|||
|
|
@ -971,7 +971,6 @@
|
|||
<ClInclude Include="..\src\include\ngspice\ciderinp.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cidersupt.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cktdefs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cluster.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cm.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cmconstants.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\cmproto.h" />
|
||||
|
|
@ -1027,8 +1026,6 @@
|
|||
<ClInclude Include="..\src\include\ngspice\inpmacs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipc.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipcproto.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\ipctiein.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\jobdefs.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
||||
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
||||
|
|
@ -1779,7 +1776,6 @@
|
|||
<ClCompile Include="..\src\spicelib\analysis\ckttroub.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\ckttrunc.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\ckttyplk.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\cluster.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\daskq.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\dcoaskq.c" />
|
||||
<ClCompile Include="..\src\spicelib\analysis\dcop.c" />
|
||||
|
|
@ -2849,11 +2845,6 @@
|
|||
<ClCompile Include="..\src\xspice\evt\evtsetup.c" />
|
||||
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
||||
<ClCompile Include="..\src\xspice\idn\idndig.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipc.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcaegis.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcsockets.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipcstdio.c" />
|
||||
<ClCompile Include="..\src\xspice\ipc\ipctiein.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mif.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
||||
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
||||
|
|
|
|||
Loading…
Reference in New Issue