Merge branch 'pre-master-46' into bt_dev

This commit is contained in:
Brian Taylor 2025-12-14 13:57:30 -08:00
commit e29452bdab
67 changed files with 1390 additions and 4808 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,6 @@ noinst_HEADERS = \
ciderinp.h \
cidersupt.h \
cktdefs.h \
cluster.h \
cmconstants.h \
cm.h \
cmproto.h \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -258,13 +258,7 @@ IFfrontEnd nutmeginfo = {
OUTerrorf,
OUTpBeginPlot,
OUTpData,
OUTwBeginPlot,
OUTwReference,
OUTwData,
OUTwEnd,
OUTendPlot,
OUTbeginDomain,
OUTendDomain,
OUTattributes
};

View File

@ -98,8 +98,7 @@ libckt_la_SOURCES = \
tfsetp.c \
tranaskq.c \
traninit.c \
transetp.c \
cluster.c
transetp.c
if PSS_WANTED

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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