Remove all entries connected to IPC, an outdated (>30 years)
method to link ngspice to a now defunct controller (ATESSE).
This commit is contained in:
parent
7fbb4450d4
commit
4d24b18f35
|
|
@ -1428,7 +1428,6 @@ AC_CONFIG_FILES([Makefile
|
||||||
src/xspice/mif/Makefile
|
src/xspice/mif/Makefile
|
||||||
src/xspice/evt/Makefile
|
src/xspice/evt/Makefile
|
||||||
src/xspice/enh/Makefile
|
src/xspice/enh/Makefile
|
||||||
src/xspice/ipc/Makefile
|
|
||||||
src/xspice/idn/Makefile
|
src/xspice/idn/Makefile
|
||||||
src/xspice/verilog/Makefile
|
src/xspice/verilog/Makefile
|
||||||
src/xspice/vhdl/Makefile
|
src/xspice/vhdl/Makefile
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,6 @@ ngspice_LDADD += \
|
||||||
xspice/mif/libmifxsp.la \
|
xspice/mif/libmifxsp.la \
|
||||||
xspice/evt/libevtxsp.la \
|
xspice/evt/libevtxsp.la \
|
||||||
xspice/enh/libenhxsp.la \
|
xspice/enh/libenhxsp.la \
|
||||||
xspice/ipc/libipcxsp.la \
|
|
||||||
xspice/idn/libidnxsp.la
|
xspice/idn/libidnxsp.la
|
||||||
endif
|
endif
|
||||||
ngspice_LDADD += $(XSPICEDLLIBS)
|
ngspice_LDADD += $(XSPICEDLLIBS)
|
||||||
|
|
@ -459,7 +458,6 @@ if XSPICE_WANTED
|
||||||
libspice_la_LIBADD += \
|
libspice_la_LIBADD += \
|
||||||
xspice/evt/libevtxsp.la \
|
xspice/evt/libevtxsp.la \
|
||||||
xspice/enh/libenhxsp.la \
|
xspice/enh/libenhxsp.la \
|
||||||
xspice/ipc/libipcxsp.la \
|
|
||||||
xspice/idn/libidnxsp.la
|
xspice/idn/libidnxsp.la
|
||||||
endif
|
endif
|
||||||
libspice_la_LIBADD += $(XSPICEDLLIBS)
|
libspice_la_LIBADD += $(XSPICEDLLIBS)
|
||||||
|
|
@ -586,7 +584,6 @@ if XSPICE_WANTED
|
||||||
libngspice_la_LIBADD += \
|
libngspice_la_LIBADD += \
|
||||||
xspice/evt/libevtxsp.la \
|
xspice/evt/libevtxsp.la \
|
||||||
xspice/enh/libenhxsp.la \
|
xspice/enh/libenhxsp.la \
|
||||||
xspice/ipc/libipcxsp.la \
|
|
||||||
xspice/idn/libidnxsp.la
|
xspice/idn/libidnxsp.la
|
||||||
endif
|
endif
|
||||||
libngspice_la_LIBADD += $(XSPICEDLLIBS)
|
libngspice_la_LIBADD += $(XSPICEDLLIBS)
|
||||||
|
|
|
||||||
|
|
@ -244,13 +244,6 @@ inp_list(FILE *file, struct card *deck, struct card *extras, int type)
|
||||||
bool useout = (file == cp_out);
|
bool useout = (file == cp_out);
|
||||||
int i = 1;
|
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) {
|
if (useout) {
|
||||||
out_init();
|
out_init();
|
||||||
file = cp_more;
|
file = cp_more;
|
||||||
|
|
@ -1474,10 +1467,6 @@ inp_dodeck(
|
||||||
|
|
||||||
if (dd->error) {
|
if (dd->error) {
|
||||||
char *p, *q;
|
char *p, *q;
|
||||||
#ifdef XSPICE
|
|
||||||
/* add setting of ipc syntax error flag */
|
|
||||||
g_ipc.syntax_error = IPC_TRUE;
|
|
||||||
#endif
|
|
||||||
p = dd->error;
|
p = dd->error;
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
do {
|
do {
|
||||||
|
|
|
||||||
|
|
@ -1355,12 +1355,7 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name
|
||||||
else {
|
else {
|
||||||
|
|
||||||
#ifdef XSPICE
|
#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) {
|
if (call_depth == 0 && line_count == 0) {
|
||||||
line_count++;
|
line_count++;
|
||||||
if (fgets(big_buff, 5000, fp))
|
if (fgets(big_buff, 5000, fp))
|
||||||
|
|
@ -1371,31 +1366,7 @@ static struct inp_read_t inp_read(FILE* fp, int call_depth, const char* dir_name
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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;
|
|
||||||
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
|
#else
|
||||||
|
|
||||||
buffer = readline(fp);
|
buffer = readline(fp);
|
||||||
|
|
|
||||||
|
|
@ -213,14 +213,6 @@ printres(char *name)
|
||||||
called = TRUE;
|
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;
|
yy = TRUE;
|
||||||
#else
|
#else
|
||||||
if (!name || eq(name, "totalcputime"))
|
if (!name || eq(name, "totalcputime"))
|
||||||
|
|
|
||||||
|
|
@ -323,14 +323,6 @@ static int dosim(
|
||||||
if (if_sens_run(ft_curckt->ci_ckt, ww, ft_curckt->ci_symtab) == 1) {
|
if (if_sens_run(ft_curckt->ci_ckt, ww, ft_curckt->ci_symtab) == 1) {
|
||||||
/* The circuit was interrupted somewhere. */
|
/* The circuit was interrupted somewhere. */
|
||||||
fprintf(cp_err, "%s simulation interrupted\n", what);
|
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 {
|
else {
|
||||||
ft_curckt->ci_inprogress = FALSE;
|
ft_curckt->ci_inprogress = FALSE;
|
||||||
|
|
@ -342,14 +334,6 @@ static int dosim(
|
||||||
if (err == 1) {
|
if (err == 1) {
|
||||||
/* The circuit was interrupted somewhere. */
|
/* The circuit was interrupted somewhere. */
|
||||||
fprintf(cp_err, "%s simulation interrupted\n", what);
|
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;
|
err = 0;
|
||||||
}
|
}
|
||||||
else if (err == 2) {
|
else if (err == 2) {
|
||||||
|
|
|
||||||
|
|
@ -62,16 +62,9 @@ ACan(CKTcircuit* ckt, int restart)
|
||||||
|
|
||||||
|
|
||||||
#ifdef XSPICE
|
#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 */
|
/* Tell the code models what mode we're in */
|
||||||
g_mif_info.circuit.anal_type = MIF_DC;
|
g_mif_info.circuit.anal_type = MIF_DC;
|
||||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
|
|
||||||
/* gtri - end - wbk */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* start at beginning */
|
/* start at beginning */
|
||||||
|
|
@ -152,40 +145,6 @@ ACan(CKTcircuit* ckt, int restart)
|
||||||
else
|
else
|
||||||
fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n");
|
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;
|
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
|
||||||
error = CKTload(ckt);
|
error = CKTload(ckt);
|
||||||
if (error) return(error);
|
if (error) return(error);
|
||||||
|
|
@ -376,21 +335,8 @@ ACan(CKTcircuit* ckt, int restart)
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
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) {
|
if (error) {
|
||||||
UPDATE_STATS(DOING_AC);
|
UPDATE_STATS(DOING_AC);
|
||||||
return(error);
|
return(error);
|
||||||
|
|
|
||||||
|
|
@ -157,51 +157,15 @@ CKTdoJob(CKTcircuit* ckt, int reset, TSKtask* task)
|
||||||
if (!error)
|
if (!error)
|
||||||
error = CKTunsetup(ckt);
|
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)
|
if (!error)
|
||||||
error = CKTsetup(ckt);
|
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)
|
if (!error)
|
||||||
error = CKTtemp(ckt);
|
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) {
|
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;
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
}/* if error */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error2 = OK;
|
error2 = OK;
|
||||||
|
|
|
||||||
|
|
@ -35,17 +35,12 @@ DCop(CKTcircuit *ckt, int notused)
|
||||||
NG_IGNORE(notused);
|
NG_IGNORE(notused);
|
||||||
|
|
||||||
#ifdef XSPICE
|
#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 */
|
/* Tell the code models what mode we're in */
|
||||||
g_mif_info.circuit.anal_type = MIF_DC;
|
g_mif_info.circuit.anal_type = MIF_DC;
|
||||||
|
|
||||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
|
|
||||||
/* gtri - end - wbk */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
error = CKTnames(ckt,&numNames,&nameList);
|
error = CKTnames(ckt,&numNames,&nameList);
|
||||||
|
|
@ -114,23 +109,9 @@ DCop(CKTcircuit *ckt, int notused)
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
converged = CKTload(ckt);
|
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) {
|
if(converged == 0) {
|
||||||
CKTdump(ckt, 0.0, plot);
|
CKTdump(ckt, 0.0, plot);
|
||||||
if (ckt->CKTsoaCheck)
|
if (ckt->CKTsoaCheck)
|
||||||
|
|
@ -138,7 +119,7 @@ DCop(CKTcircuit *ckt, int notused)
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,"error: circuit reload failed.\n");
|
fprintf(stderr,"error: circuit reload failed.\n");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
SPfrontEnd->OUTendPlot (plot);
|
SPfrontEnd->OUTendPlot (plot);
|
||||||
return(converged);
|
return(converged);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,15 +84,6 @@ DCpss(CKTcircuit *ckt,
|
||||||
|
|
||||||
int ltra_num;
|
int ltra_num;
|
||||||
CKTnode *node;
|
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
|
|
||||||
|
|
||||||
/* New variables */
|
/* New variables */
|
||||||
int j, oscnNode;
|
int j, oscnNode;
|
||||||
|
|
@ -216,15 +207,12 @@ DCpss(CKTcircuit *ckt,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and set anal_init and anal_type */
|
/* set anal_init and anal_type */
|
||||||
/* Tell the beginPlot routine what mode we're in */
|
|
||||||
g_ipc.anal_type = IPC_ANAL_TRAN;
|
|
||||||
|
|
||||||
/* Tell the code models what mode we're in */
|
/* Tell the code models what mode we're in */
|
||||||
g_mif_info.circuit.anal_type = MIF_DC;
|
g_mif_info.circuit.anal_type = MIF_DC;
|
||||||
|
|
||||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
/* gtri - end - wbk */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Time Domain plot start and prepared to be filled in later */
|
/* Time Domain plot start and prepared to be filled in later */
|
||||||
|
|
@ -298,35 +286,18 @@ DCpss(CKTcircuit *ckt,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If no convergence reached - NO valid Operating Point */
|
/* If no convergence reached - NO valid Operating Point */
|
||||||
if(converged != 0) return(converged);
|
if(converged != 0)
|
||||||
|
return(converged);
|
||||||
|
|
||||||
#ifdef XSPICE
|
#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;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
|
|
||||||
/* Tell the code models what mode we're in */
|
/* Tell the code models what mode we're in */
|
||||||
g_mif_info.circuit.anal_type = MIF_TRAN;
|
g_mif_info.circuit.anal_type = MIF_TRAN;
|
||||||
|
|
||||||
/* gtri - end - wbk */
|
|
||||||
|
|
||||||
/* gtri - begin - wbk - Add Breakpoint stuff */
|
|
||||||
|
|
||||||
/* Initialize the temporary breakpoint variables to infinity */
|
/* Initialize the temporary breakpoint variables to infinity */
|
||||||
g_mif_info.breakpoint.current = HUGE_VAL;
|
g_mif_info.breakpoint.current = HUGE_VAL;
|
||||||
g_mif_info.breakpoint.last = HUGE_VAL;
|
g_mif_info.breakpoint.last = HUGE_VAL;
|
||||||
|
|
||||||
/* gtri - end - wbk - Add Breakpoint stuff */
|
|
||||||
#endif
|
#endif
|
||||||
ckt->CKTstat->STATtimePts ++;
|
ckt->CKTstat->STATtimePts ++;
|
||||||
|
|
||||||
|
|
@ -434,52 +405,16 @@ DCpss(CKTcircuit *ckt,
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
|
||||||
|
|
||||||
if ((g_ipc.enabled) || wantevtdata) {
|
if (wantevtdata) {
|
||||||
|
|
||||||
if (pss_state == PSS)
|
if (pss_state == PSS)
|
||||||
{
|
{
|
||||||
/* Send event-driven results */
|
/* Send event-driven results */
|
||||||
EVTdump(ckt, IPC_ANAL_TRAN, 0.0);
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (pss_state == PSS)
|
if (pss_state == PSS)
|
||||||
|
|
|
||||||
|
|
@ -99,13 +99,6 @@ DCtran(CKTcircuit *ckt,
|
||||||
int ltra_num;
|
int ltra_num;
|
||||||
CKTnode *node;
|
CKTnode *node;
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* 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;
|
|
||||||
|
|
||||||
/* xspice_breakpoints_processed 0:
|
/* xspice_breakpoints_processed 0:
|
||||||
XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime].
|
XSPICE models didn't have breakpoints in [last_accepted_time, CKTtime].
|
||||||
xspice_breakpoints_processed 1:
|
xspice_breakpoints_processed 1:
|
||||||
|
|
@ -176,13 +169,9 @@ DCtran(CKTcircuit *ckt,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* Add IPC stuff and set anal_init and anal_type */
|
/* set anal_init and anal_type */
|
||||||
/* Tell the beginPlot routine what mode we're in */
|
|
||||||
g_ipc.anal_type = IPC_ANAL_TRAN;
|
|
||||||
|
|
||||||
/* Tell the code models what mode we're in */
|
/* Tell the code models what mode we're in */
|
||||||
g_mif_info.circuit.anal_type = MIF_DC;
|
g_mif_info.circuit.anal_type = MIF_DC;
|
||||||
|
|
||||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
#endif
|
#endif
|
||||||
/* Scan ckt->CKTnodes and create list of node names */
|
/* Scan ckt->CKTnodes and create list of node names */
|
||||||
|
|
@ -279,13 +268,6 @@ DCtran(CKTcircuit *ckt,
|
||||||
return(converged);
|
return(converged);
|
||||||
}
|
}
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* IPC stuff: Send the operating point results */
|
|
||||||
if(g_ipc.enabled) {
|
|
||||||
ipc_send_dcop_prefix();
|
|
||||||
CKTdump(ckt, 0.0, job->TRANplot);
|
|
||||||
ipc_send_dcop_suffix();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set anal_init and anal_type */
|
/* set anal_init and anal_type */
|
||||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
|
|
||||||
|
|
@ -420,59 +402,21 @@ DCtran(CKTcircuit *ckt,
|
||||||
UPDATE_STATS(DOING_TRAN);
|
UPDATE_STATS(DOING_TRAN);
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
|
/* Send evt data stuff in shared library */
|
||||||
/* Send IPC stuff */
|
if (wantevtdata) {
|
||||||
if ((g_ipc.enabled) || wantevtdata) {
|
|
||||||
|
|
||||||
/* Send event-driven results */
|
/* Send event-driven results */
|
||||||
EVTdump(ckt, IPC_ANAL_TRAN, 0.0);
|
EVTdump(ckt, IPC_ANAL_TRAN, 0.0);
|
||||||
|
|
||||||
/* Then follow with analog results... */
|
/* 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;
|
|
||||||
}
|
|
||||||
/* End of Send IPC stuff*/
|
|
||||||
} else
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Output the data of the current accepted time point */
|
/* Output the data of the current accepted time point */
|
||||||
if((ckt->CKTmode&MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime)
|
if ((ckt->CKTmode & MODEUIC && ckt->CKTtime > 0 && ckt->CKTtime >= ckt->CKTinitTime)
|
||||||
|| (!(ckt->CKTmode&MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime))
|
|| (!(ckt->CKTmode & MODEUIC) && ckt->CKTtime >= ckt->CKTinitTime)) {
|
||||||
CKTdump(ckt, ckt->CKTtime, job->TRANplot);
|
CKTdump(ckt, ckt->CKTtime, job->TRANplot);
|
||||||
|
}
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* Update event queues/data for accepted timepoint */
|
/* Update event queues/data for accepted timepoint */
|
||||||
/* Note: this must be done AFTER sending results to SI so it can't
|
/* Note: this must be done AFTER sending results to SI so it can't
|
||||||
|
|
|
||||||
|
|
@ -165,17 +165,12 @@ DCtrCurv(CKTcircuit *ckt, int restart)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef XSPICE
|
#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 */
|
/* Tell the code models what mode we're in */
|
||||||
g_mif_info.circuit.anal_type = MIF_DC;
|
g_mif_info.circuit.anal_type = MIF_DC;
|
||||||
|
|
||||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
|
|
||||||
/* gtri - end - wbk */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
error = CKTnames(ckt, &numNames, &nameList);
|
error = CKTnames(ckt, &numNames, &nameList);
|
||||||
|
|
@ -383,18 +378,10 @@ DCtrCurv(CKTcircuit *ckt, int restart)
|
||||||
ckt->CKTtime = ckt->CKTtemp - CONSTCtoK;
|
ckt->CKTtime = ckt->CKTtemp - CONSTCtoK;
|
||||||
|
|
||||||
#ifdef XSPICE
|
#ifdef XSPICE
|
||||||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
|
||||||
|
|
||||||
/* If first time through, call CKTdump to output Operating Point info */
|
/* If first time through, call CKTdump to output Operating Point info */
|
||||||
/* for Mspice compatibility */
|
if (wantevtdata && firstTime) {
|
||||||
|
|
||||||
if (((g_ipc.enabled) || wantevtdata) && firstTime) {
|
|
||||||
ipc_send_dcop_prefix();
|
|
||||||
CKTdump(ckt, 0.0, plot);
|
CKTdump(ckt, 0.0, plot);
|
||||||
ipc_send_dcop_suffix();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* gtri - end - wbk */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WANT_SENSE2
|
#ifdef WANT_SENSE2
|
||||||
|
|
@ -435,25 +422,11 @@ DCtrCurv(CKTcircuit *ckt, int restart)
|
||||||
}
|
}
|
||||||
#endif
|
#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);
|
CKTdump(ckt,ckt->CKTtime,plot);
|
||||||
|
|
||||||
if (ckt->CKTsoaCheck)
|
if (ckt->CKTsoaCheck)
|
||||||
error = CKTsoaCheck(ckt);
|
error = CKTsoaCheck(ckt);
|
||||||
|
|
||||||
#ifdef XSPICE
|
|
||||||
if (g_ipc.enabled)
|
|
||||||
ipc_send_data_suffix();
|
|
||||||
|
|
||||||
/* gtri - end - wbk */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (firstTime) {
|
if (firstTime) {
|
||||||
firstTime = 0;
|
firstTime = 0;
|
||||||
if (ckt->CKTstate1 && ckt->CKTstate0) {
|
if (ckt->CKTstate1 && ckt->CKTstate0) {
|
||||||
|
|
|
||||||
|
|
@ -65,16 +65,9 @@ NOISEan(CKTcircuit* ckt, int restart)
|
||||||
runDesc* plot = NULL;
|
runDesc* plot = NULL;
|
||||||
|
|
||||||
#ifdef XSPICE
|
#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 */
|
/* Tell the code models what mode we're in */
|
||||||
g_mif_info.circuit.anal_type = MIF_DC;
|
g_mif_info.circuit.anal_type = MIF_DC;
|
||||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
|
|
||||||
/* gtri - end - wbk */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef KLU
|
#ifdef KLU
|
||||||
|
|
@ -220,43 +213,8 @@ NOISEan(CKTcircuit* ckt, int restart)
|
||||||
else {
|
else {
|
||||||
fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n");
|
fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XSPICE
|
|
||||||
} // end of no XSPICE event-driven instances
|
} // 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. */
|
/* Patch to noisean.c by Richard D. McRoberts. */
|
||||||
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
|
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
|
||||||
error = CKTload(ckt);
|
error = CKTload(ckt);
|
||||||
|
|
|
||||||
|
|
@ -386,18 +386,9 @@ SPan(CKTcircuit* ckt, int restart)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XSPICE
|
#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 */
|
/* Tell the code models what mode we're in */
|
||||||
g_mif_info.circuit.anal_type = MIF_DC;
|
g_mif_info.circuit.anal_type = MIF_DC;
|
||||||
g_mif_info.circuit.anal_init = MIF_TRUE;
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
||||||
|
|
||||||
/* gtri - end - wbk */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* start at beginning */
|
/* start at beginning */
|
||||||
|
|
@ -475,40 +466,6 @@ SPan(CKTcircuit* ckt, int restart)
|
||||||
else
|
else
|
||||||
fprintf(stdout, "\n Linear circuit, option noopac given: no OP analysis\n");
|
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;
|
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG;
|
||||||
error = CKTload(ckt);
|
error = CKTload(ckt);
|
||||||
if (error) return(error);
|
if (error) return(error);
|
||||||
|
|
@ -937,22 +894,8 @@ SPan(CKTcircuit* ckt, int restart)
|
||||||
data->lstFreq = freq;
|
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);
|
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) {
|
if (error) {
|
||||||
UPDATE_STATS(DOING_AC);
|
UPDATE_STATS(DOING_AC);
|
||||||
tfree(internalNoiseAN);
|
tfree(internalNoiseAN);
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ EXTRA_DIST = README examples icm xspice.c .gitignore \
|
||||||
tlines/msline_common.c tlines/msline_common.h \
|
tlines/msline_common.c tlines/msline_common.h \
|
||||||
tlines/tline_common.c tlines/tline_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:
|
dist-hook:
|
||||||
rm -f "$(distdir)/icm/makedefs"
|
rm -f "$(distdir)/icm/makedefs"
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,6 @@ NON-STANDARD FEATURES
|
||||||
#include "ngspice/evtproto.h"
|
#include "ngspice/evtproto.h"
|
||||||
#include "ngspice/evtudn.h"
|
#include "ngspice/evtudn.h"
|
||||||
|
|
||||||
#include "ngspice/ipc.h"
|
|
||||||
#include "ngspice/ipctiein.h"
|
|
||||||
#include "ngspice/ipcproto.h"
|
|
||||||
|
|
||||||
#ifdef SHARED_MODULE
|
#ifdef SHARED_MODULE
|
||||||
/* global flag, TRUE if callback is used */
|
/* global flag, TRUE if callback is used */
|
||||||
extern bool wantevtdata;
|
extern bool wantevtdata;
|
||||||
|
|
@ -76,13 +72,6 @@ static void EVTsharedsend_line(
|
||||||
int mode); /* mode (op, dc, tran) we are in */
|
int mode); /* mode (op, dc, tran) we are in */
|
||||||
#endif
|
#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
|
EVTdump
|
||||||
|
|
@ -129,250 +118,25 @@ void EVTdump(
|
||||||
double step) /* The sweep step for a DCTRCURVE analysis, or */
|
double step) /* The sweep step for a DCTRCURVE analysis, or */
|
||||||
/* 0.0 for DCOP and TRAN */
|
/* 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
|
#ifdef SHARED_MODULE
|
||||||
if((! g_ipc.enabled) && (!wantevtdata))
|
if (!wantevtdata)
|
||||||
return;
|
return;
|
||||||
if ((!g_ipc.enabled) && (wantevtdata)) {
|
else {
|
||||||
EVTshareddump(ckt, mode, step);
|
EVTshareddump(ckt, mode, step);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Return immediately if IPC is not enabled */
|
(void)*ckt;
|
||||||
if(! g_ipc.enabled)
|
(void)mode;
|
||||||
|
(void)step;
|
||||||
|
|
||||||
|
/* Return immediately */
|
||||||
return;
|
return;
|
||||||
#endif
|
#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
|
#ifdef SHARED_MODULE
|
||||||
static void EVTshareddump(
|
static void EVTshareddump(
|
||||||
CKTcircuit *ckt, /* The circuit structure */
|
CKTcircuit *ckt, /* The circuit structure */
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
## Process this file with automake to produce Makefile.in
|
|
||||||
#
|
|
||||||
# JW 3/9/01 - had a go and makeing an autoconf script.
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libipcxsp.la
|
|
||||||
|
|
||||||
libipcxsp_la_SOURCES = \
|
|
||||||
ipcaegis.c \
|
|
||||||
ipc.c \
|
|
||||||
ipcsockets.c \
|
|
||||||
ipcstdio.c \
|
|
||||||
ipctiein.c
|
|
||||||
|
|
||||||
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices
|
|
||||||
AM_CFLAGS = $(STATIC)
|
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = Makefile.in
|
|
||||||
|
|
@ -1,978 +0,0 @@
|
||||||
/*============================================================================
|
|
||||||
FILE IPC.c
|
|
||||||
|
|
||||||
MEMBER OF process XSPICE
|
|
||||||
|
|
||||||
Public Domain
|
|
||||||
|
|
||||||
Georgia Tech Research Corporation
|
|
||||||
Atlanta, Georgia 30332
|
|
||||||
PROJECT A-8503
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
9/12/91 Steve Tynor
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
6/13/92 Bill Kuhn Added some comments
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
Provides compatibility for the new SPICE simulator to both the MSPICE user
|
|
||||||
interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE
|
|
||||||
v.2 Simulator Interface and BCP (via Bsd Sockets).
|
|
||||||
|
|
||||||
The Interprocess Communications package provides functions
|
|
||||||
called to receive XSPICE decks from the ATESSE Simulator Interface
|
|
||||||
or Batch Control processes, and to return results to those
|
|
||||||
processes. Functions callable from the simulator packages include:
|
|
||||||
|
|
||||||
ipc_initialize_server
|
|
||||||
ipc_terminate_server
|
|
||||||
ipc_get_line
|
|
||||||
ipc_send_line
|
|
||||||
ipc_send_data_prefix
|
|
||||||
ipc_send_data_suffix
|
|
||||||
ipc_send_dcop_prefix
|
|
||||||
ipc_send_dcop_suffix
|
|
||||||
ipc_send_evtdict_prefix
|
|
||||||
ipc_send_evtdict_suffix
|
|
||||||
ipc_send_evtdata_prefix
|
|
||||||
ipc_send_evtdata_suffix
|
|
||||||
ipc_send_errchk
|
|
||||||
ipc_send_end
|
|
||||||
ipc_send_boolean
|
|
||||||
ipc_send_int
|
|
||||||
ipc_send_double
|
|
||||||
ipc_send_complex
|
|
||||||
ipc_send_event
|
|
||||||
ipc_flush
|
|
||||||
|
|
||||||
These functions communicate with a set of transport-level functions
|
|
||||||
that implement the interprocess communications under one of
|
|
||||||
the following protocol types determined by a compile-time option:
|
|
||||||
|
|
||||||
BSD UNIX Sockets
|
|
||||||
HP/Apollo Mailboxes
|
|
||||||
|
|
||||||
For each transport protocol, the following functions are written:
|
|
||||||
|
|
||||||
ipc_transport_initialize_server
|
|
||||||
ipc_transport_get_line
|
|
||||||
ipc_transport_terminate_server
|
|
||||||
ipc_transport_send_line
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
============================================================================*/
|
|
||||||
|
|
||||||
#include "ngspice/ngspice.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include "ngspice/memory.h" /* NOTE: I think this is a Sys5ism (there is not man
|
|
||||||
* page for it under Bsd, but it's in /usr/include
|
|
||||||
* and it has a BSD copyright header. Go figure.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ngspice/ipc.h"
|
|
||||||
#include "ngspice/ipctiein.h"
|
|
||||||
#include "ngspice/ipcproto.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Conditional compilation sanity check:
|
|
||||||
*/
|
|
||||||
#if !defined (IPC_AEGIS_MAILBOXES) && !defined (IPC_UNIX_SOCKETS)\
|
|
||||||
&& !defined (IPC_DEBUG_VIA_STDIO)
|
|
||||||
" compiler error - must specify a transport mechanism";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* static 'globals'
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* typedef unsigned char Buffer_Char_t; */
|
|
||||||
typedef char Buffer_Char_t;
|
|
||||||
|
|
||||||
#define OUT_BUFFER_SIZE 1000
|
|
||||||
#define MAX_NUM_RECORDS 200
|
|
||||||
static int end_of_record_index [MAX_NUM_RECORDS];
|
|
||||||
static int num_records;
|
|
||||||
static Buffer_Char_t out_buffer [OUT_BUFFER_SIZE];
|
|
||||||
static int fill_count;
|
|
||||||
|
|
||||||
static Ipc_Mode_t mode;
|
|
||||||
static Ipc_Protocol_t protocol;
|
|
||||||
static Ipc_Boolean_t end_of_deck_seen;
|
|
||||||
static int batch_fd;
|
|
||||||
|
|
||||||
#define FMT_BUFFER_SIZE 80
|
|
||||||
static char fmt_buffer [FMT_BUFFER_SIZE];
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
Ipc_Boolean_t
|
|
||||||
kw_match (char *keyword, char *str)
|
|
||||||
/*
|
|
||||||
* returns IPC_TRUE if the first `strlen(keyword)' characters of `str' match
|
|
||||||
* the ones in `keyword' - case sensitive
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
char *k = keyword;
|
|
||||||
char *s = str;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* quit if we run off the end of either string:
|
|
||||||
*/
|
|
||||||
while (*s && *k) {
|
|
||||||
if (*s != *k) {
|
|
||||||
return IPC_FALSE;
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* if we get this far, it sould be because we ran off the end of the
|
|
||||||
* keyword else we didn't match:
|
|
||||||
*/
|
|
||||||
return (*k == '\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_initialize_server
|
|
||||||
|
|
||||||
This function creates the interprocess communication channel
|
|
||||||
server mailbox or socket.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_initialize_server (
|
|
||||||
char *server_name, /* Mailbox path or host/portnumber pair */
|
|
||||||
Ipc_Mode_t m, /* Interactive or batch */
|
|
||||||
Ipc_Protocol_t p ) /* Type of IPC protocol */
|
|
||||||
/*
|
|
||||||
* For mailboxes, `server_name' would be the mailbox pathname; for
|
|
||||||
* sockets, this needs to be a host/portnumber pair. Maybe this should be
|
|
||||||
* automatically generated by the routine...
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Ipc_Status_t status;
|
|
||||||
char batch_filename [1025];
|
|
||||||
|
|
||||||
mode = m;
|
|
||||||
protocol = p;
|
|
||||||
end_of_deck_seen = IPC_FALSE;
|
|
||||||
|
|
||||||
num_records = 0;
|
|
||||||
fill_count = 0;
|
|
||||||
|
|
||||||
status = ipc_transport_initialize_server (server_name, m, p,
|
|
||||||
batch_filename);
|
|
||||||
|
|
||||||
if (status != IPC_STATUS_OK) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: error initializing server\n");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == IPC_MODE_BATCH) {
|
|
||||||
#ifdef IPC_AEGIS_MAILBOXES
|
|
||||||
strcat (batch_filename, ".log");
|
|
||||||
#endif
|
|
||||||
batch_fd = open (batch_filename, O_WRONLY | O_CREAT, 0666);
|
|
||||||
if (batch_fd < 0) {
|
|
||||||
/* fprintf (stderr, "ERROR: IPC: Error opening batch output file: %s\n",batch_filename); */
|
|
||||||
perror ("IPC");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_terminate_server
|
|
||||||
|
|
||||||
This function deallocates the interprocess communication channel
|
|
||||||
mailbox or socket.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_terminate_server (void)
|
|
||||||
{
|
|
||||||
return ipc_transport_terminate_server ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_get_line
|
|
||||||
|
|
||||||
This function gets a SPICE deck input line from the interprocess
|
|
||||||
communication channel. Any special control commands in the deck
|
|
||||||
beginning with a ``>'' or ``#'' character are processed internally by
|
|
||||||
this function and not returned to SPICE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_get_line (
|
|
||||||
char *str, /* Text retrieved from IPC channel */
|
|
||||||
int *len, /* Length of text string */
|
|
||||||
Ipc_Wait_t wait ) /* Select blocking or non-blocking */
|
|
||||||
/*
|
|
||||||
* Reads one SPICE line from the connection. Strips any control lines
|
|
||||||
* which cannot be interpretted by the simulator (e.g. >INQCON) and
|
|
||||||
* processes them. If such a line is read, it is processed and the next
|
|
||||||
* line is read. `ipc_get_line' does not return until a non-interceptable
|
|
||||||
* line is read or end of file.
|
|
||||||
*
|
|
||||||
* If `wait' is IPC_NO_WAIT and there is no data available on the
|
|
||||||
* connection, `ipc_get_line' returns IPC_STATUS_NO_DATA. If `wait' is
|
|
||||||
* IPC_WAIT, `ipc_get_line' will not return until there is data available
|
|
||||||
* or and end of file condition is reached or an error occurs.
|
|
||||||
*
|
|
||||||
* Intercepts and processes the following commands:
|
|
||||||
* #RETURNI, #MINTIME, #VTRANS,
|
|
||||||
* >PAUSE, >CONT, >STOP, >INQCON, >NETLIST, >ENDNET
|
|
||||||
* Other > records are silently ignored.
|
|
||||||
*
|
|
||||||
* Intercepts old-style .TEMP card generated by MSPICE
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* IPC_STATUS_OK - for successful reads
|
|
||||||
* IPC_STATUS_NO_DATA - when NO_WAIT and no data available
|
|
||||||
* IPC_STATUS_END_OF_DECK - at end of deck (>ENDNET seen)
|
|
||||||
* IPC_STATUS_ERROR - otherwise
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Ipc_Status_t status;
|
|
||||||
Ipc_Boolean_t need_another = IPC_TRUE;
|
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
status = ipc_transport_get_line (str, len, wait);
|
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case IPC_STATUS_NO_DATA:
|
|
||||||
case IPC_STATUS_ERROR:
|
|
||||||
need_another = IPC_FALSE;
|
|
||||||
break;
|
|
||||||
case IPC_STATUS_END_OF_DECK:
|
|
||||||
assert (0); /* should never get this from the low-level get-line */
|
|
||||||
status = IPC_STATUS_ERROR;
|
|
||||||
need_another = IPC_FALSE;
|
|
||||||
break;
|
|
||||||
case IPC_STATUS_OK:
|
|
||||||
/*
|
|
||||||
* Got a good line - check to see if it's one of the ones we need to
|
|
||||||
* intercept
|
|
||||||
*/
|
|
||||||
if (str[0] == '>') {
|
|
||||||
if (kw_match (">STOP", str)) {
|
|
||||||
ipc_handle_stop();
|
|
||||||
} else if (kw_match (">PAUSE", str)) {
|
|
||||||
/* assert (need_another); */
|
|
||||||
/*
|
|
||||||
* once more around the loop to do a blocking wait for the >CONT
|
|
||||||
*/
|
|
||||||
need_another = IPC_TRUE;
|
|
||||||
wait = IPC_WAIT;
|
|
||||||
} else if (kw_match (">INQCON", str)) {
|
|
||||||
ipc_send_line (">ABRTABL");
|
|
||||||
ipc_send_line (">PAUSABL");
|
|
||||||
ipc_send_line (">KEEPABL");
|
|
||||||
status = ipc_flush ();
|
|
||||||
if (IPC_STATUS_OK != status) {
|
|
||||||
need_another = IPC_FALSE;
|
|
||||||
}
|
|
||||||
} else if (kw_match (">ENDNET", str)) {
|
|
||||||
end_of_deck_seen = IPC_TRUE;
|
|
||||||
need_another = IPC_FALSE;
|
|
||||||
status = IPC_STATUS_END_OF_DECK;
|
|
||||||
} else {
|
|
||||||
/* silently ignore */
|
|
||||||
}
|
|
||||||
} else if (str[0] == '#') {
|
|
||||||
if (kw_match ("#RETURNI", str)) {
|
|
||||||
ipc_handle_returni ();
|
|
||||||
} else if (kw_match ("#MINTIME", str)) {
|
|
||||||
double d1/*,d2*/;
|
|
||||||
if (1 != sscanf (&str[8], "%lg", &d1)) {
|
|
||||||
status = IPC_STATUS_ERROR;
|
|
||||||
need_another = IPC_FALSE;
|
|
||||||
} else {
|
|
||||||
ipc_handle_mintime (d1);
|
|
||||||
}
|
|
||||||
} else if (kw_match ("#VTRANS", str)) {
|
|
||||||
char *tok1;
|
|
||||||
char *tok2;
|
|
||||||
char *tok3;
|
|
||||||
|
|
||||||
tok1 = &str[8];
|
|
||||||
for (tok2 = tok1; *tok2; tok2++) {
|
|
||||||
if (isspace_c(*tok2)) {
|
|
||||||
*tok2 = '\0';
|
|
||||||
tok2++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(tok3 = tok2; *tok3; tok3++) {
|
|
||||||
if(isspace_c(*tok3)) {
|
|
||||||
*tok3 = '\0';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ipc_handle_vtrans (tok1, tok2);
|
|
||||||
} else {
|
|
||||||
/* silently ignore */
|
|
||||||
}
|
|
||||||
} else if (str[0] == '.') {
|
|
||||||
if (kw_match (".TEMP", str)) {
|
|
||||||
/* don't pass .TEMP card to caller */
|
|
||||||
printf("Old-style .TEMP card found - ignored\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* pass all other . cards to the caller */
|
|
||||||
need_another = IPC_FALSE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Not a '>' or '#' record - let the caller deal with it
|
|
||||||
*/
|
|
||||||
need_another = IPC_FALSE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/*
|
|
||||||
* some unknown status value!
|
|
||||||
*/
|
|
||||||
assert (0);
|
|
||||||
status = IPC_STATUS_ERROR;
|
|
||||||
need_another = IPC_FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (need_another);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_flush
|
|
||||||
|
|
||||||
This function flushes the interprocess communication channel
|
|
||||||
buffer contents.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_flush (void)
|
|
||||||
/*
|
|
||||||
* Flush all buffered messages out the connection.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Ipc_Status_t status;
|
|
||||||
int last = 0;
|
|
||||||
/*int bytes;*/
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* if batch mode */
|
|
||||||
if (mode == IPC_MODE_BATCH) {
|
|
||||||
|
|
||||||
assert (batch_fd >= 0);
|
|
||||||
|
|
||||||
/* for number of records in buffer */
|
|
||||||
for (i = 0; i < num_records; i++) {
|
|
||||||
|
|
||||||
/* write the records to the .log file */
|
|
||||||
if ((end_of_record_index [i] - last) !=
|
|
||||||
write (batch_fd, &out_buffer[last], (size_t) (end_of_record_index [i] - last))) {
|
|
||||||
/* fprintf (stderr,"ERROR: IPC: Error writing to batch output file\n"); */
|
|
||||||
perror ("IPC");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the record is one of the batch simulation status messages, */
|
|
||||||
/* send it over the ipc channel too */
|
|
||||||
if( kw_match("#ERRCHK", &out_buffer[last]) ||
|
|
||||||
kw_match(">ENDANAL", &out_buffer[last]) ||
|
|
||||||
kw_match(">ABORTED", &out_buffer[last]) ) {
|
|
||||||
|
|
||||||
status = ipc_transport_send_line (&out_buffer[last],
|
|
||||||
end_of_record_index [i] - last);
|
|
||||||
if (IPC_STATUS_OK != status) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last = end_of_record_index [i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* else, must be interactive mode */
|
|
||||||
} else {
|
|
||||||
/* send the full buffer over the ipc channel */
|
|
||||||
status = ipc_transport_send_line (&out_buffer[0],
|
|
||||||
end_of_record_index [num_records - 1]);
|
|
||||||
if (IPC_STATUS_OK != status) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset counts to zero and return */
|
|
||||||
num_records = 0;
|
|
||||||
fill_count = 0;
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_line_binary (
|
|
||||||
char *str,
|
|
||||||
int len )
|
|
||||||
/*
|
|
||||||
* Same as `ipc_send_line' except does not expect the str to be null
|
|
||||||
* terminated. Sends exactly `len' characters. Use this for binary data
|
|
||||||
* strings that may have embedded nulls.
|
|
||||||
*
|
|
||||||
* Modified by wbk to append newlines for compatibility with
|
|
||||||
* ATESSE 1.0
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
int length = len + 1;
|
|
||||||
/*int diff;*/
|
|
||||||
Ipc_Status_t status;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If we can't add the whole str to the buffer, or if there are no more
|
|
||||||
* record indices free, flush the buffer:
|
|
||||||
*/
|
|
||||||
if (((fill_count + length) >= OUT_BUFFER_SIZE) ||
|
|
||||||
(num_records >= MAX_NUM_RECORDS)) {
|
|
||||||
status = ipc_flush ();
|
|
||||||
if (IPC_STATUS_OK != status) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* make sure that the str will fit:
|
|
||||||
*/
|
|
||||||
if (length + fill_count > OUT_BUFFER_SIZE) {
|
|
||||||
/* fprintf (stderr,"ERROR: IPC: String too long to fit in output buffer (> %d bytes) - truncated\n",OUT_BUFFER_SIZE); */
|
|
||||||
length = OUT_BUFFER_SIZE - fill_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* finally, concatenate the str to the end of the buffer and add the newline:
|
|
||||||
*/
|
|
||||||
memcpy (&out_buffer[fill_count], str, (size_t) len);
|
|
||||||
fill_count += len;
|
|
||||||
|
|
||||||
out_buffer[fill_count] = '\n';
|
|
||||||
fill_count++;
|
|
||||||
|
|
||||||
end_of_record_index [num_records++] = fill_count;
|
|
||||||
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_line
|
|
||||||
|
|
||||||
This function sends a line of text over the interprocess
|
|
||||||
communication channel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_line (char *str ) /* The text to send */
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
int send_len;
|
|
||||||
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
Ipc_Status_t status= IPC_STATUS_OK;
|
|
||||||
|
|
||||||
|
|
||||||
len = (int) strlen(str);
|
|
||||||
|
|
||||||
/* if short string, send it immediately */
|
|
||||||
if(len < 80)
|
|
||||||
status = ipc_send_line_binary (str, len);
|
|
||||||
else {
|
|
||||||
/* otherwise, we have to send it as multiple strings */
|
|
||||||
/* because Mspice cannot handle things longer than 80 chars */
|
|
||||||
s = str;
|
|
||||||
while(len > 0) {
|
|
||||||
if(len < 80)
|
|
||||||
send_len = len;
|
|
||||||
else
|
|
||||||
send_len = 79;
|
|
||||||
status = ipc_send_line_binary (str, send_len);
|
|
||||||
if(status != IPC_STATUS_OK)
|
|
||||||
break;
|
|
||||||
s += send_len;
|
|
||||||
len -= send_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_data_prefix
|
|
||||||
|
|
||||||
This function sends a ``>DATAB'' line over the interprocess
|
|
||||||
communication channel to signal that this is the beginning of a
|
|
||||||
results dump for the current analysis point.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_data_prefix (double time ) /* The analysis point for this data set */
|
|
||||||
{
|
|
||||||
char buffer[40];
|
|
||||||
|
|
||||||
sprintf (buffer, ">DATAB %.5E", time);
|
|
||||||
return ipc_send_line (buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_data_suffix
|
|
||||||
|
|
||||||
This function sends a ``>ENDDATA'' line over the interprocess
|
|
||||||
communication channel to signal that this is the end of a results
|
|
||||||
dump from a particular analysis point.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_data_suffix (void)
|
|
||||||
{
|
|
||||||
Ipc_Status_t status;
|
|
||||||
|
|
||||||
status = ipc_send_line (">ENDDATA");
|
|
||||||
|
|
||||||
if(status != IPC_STATUS_OK)
|
|
||||||
return(status);
|
|
||||||
|
|
||||||
return(ipc_flush());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_dcop_prefix
|
|
||||||
|
|
||||||
This function sends a ``>DCOPB'' line over the interprocess
|
|
||||||
communication channel to signal that this is the beginning of a
|
|
||||||
results dump from a DC operating point analysis.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_dcop_prefix (void)
|
|
||||||
{
|
|
||||||
return ipc_send_line (">DCOPB");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_dcop_suffix
|
|
||||||
|
|
||||||
This function sends a ``>ENDDATA'' line over the interprocess
|
|
||||||
communication channel to signal that this is the end of a results
|
|
||||||
dump from a particular analysis point.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_dcop_suffix (void)
|
|
||||||
{
|
|
||||||
Ipc_Status_t status;
|
|
||||||
|
|
||||||
status = ipc_send_line (">ENDDCOP");
|
|
||||||
|
|
||||||
if(status != IPC_STATUS_OK)
|
|
||||||
return(status);
|
|
||||||
|
|
||||||
return(ipc_flush());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_evtdict_prefix
|
|
||||||
|
|
||||||
This function sends a ``>EVTDICT'' line over the interprocess
|
|
||||||
communication channel to signal that this is the beginning of an
|
|
||||||
event-driven node dictionary.
|
|
||||||
|
|
||||||
The line is sent only if the IPC is configured
|
|
||||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_evtdict_prefix (void)
|
|
||||||
{
|
|
||||||
#ifdef IPC_AEGIS_MAILBOXES
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
#else
|
|
||||||
return ipc_send_line (">EVTDICT");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_evtdict_suffix
|
|
||||||
|
|
||||||
This function sends a ``>ENDDICT'' line over the interprocess
|
|
||||||
communication channel to signal that this is the end of an
|
|
||||||
event-driven node dictionary.
|
|
||||||
|
|
||||||
The line is sent only if the IPC is configured
|
|
||||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_evtdict_suffix (void)
|
|
||||||
{
|
|
||||||
#ifdef IPC_AEGIS_MAILBOXES
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
#else
|
|
||||||
Ipc_Status_t status;
|
|
||||||
|
|
||||||
status = ipc_send_line (">ENDDICT");
|
|
||||||
|
|
||||||
if(status != IPC_STATUS_OK)
|
|
||||||
return(status);
|
|
||||||
|
|
||||||
return(ipc_flush());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_evtdata_prefix
|
|
||||||
|
|
||||||
This function sends a ``>EVTDATA'' line over the interprocess
|
|
||||||
communication channel to signal that this is the beginning of an
|
|
||||||
event-driven node data block.
|
|
||||||
|
|
||||||
The line is sent only if the IPC is configured
|
|
||||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_evtdata_prefix (void)
|
|
||||||
{
|
|
||||||
#ifdef IPC_AEGIS_MAILBOXES
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
#else
|
|
||||||
return ipc_send_line (">EVTDATA");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_evtdata_suffix
|
|
||||||
|
|
||||||
This function sends a ``>ENDDATA'' line over the interprocess
|
|
||||||
communication channel to signal that this is the end of an
|
|
||||||
event-driven node data block.
|
|
||||||
|
|
||||||
The line is sent only if the IPC is configured
|
|
||||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_evtdata_suffix (void)
|
|
||||||
{
|
|
||||||
#ifdef IPC_AEGIS_MAILBOXES
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
#else
|
|
||||||
Ipc_Status_t status;
|
|
||||||
|
|
||||||
status = ipc_send_line (">ENDDATA");
|
|
||||||
|
|
||||||
if(status != IPC_STATUS_OK)
|
|
||||||
return(status);
|
|
||||||
|
|
||||||
return(ipc_flush());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_errchk
|
|
||||||
|
|
||||||
This function sends a ``\ERRCHK [GO|NOGO]'' message over the
|
|
||||||
interprocess communication channel to signal that the initial
|
|
||||||
parsing of the input deck has been completed and to indicate
|
|
||||||
whether or not errors were detected.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_errchk(void)
|
|
||||||
{
|
|
||||||
char str[IPC_MAX_LINE_LEN+1];
|
|
||||||
Ipc_Status_t status;
|
|
||||||
|
|
||||||
if(g_ipc.errchk_sent)
|
|
||||||
return(IPC_STATUS_OK);
|
|
||||||
|
|
||||||
if(g_ipc.syntax_error)
|
|
||||||
sprintf(str, "#ERRCHK NOGO");
|
|
||||||
else
|
|
||||||
sprintf(str, "#ERRCHK GO");
|
|
||||||
|
|
||||||
g_ipc.errchk_sent = IPC_TRUE;
|
|
||||||
|
|
||||||
status = ipc_send_line(str);
|
|
||||||
if(status != IPC_STATUS_OK)
|
|
||||||
return(status);
|
|
||||||
|
|
||||||
return(ipc_flush());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_end
|
|
||||||
|
|
||||||
This function sends either an ``>ENDANAL'' or an ``>ABORTED'' message
|
|
||||||
over the interprocess communication channel together with the
|
|
||||||
total CPU time used to indicate whether or not the simulation
|
|
||||||
completed normally.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_end(void)
|
|
||||||
{
|
|
||||||
char str[IPC_MAX_LINE_LEN+1];
|
|
||||||
Ipc_Status_t status;
|
|
||||||
|
|
||||||
if(g_ipc.syntax_error || g_ipc.run_error)
|
|
||||||
sprintf(str, ">ABORTED %.4f", g_ipc.cpu_time);
|
|
||||||
else
|
|
||||||
sprintf(str, ">ENDANAL %.4f", g_ipc.cpu_time);
|
|
||||||
|
|
||||||
status = ipc_send_line(str);
|
|
||||||
if(status != IPC_STATUS_OK)
|
|
||||||
return(status);
|
|
||||||
|
|
||||||
return(ipc_flush());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int
|
|
||||||
stuff_binary_v1 (
|
|
||||||
double d1, double d2, /* doubles to be stuffed */
|
|
||||||
int n, /* how many of d1, d2 ( 1 <= n <= 2 ) */
|
|
||||||
char *buf, /* buffer to stuff to */
|
|
||||||
int pos ) /* index at which to stuff */
|
|
||||||
{
|
|
||||||
union {
|
|
||||||
float float_val[2];
|
|
||||||
char ch[32];
|
|
||||||
} trick;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
assert (protocol == IPC_PROTOCOL_V1);
|
|
||||||
assert (sizeof(float) == 4);
|
|
||||||
assert (sizeof(char) == 1);
|
|
||||||
assert ((n >= 1) && (n <= 2));
|
|
||||||
|
|
||||||
trick.float_val[0] = (float)d1;
|
|
||||||
if (n > 1) {
|
|
||||||
trick.float_val[1] = (float)d2;
|
|
||||||
}
|
|
||||||
for (i = 0, j = pos; i < n * (int) sizeof(float); j++, i++)
|
|
||||||
buf[j] = trick.ch[i];
|
|
||||||
buf[0] = (char) ('A' + j - 1);
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_double
|
|
||||||
|
|
||||||
This function sends a double data value over the interprocess
|
|
||||||
communication channel preceded by a character string that
|
|
||||||
identifies the simulation variable.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_double (
|
|
||||||
char *tag, /* The node or instance */
|
|
||||||
double value ) /* The data value to send */
|
|
||||||
{
|
|
||||||
int len = 0;
|
|
||||||
|
|
||||||
switch (protocol) {
|
|
||||||
case IPC_PROTOCOL_V1:
|
|
||||||
strcpy (fmt_buffer, " "); /* save room for the length byte */
|
|
||||||
strcat (fmt_buffer, tag);
|
|
||||||
strcat (fmt_buffer, " ");
|
|
||||||
|
|
||||||
/* If talking to Mentor tools, must force upper case for Mspice 7.0 */
|
|
||||||
strtoupper(fmt_buffer);
|
|
||||||
|
|
||||||
len = stuff_binary_v1 (value, 0.0, 1, fmt_buffer, (int) strlen(fmt_buffer));
|
|
||||||
break;
|
|
||||||
case IPC_PROTOCOL_V2:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ipc_send_line_binary (fmt_buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_complex
|
|
||||||
|
|
||||||
This function sends a complex data value over the interprocess
|
|
||||||
communication channel preceded by a character string that
|
|
||||||
identifies the simulation variable.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_complex (
|
|
||||||
char *tag, /* The node or instance */
|
|
||||||
Ipc_Complex_t value ) /* The data value to send */
|
|
||||||
{
|
|
||||||
int len=0;
|
|
||||||
|
|
||||||
switch (protocol) {
|
|
||||||
case IPC_PROTOCOL_V1:
|
|
||||||
strcpy (fmt_buffer, " "); /* save room for the length byte */
|
|
||||||
strcat (fmt_buffer, tag);
|
|
||||||
strcat (fmt_buffer, " ");
|
|
||||||
|
|
||||||
/* If talking to Mentor tools, must force upper case for Mspice 7.0 */
|
|
||||||
strtoupper(fmt_buffer);
|
|
||||||
|
|
||||||
len = stuff_binary_v1 (value.real, value.imag, 2, fmt_buffer,
|
|
||||||
(int) strlen(fmt_buffer));
|
|
||||||
break;
|
|
||||||
case IPC_PROTOCOL_V2:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ipc_send_line_binary (fmt_buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_event
|
|
||||||
|
|
||||||
This function sends data from an event-driven node over the interprocess
|
|
||||||
communication channel. The data is sent only if the IPC is configured
|
|
||||||
for UNIX sockets, indicating use with the V2 ATESSE SI process.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_send_event (
|
|
||||||
int ipc_index, /* Index used in EVTDICT */
|
|
||||||
double step, /* Analysis point or timestep (0.0 for DC) */
|
|
||||||
double plot_val, /* The value for plotting purposes */
|
|
||||||
char *print_val, /* The value for printing purposes */
|
|
||||||
void *ipc_val, /* The binary representation of the node data */
|
|
||||||
int len ) /* The length of the binary representation */
|
|
||||||
{
|
|
||||||
#ifdef IPC_AEGIS_MAILBOXES
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
#else
|
|
||||||
char buff[OUT_BUFFER_SIZE];
|
|
||||||
int i;
|
|
||||||
int buff_len;
|
|
||||||
char *buff_ptr;
|
|
||||||
char *temp_ptr;
|
|
||||||
float fvalue;
|
|
||||||
|
|
||||||
/* Report error if size of data is too big for IPC channel block size */
|
|
||||||
if((len + (int) strlen(print_val) + 100) >= OUT_BUFFER_SIZE) {
|
|
||||||
printf("ERROR - Size of event-driven data too large for IPC channel\n");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Place the index into the buffer with a trailing space */
|
|
||||||
sprintf(buff, "%d ", ipc_index);
|
|
||||||
|
|
||||||
assert(sizeof(float) == 4);
|
|
||||||
assert(sizeof(int) == 4);
|
|
||||||
|
|
||||||
/* Put the analysis step bytes in */
|
|
||||||
buff_len = (int) strlen(buff);
|
|
||||||
buff_ptr = buff + buff_len;
|
|
||||||
fvalue = (float)step;
|
|
||||||
temp_ptr = (char *) &fvalue;
|
|
||||||
for(i = 0; i < 4; i++) {
|
|
||||||
*buff_ptr = temp_ptr[i];
|
|
||||||
buff_ptr++;
|
|
||||||
buff_len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put the plot value in */
|
|
||||||
fvalue = (float)plot_val;
|
|
||||||
temp_ptr = (char *) &fvalue;
|
|
||||||
for(i = 0; i < 4; i++) {
|
|
||||||
*buff_ptr = temp_ptr[i];
|
|
||||||
buff_ptr++;
|
|
||||||
buff_len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put the length of the binary representation in */
|
|
||||||
temp_ptr = (char *) &len;
|
|
||||||
for(i = 0; i < 4; i++) {
|
|
||||||
*buff_ptr = temp_ptr[i];
|
|
||||||
buff_ptr++;
|
|
||||||
buff_len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Put the binary representation bytes in last */
|
|
||||||
temp_ptr = (char*) ipc_val;
|
|
||||||
for(i = 0; i < len; i++)
|
|
||||||
buff_ptr[i] = temp_ptr[i];
|
|
||||||
buff_ptr += len;
|
|
||||||
buff_len += len;
|
|
||||||
|
|
||||||
/* Put the print value in */
|
|
||||||
strcpy(buff_ptr, print_val);
|
|
||||||
buff_ptr += strlen(print_val);
|
|
||||||
buff_len += (int) strlen(print_val);
|
|
||||||
|
|
||||||
/* Send the data to the IPC channel */
|
|
||||||
return ipc_send_line_binary(buff, buff_len);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,309 +0,0 @@
|
||||||
/*============================================================================
|
|
||||||
FILE IPCaegis.c
|
|
||||||
|
|
||||||
MEMBER OF process XSPICE
|
|
||||||
|
|
||||||
Public Domain
|
|
||||||
|
|
||||||
Georgia Tech Research Corporation
|
|
||||||
Atlanta, Georgia 30332
|
|
||||||
PROJECT A-8503
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
9/12/91 Steve Tynor
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
<date> <person name> <nature of modifications>
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
Provides compatibility for the new XSPICE simulator to both the MSPICE user
|
|
||||||
interface and BCP via ATESSE v.1 style AEGIS mailboxes.
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
|
|
||||||
REFERENCED FILES
|
|
||||||
|
|
||||||
None.
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
None.
|
|
||||||
|
|
||||||
============================================================================*/
|
|
||||||
|
|
||||||
#ifdef IPC_AEGIS_MAILBOXES
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <apollo/base.h>
|
|
||||||
#include <apollo/mbx.h>
|
|
||||||
#include <apollo/error.h>
|
|
||||||
#include "ngspice/memory.h"
|
|
||||||
|
|
||||||
#include "ngspice/ipc.h"
|
|
||||||
|
|
||||||
|
|
||||||
typedef unsigned char Buffer_char_t;
|
|
||||||
|
|
||||||
static status_$t status;
|
|
||||||
typedef enum {
|
|
||||||
IPC_MBX_UNINITIALIZED,
|
|
||||||
IPC_MBX_INITIALIZED,
|
|
||||||
IPC_MBX_CONNECTED_TO_CLIENT,
|
|
||||||
} Ipc_Mbx_State_t;
|
|
||||||
|
|
||||||
static void *mbx_handle;
|
|
||||||
static Ipc_Mbx_State_t mbx_state = IPC_MBX_UNINITIALIZED;
|
|
||||||
static mbx_$server_msg_t mbx_send_msg_buf;
|
|
||||||
static mbx_$server_msg_t mbx_recieve_msg_buf;
|
|
||||||
static mbx_$server_msg_t *mbx_ret_ptr;
|
|
||||||
static int mbx_ret_len;
|
|
||||||
static short mbx_chan;
|
|
||||||
|
|
||||||
#include "ngspice/ipcproto.h"
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_transport_initialize_server
|
|
||||||
|
|
||||||
This function creates an Aegis mailbox, and if successful,
|
|
||||||
calls ipc_get_line to wait for the first record sent which is
|
|
||||||
assumed to be the batch output filename.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t ipc_transport_initialize_server (server_name, m, p,
|
|
||||||
batch_filename)
|
|
||||||
char *server_name; /* The mailbox pathname */
|
|
||||||
Ipc_Mode_t m; /* Mode - interactive or batch */
|
|
||||||
Ipc_Protocol_t p; /* Protocol type */
|
|
||||||
char *batch_filename; /* Batch filename returned */
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
/* extern void *malloc(); */
|
|
||||||
|
|
||||||
assert (p == IPC_PROTOCOL_V1);
|
|
||||||
|
|
||||||
mbx_$create_server (server_name, strlen (server_name), mbx_$serv_msg_max,
|
|
||||||
1, &mbx_handle, &status);
|
|
||||||
|
|
||||||
if (status.all != status_$ok) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: IPC: Error creating mailbox server \"%s\"\n",
|
|
||||||
server_name);
|
|
||||||
error_$print (status);
|
|
||||||
mbx_state = IPC_MBX_UNINITIALIZED;
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
} else {
|
|
||||||
mbx_state = IPC_MBX_INITIALIZED;
|
|
||||||
/*
|
|
||||||
* First record is the name of the batch filename - whether we're in
|
|
||||||
* batch mode or not:
|
|
||||||
*/
|
|
||||||
return ipc_get_line (batch_filename, &len, IPC_WAIT);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* shouldn't get here
|
|
||||||
*/
|
|
||||||
assert (0);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
Ipc_Status_t extract_msg (str, len)
|
|
||||||
char *str;
|
|
||||||
int *len;
|
|
||||||
{
|
|
||||||
*len = mbx_ret_len - mbx_$serv_msg_hdr_len;
|
|
||||||
assert (*len >= 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* null terminate before copy:
|
|
||||||
*/
|
|
||||||
mbx_ret_ptr->data [*len] = '\0';
|
|
||||||
strcpy (str, mbx_ret_ptr->data);
|
|
||||||
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_transport_get_line
|
|
||||||
|
|
||||||
This function reads data sent by a client over the mailbox
|
|
||||||
channel. It also handles the initial opening of the
|
|
||||||
mailbox channel when requested by a client.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t ipc_transport_get_line (str, len, wait)
|
|
||||||
char *str; /* The string text read from IPC channel */
|
|
||||||
int *len; /* The length of str */
|
|
||||||
Ipc_Wait_t wait; /* Blocking or non-blocking */
|
|
||||||
{
|
|
||||||
if (mbx_state == IPC_MBX_UNINITIALIZED) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: IPC: Attempted to read from non-initialized mailbox\n");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert ((mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) ||
|
|
||||||
(mbx_state == IPC_MBX_INITIALIZED));
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (wait == IPC_WAIT) {
|
|
||||||
mbx_$get_rec (mbx_handle, &mbx_recieve_msg_buf, mbx_$serv_msg_max,
|
|
||||||
&mbx_ret_ptr, &mbx_ret_len, &status);
|
|
||||||
} else {
|
|
||||||
mbx_$get_conditional (mbx_handle, &mbx_recieve_msg_buf,
|
|
||||||
mbx_$serv_msg_max, &mbx_ret_ptr, &mbx_ret_len,
|
|
||||||
&status);
|
|
||||||
if (status.all == mbx_$channel_empty) {
|
|
||||||
return IPC_STATUS_NO_DATA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status.all != status_$ok) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: Error reading from mailbox\n");
|
|
||||||
error_$print (status);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mbx_ret_ptr->mt) {
|
|
||||||
case mbx_$channel_open_mt:
|
|
||||||
if (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) {
|
|
||||||
/*
|
|
||||||
* we're already connected to a client... refuse the connection
|
|
||||||
*/
|
|
||||||
mbx_send_msg_buf.mt = mbx_$reject_open_mt;
|
|
||||||
} else {
|
|
||||||
mbx_send_msg_buf.mt = mbx_$accept_open_mt;
|
|
||||||
mbx_state = IPC_MBX_CONNECTED_TO_CLIENT;
|
|
||||||
}
|
|
||||||
mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len;
|
|
||||||
mbx_chan = mbx_ret_ptr->chan;
|
|
||||||
mbx_send_msg_buf.chan = mbx_chan;
|
|
||||||
|
|
||||||
mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, mbx_$serv_msg_hdr_len,
|
|
||||||
&status);
|
|
||||||
|
|
||||||
if (status.all != status_$ok) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n");
|
|
||||||
error_$print (status);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* check to see if there was a message buried in the open request:
|
|
||||||
*/
|
|
||||||
if (mbx_ret_len > mbx_$serv_msg_hdr_len) {
|
|
||||||
return extract_msg (str, len);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case mbx_$eof_mt:
|
|
||||||
mbx_chan = mbx_ret_ptr->chan;
|
|
||||||
mbx_$deallocate(mbx_handle, mbx_chan, &status);
|
|
||||||
|
|
||||||
if (status.all != status_$ok) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: Error deallocating mailbox\n");
|
|
||||||
error_$print (status);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbx_state = IPC_MBX_INITIALIZED;
|
|
||||||
return IPC_STATUS_EOF;
|
|
||||||
break;
|
|
||||||
case mbx_$data_mt:
|
|
||||||
assert (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT);
|
|
||||||
return extract_msg (str, len);
|
|
||||||
break;
|
|
||||||
case mbx_$data_partial_mt:
|
|
||||||
fprintf (stderr, "ERROR: IPC: Recieved partial data message - ignored\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf (stderr, "ERROR: IPC: Bad message type (0x%x) recieved\n",
|
|
||||||
mbx_ret_ptr->mt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_transport_terminate_server
|
|
||||||
|
|
||||||
This function calls ipc\_transport\_get\_line until it
|
|
||||||
receives an EOF from the client, which concludes the
|
|
||||||
communication.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t ipc_transport_terminate_server ()
|
|
||||||
{
|
|
||||||
char buffer[300];
|
|
||||||
int len;
|
|
||||||
Ipc_Status_t status;
|
|
||||||
|
|
||||||
do {
|
|
||||||
status = ipc_transport_get_line (buffer, &len, IPC_WAIT);
|
|
||||||
} while ((status != IPC_STATUS_ERROR) &&
|
|
||||||
(status != IPC_STATUS_EOF));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_transport_send_line
|
|
||||||
|
|
||||||
This function sends a message to the current client through
|
|
||||||
the mailbox channel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t ipc_transport_send_line (str, len)
|
|
||||||
char *str; /* The bytes to send */
|
|
||||||
int len; /* The number of bytes from str to send */
|
|
||||||
{
|
|
||||||
long cnt;
|
|
||||||
|
|
||||||
if (mbx_state != IPC_MBX_CONNECTED_TO_CLIENT) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: IPC: Attempted to write to non-open mailbox\n");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbx_send_msg_buf.mt = mbx_$data_mt;
|
|
||||||
if (mbx_$serv_msg_hdr_len + len > mbx_$serv_msg_max) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: IPC: send_line message too long - truncating\n");
|
|
||||||
len = mbx_$serv_msg_max - mbx_$serv_msg_hdr_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len + len;
|
|
||||||
mbx_send_msg_buf.chan = mbx_chan;
|
|
||||||
memcpy (mbx_send_msg_buf.data, str, len);
|
|
||||||
|
|
||||||
cnt = mbx_send_msg_buf.cnt;
|
|
||||||
mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, cnt, &status);
|
|
||||||
|
|
||||||
if (status.all != status_$ok) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n");
|
|
||||||
error_$print (status);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
int intDummy1;
|
|
||||||
|
|
||||||
#endif /* IPC_AEGIS_MAILBOXES */
|
|
||||||
|
|
@ -1,756 +0,0 @@
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
FILE IPCsockets.c
|
|
||||||
|
|
||||||
Public Domain
|
|
||||||
|
|
||||||
Georgia Tech Research Corporation
|
|
||||||
Atlanta, Georgia 30332
|
|
||||||
PROJECT A-8503
|
|
||||||
|
|
||||||
AUTHOR
|
|
||||||
Stefan Roth July 1991
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
none
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
Generic Interprocess Communication module
|
|
||||||
Provides compatibility for the new SPICE simulator to both the MSPICE user
|
|
||||||
interface and BCP (via ATESSE v.1 style AEGIS mailboxes) and the new ATESSE
|
|
||||||
v.2 Simulator Interface and BCP (via BSD Sockets). This file contains the
|
|
||||||
BSD sockets version.
|
|
||||||
The Simulator is the server, while the SI and BCP will be the clients.
|
|
||||||
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
FILE ROUTINE CALLED
|
|
||||||
|
|
||||||
IPC.c ipc_get_line();
|
|
||||||
|
|
||||||
|
|
||||||
REFERENCED FILES
|
|
||||||
|
|
||||||
Outputs to stderr.
|
|
||||||
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
DESCRIPTION OF FUNCTIONALITY:
|
|
||||||
|
|
||||||
Outline of Initialize_Server function:
|
|
||||||
create socket;
|
|
||||||
bind name to socket;
|
|
||||||
getsockname;
|
|
||||||
listen;
|
|
||||||
sock_state = IPC_SOCK_INITIALIZED;
|
|
||||||
return ipc_get_line ();
|
|
||||||
|
|
||||||
|
|
||||||
Format of a message line:
|
|
||||||
bytes description
|
|
||||||
----- -------------------
|
|
||||||
0 recognition character for beginning of line; value is BOL_CHAR.
|
|
||||||
1-4 message length (not including bytes 0-4); 32 bits in htonl
|
|
||||||
format;
|
|
||||||
if value = -1, then EOF and socket should be closed.
|
|
||||||
5-N+5 message body of length specified in bytes 1-4.
|
|
||||||
|
|
||||||
The bytes before the message body are the message header. The header
|
|
||||||
length is specified as SOCK_MSG_HDR_LEN bytes.
|
|
||||||
|
|
||||||
|
|
||||||
Outline of Get_Line function:
|
|
||||||
read 5 characters;
|
|
||||||
verify that first char is BOL_CHAR;
|
|
||||||
interpret message length (N) from bytes 1-4;
|
|
||||||
do error checking on message header bytes;
|
|
||||||
read N characters as message body;
|
|
||||||
do error checking on message body read;
|
|
||||||
|
|
||||||
|
|
||||||
Outline of Send_Line function:
|
|
||||||
write BOL_CHAR;
|
|
||||||
write 4-byte message body length
|
|
||||||
write message body (N bytes)
|
|
||||||
do error checking after each write operation
|
|
||||||
|
|
||||||
|
|
||||||
Outline of Terminate_Server function:
|
|
||||||
Continue to read lines (with ipc_transport_get_line) and ignore
|
|
||||||
them until socket EOF is reached;
|
|
||||||
Close the socket.
|
|
||||||
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
#include "ngspice/ngspice.h"
|
|
||||||
|
|
||||||
#ifdef IPC_UNIX_SOCKETS
|
|
||||||
|
|
||||||
/*=== INCLUDE FILES ===*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include "ngspice/ipc.h"
|
|
||||||
#include "ngspice/ipctiein.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*=== TYPE DEFINITIONS ===*/
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
IPC_SOCK_UNINITIALIZED,
|
|
||||||
IPC_SOCK_INITIALIZED,
|
|
||||||
IPC_SOCK_CONNECTED_TO_CLIENT
|
|
||||||
} Ipc_Sock_State_t;
|
|
||||||
|
|
||||||
|
|
||||||
/*=== LOCAL VARIABLES ===*/
|
|
||||||
|
|
||||||
static int sock_desc; /* socket descriptor */
|
|
||||||
static int msg_stream; /* socket stream */
|
|
||||||
static Ipc_Sock_State_t sock_state = IPC_SOCK_UNINITIALIZED;
|
|
||||||
|
|
||||||
|
|
||||||
/*=== INCLUDE FILES ===*/
|
|
||||||
|
|
||||||
#include "ngspice/ipcproto.h"
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
FUNCTION ipc_transport_initialize_server
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
July 1991 Stefan Roth
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
Creates and opens the BSD socket of the server. Listens for requests
|
|
||||||
by a client and then reads the first line message.
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
Called by: (IPC.c) ipc_initialize_server();
|
|
||||||
|
|
||||||
RETURNED VALUE
|
|
||||||
|
|
||||||
Ipc_Status_t - returns status of the socket connection.
|
|
||||||
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_transport_initialize_server (
|
|
||||||
char *server_name, /* not used */
|
|
||||||
Ipc_Mode_t mode, /* not used */
|
|
||||||
Ipc_Protocol_t protocol, /* IN - only used in assert */
|
|
||||||
char *batch_filename ) /* OUT - returns a value */
|
|
||||||
/* Note that unused parameters are required to maintain compatibility */
|
|
||||||
/* with version 1 (mailboxes) functions of the same names. */
|
|
||||||
{
|
|
||||||
struct sockaddr_in server; /* Server specifications for socket*/
|
|
||||||
socklen_t server_length; /* Size of server structure */
|
|
||||||
int port_num; /* Port number converted from server_name */
|
|
||||||
|
|
||||||
NG_IGNORE(mode);
|
|
||||||
NG_IGNORE(protocol);
|
|
||||||
|
|
||||||
/* assert (protocol == IPC_PROTOCOL_V2); */ /* allow v1 protocol - wbk */
|
|
||||||
assert (sock_state == IPC_SOCK_UNINITIALIZED);
|
|
||||||
|
|
||||||
/* convert server_name (from atesse_xspice invocation line) to a port */
|
|
||||||
/* number */
|
|
||||||
port_num = atoi(server_name);
|
|
||||||
if((port_num > 0) && (port_num < 1024)) {
|
|
||||||
/* Reserved port number */
|
|
||||||
perror ("ERROR: IPC Port numbers below 1024 are reserved");
|
|
||||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sock_desc = socket (AF_INET, SOCK_STREAM, 0);
|
|
||||||
|
|
||||||
if (sock_desc < 0) {
|
|
||||||
/* Unsuccessful socket opening */
|
|
||||||
perror ("ERROR: IPC Creating socket");
|
|
||||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Socket opened successfully */
|
|
||||||
|
|
||||||
server.sin_family = AF_INET;
|
|
||||||
server.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
server.sin_port = SOCKET_PORT;
|
|
||||||
|
|
||||||
server_length = sizeof (server);
|
|
||||||
if (bind (sock_desc, (struct sockaddr *)&server, server_length)
|
|
||||||
< 0) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: Bind unsuccessful\n");
|
|
||||||
perror ("ERROR: IPC");
|
|
||||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getsockname (sock_desc, (struct sockaddr *)&server, &server_length)
|
|
||||||
< 0) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: getting socket name\n");
|
|
||||||
perror ("ERROR: IPC");
|
|
||||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf (stderr, "Socket port %d.\n", ntohs(server.sin_port));
|
|
||||||
|
|
||||||
listen (sock_desc, 5);
|
|
||||||
|
|
||||||
sock_state = IPC_SOCK_INITIALIZED;
|
|
||||||
|
|
||||||
/* Socket ok to use now */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* First record is the name of the batch filename if we're in batch mode.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(g_ipc.mode == IPC_MODE_BATCH) {
|
|
||||||
int len;
|
|
||||||
return ipc_get_line (batch_filename, &len, IPC_WAIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return success */
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
|
|
||||||
} /* end ipc_transport_initialize_server */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
FUNCTION bytes_to_integer
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
July 1991 Stefan Roth
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
Convert four bytes at START in the string STR
|
|
||||||
to a 32-bit unsigned integer. The string is assumed
|
|
||||||
to be in network byte order and the returned value
|
|
||||||
is converted to host byte order (with ntohl).
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
Local to this file.
|
|
||||||
Called by: ipc_transport_get_line();
|
|
||||||
|
|
||||||
RETURNED VALUE
|
|
||||||
|
|
||||||
u_long - unsigned 32 bit integer
|
|
||||||
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
/* FIXME,
|
|
||||||
* this is seriously broken,
|
|
||||||
* once it was probably based upon htonl(),
|
|
||||||
* yet with broken types
|
|
||||||
* then the game has changed and strtoul() was used
|
|
||||||
* with a ascii representation of the length
|
|
||||||
* (probably as a hacky workaround, because it proved unreliable)
|
|
||||||
* but the buffer is not terminated properly
|
|
||||||
* Fix this when needed, currently this functionality looks like
|
|
||||||
* an unused ancient artefact
|
|
||||||
* Fix it with regard to ipc_transport_get_line() and ipc_transport_send_line()
|
|
||||||
* and in concert with the actual user at the other side of the socket
|
|
||||||
*/
|
|
||||||
static u_long
|
|
||||||
bytes_to_integer (
|
|
||||||
char *str, /* IN - string that contains the bytes to convert */
|
|
||||||
int start ) /* IN - index into string where bytes are */
|
|
||||||
{
|
|
||||||
uint32_t u; /* Value to be returned */
|
|
||||||
char buff[4]; /* Transfer str into buff to word align reqd data */
|
|
||||||
int index; /* Index into str and buff for transfer */
|
|
||||||
|
|
||||||
/* Get the str+start character and cast it into a u_long and put
|
|
||||||
the value through the network-to-host-short converter and store
|
|
||||||
it in the variable u. */
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
while (index < (int) sizeof(u)) {
|
|
||||||
buff[index] = str[index+start];
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
/* u = ntohl (*((u_long *) buff)); */
|
|
||||||
u = (uint32_t) strtoul(buff, NULL, 10);
|
|
||||||
|
|
||||||
return u;
|
|
||||||
} /* end bytes_to_integer */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
FUNCTION handle_socket_eof
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
July 1991 Stefan Roth
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
Do processing when the socket reaches EOF or when a message from the
|
|
||||||
client states that EOF has been reached.
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
Local to this file.
|
|
||||||
Called by: ipc_transport_get_line();
|
|
||||||
|
|
||||||
RETURNED VALUE
|
|
||||||
|
|
||||||
Ipc_Status_t - always IPC_STATUS_EOF
|
|
||||||
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
static Ipc_Status_t
|
|
||||||
handle_socket_eof (void)
|
|
||||||
{
|
|
||||||
close (msg_stream);
|
|
||||||
close (sock_desc);
|
|
||||||
|
|
||||||
sock_state = IPC_SOCK_UNINITIALIZED;
|
|
||||||
|
|
||||||
return IPC_STATUS_EOF;
|
|
||||||
} /* handle_socket_eof */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
FUNCTION read_sock
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
July 1991 Stefan Roth
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
Read N bytes from a socket. Only returns when the read had an error,
|
|
||||||
when 0 bytes (EOF) could be read, or LENGTH bytes are read.
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
Local to this file.
|
|
||||||
Called by: ipc_transport_get_line();
|
|
||||||
|
|
||||||
RETURNED VALUE
|
|
||||||
|
|
||||||
int - Returns the total number of bytes read.
|
|
||||||
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
read_sock (
|
|
||||||
int stream, /* IN - Socket stream */
|
|
||||||
char *buffer, /* OUT - buffer to store incoming data */
|
|
||||||
int length, /* IN - Number of bytes to be read */
|
|
||||||
Ipc_Wait_t wait, /* IN - type of read operation */
|
|
||||||
int flags ) /* IN - Original socket flags for blocking read */
|
|
||||||
{
|
|
||||||
int count; /* Number of bytes read with last `read` */
|
|
||||||
int totalcount; /* total number of bytes read */
|
|
||||||
char *buf2;
|
|
||||||
|
|
||||||
/* count = 0; */
|
|
||||||
/* while (count < length) { */
|
|
||||||
/* buffer[count] = 'x'; */
|
|
||||||
/* count++; */
|
|
||||||
/* } */
|
|
||||||
count = (int) read (stream, buffer, (size_t) length);
|
|
||||||
if (wait == IPC_NO_WAIT) {
|
|
||||||
fcntl (stream, F_SETFL, flags); /* Revert to blocking read */
|
|
||||||
}
|
|
||||||
if ((count <= 0) || (count == length)) {
|
|
||||||
/* If error or if read in reqd number of bytes: */
|
|
||||||
return count;
|
|
||||||
} else {
|
|
||||||
/* Only got some of the bytes requested */
|
|
||||||
totalcount = count;
|
|
||||||
buf2 = &buffer[totalcount];
|
|
||||||
length = length - count;
|
|
||||||
while (length > 0) {
|
|
||||||
count = (int) read (stream, buf2, (size_t) length);
|
|
||||||
if (count <= 0) /* EOF or read error */
|
|
||||||
break;
|
|
||||||
totalcount = totalcount + count;
|
|
||||||
buf2 = &buffer[totalcount];
|
|
||||||
length = length - count;
|
|
||||||
}
|
|
||||||
if (length != 0) {
|
|
||||||
fprintf (stderr, "WARNING: READ_SOCK read %d bytes instead of %d\n",
|
|
||||||
totalcount, totalcount + length);
|
|
||||||
}
|
|
||||||
return totalcount;
|
|
||||||
}
|
|
||||||
} /* end read_sock */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
FUNCTION ipc_transport_get_line
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
July 1991 Stefan Roth
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
Main function for reading one line from a socket. Requires that the
|
|
||||||
socket be open. Lines are mostly SPICE code, but commands may also
|
|
||||||
be embedded in the socket data and they are interpreted by this function.
|
|
||||||
Therefore, this function may cause the socket to be closed.
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
Called by: ipc_transport_terminate_server();
|
|
||||||
(IPC.c) ipc_get_line();
|
|
||||||
|
|
||||||
RETURNED VALUE
|
|
||||||
|
|
||||||
Ipc_Status_t - returns status of the read operation
|
|
||||||
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_transport_get_line (
|
|
||||||
char *str, /* returns the result, null terminated */
|
|
||||||
int *len, /* length of str passed IN and passed OUT */
|
|
||||||
Ipc_Wait_t wait ) /* IN - wait or dont wait on incoming msg */
|
|
||||||
{
|
|
||||||
int count = 0; /* number of bytes read */
|
|
||||||
int message_length; /* extracted from message header */
|
|
||||||
|
|
||||||
if (sock_state == IPC_SOCK_UNINITIALIZED) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: IPC: Attempted to read from uninitialized socket\n");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert ((sock_state == IPC_SOCK_CONNECTED_TO_CLIENT) ||
|
|
||||||
(sock_state == IPC_SOCK_INITIALIZED));
|
|
||||||
|
|
||||||
if (sock_state == IPC_SOCK_INITIALIZED) {
|
|
||||||
/* We have an open socket but have not connected to a client. */
|
|
||||||
/* Accept a connection from a client. */
|
|
||||||
msg_stream = accept (sock_desc, (struct sockaddr *)0, (socklen_t*)0);
|
|
||||||
|
|
||||||
if (msg_stream == -1) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: Server accepting request\n");
|
|
||||||
perror ("ERROR: IPC");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
sock_state = IPC_SOCK_CONNECTED_TO_CLIENT;
|
|
||||||
}
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* First read in the message header. */
|
|
||||||
{
|
|
||||||
int flags;
|
|
||||||
flags = fcntl(msg_stream, F_GETFL, NULL); /* Blocking read mode */
|
|
||||||
|
|
||||||
if (wait == IPC_WAIT) {
|
|
||||||
/* Block here and wait for the next message */
|
|
||||||
count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags);
|
|
||||||
if (count == 0) {
|
|
||||||
/* EOF, will this ever happen? */
|
|
||||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */
|
|
||||||
return handle_socket_eof ();
|
|
||||||
}
|
|
||||||
} else if (wait == IPC_NO_WAIT) {
|
|
||||||
/* Read message, but do not wait if none available. */
|
|
||||||
|
|
||||||
fcntl (msg_stream, F_SETFL, flags | O_NDELAY);
|
|
||||||
count = read_sock (msg_stream, str, SOCK_MSG_HDR_LEN, wait, flags);
|
|
||||||
|
|
||||||
if (count == 0) {
|
|
||||||
/* EOF, will this ever happen? */
|
|
||||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */
|
|
||||||
return handle_socket_eof ();
|
|
||||||
} else if (count == -1) {
|
|
||||||
if (errno == EWOULDBLOCK) {
|
|
||||||
return IPC_STATUS_NO_DATA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
/* Serious problem, since it is not reading anything. */
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: IPC: invalid wait arg to ipc_transport_get_line\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do more error checking on the read in values of the message header: */
|
|
||||||
if (count == -1) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: Reading from socket\n");
|
|
||||||
perror ("ERROR: IPC");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
} else if (str[0] != BOL_CHAR) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: IPC: Did not find beginning of message header (%c)\n",
|
|
||||||
str[0]);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
} else if ((message_length = (int) bytes_to_integer (str, 1)) == -1) {
|
|
||||||
/* fprintf (stderr, "WARNING: IPC: Reached eof on socket\n"); */
|
|
||||||
return handle_socket_eof ();
|
|
||||||
} else if (message_length == 0) {
|
|
||||||
*len = 0;
|
|
||||||
return IPC_STATUS_NO_DATA;
|
|
||||||
|
|
||||||
/* Invalid test... delete - wbk
|
|
||||||
} else if (message_length > *len) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"ERROR: IPC: Buffer (%d) is too short for message (%d)\n",
|
|
||||||
*len, message_length);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------*/
|
|
||||||
/* Now read in the message body. */
|
|
||||||
/* Always block here since the message header was already read and */
|
|
||||||
/* we must get the body. */
|
|
||||||
|
|
||||||
*len = message_length;
|
|
||||||
count = read_sock (msg_stream, str, message_length, IPC_WAIT, 0);
|
|
||||||
if (count == 0) {
|
|
||||||
/* EOF, will this ever happen? */
|
|
||||||
/* fprintf (stderr, */
|
|
||||||
/* "WARNING: IPC: Reached eof in message body on socket\n");*/
|
|
||||||
return handle_socket_eof ();
|
|
||||||
} else if (count == -1) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: reading message body from socket\n");
|
|
||||||
perror ("ERROR: IPC");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Looks like we have a valid message here. Put in the string terminator. */
|
|
||||||
*len = count;
|
|
||||||
str[count] = '\0';
|
|
||||||
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
|
|
||||||
} /* end ipc_transport_get_line */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
FUNCTION ipc_transport_send_line
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
July 1991 Stefan Roth
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
Send a line of information. First sends a message header and
|
|
||||||
then the actual message body.
|
|
||||||
Error checking is done to make reasonably sure that the data was sent.
|
|
||||||
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
Called by: (IPC.c) ipc_flush ();
|
|
||||||
|
|
||||||
RETURNED VALUE
|
|
||||||
|
|
||||||
Ipc_Status_t - returns status of the send operation (typically
|
|
||||||
IPC_STATUS_ERROR or IPC_STATUS_OK).
|
|
||||||
|
|
||||||
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_transport_send_line (
|
|
||||||
char *str, /* IN - String to write */
|
|
||||||
int len ) /* IN - Number of characters out of STR to write */
|
|
||||||
{
|
|
||||||
int count; /* Counts how many bytes were actually written */
|
|
||||||
u_long u; /* 32-bit placeholder for transmission of LEN */
|
|
||||||
char hdr_buff[5]; /* Buffer for building header message in */
|
|
||||||
int i; /* Temporary counter */
|
|
||||||
char *char_ptr; /* Pointer for int to bytes conversion */
|
|
||||||
|
|
||||||
if (sock_state != IPC_SOCK_CONNECTED_TO_CLIENT) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: Attempt to write to non-open socket\n");
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write message body header with length: */
|
|
||||||
hdr_buff[0] = BOL_CHAR;
|
|
||||||
u = htonl ((uint32_t) len);
|
|
||||||
char_ptr = (char *) &u;
|
|
||||||
for(i = 0; i < 4; i++)
|
|
||||||
hdr_buff[i+1] = char_ptr[i];
|
|
||||||
|
|
||||||
count = (int) write (msg_stream, hdr_buff, 5);
|
|
||||||
if (count != 5) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: (%d) send line error 1\n", count);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write message body: */
|
|
||||||
count = (int) write (msg_stream, str, (size_t) len);
|
|
||||||
if (count != len) {
|
|
||||||
fprintf (stderr, "ERROR: IPC: (%d) send line error 2\n", count);
|
|
||||||
return IPC_STATUS_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
} /* end ipc_transport_send_line */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*=============================================================================
|
|
||||||
|
|
||||||
FUNCTION ipc_transport_terminate_server
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
July 1991 Stefan Roth
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
This function reads all pending incoming messages and discards them.
|
|
||||||
Reading continues until a read error occurs or EOF is reached, at which
|
|
||||||
time the socket is closed.
|
|
||||||
Note that this function does not actually close the socket. This is
|
|
||||||
done in ipc_transport_get_line, which is called in this function.
|
|
||||||
|
|
||||||
In this function, the incoming line length is limited. See buffer below.
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
Called by: (IPC.c) ipc_terminate_server();
|
|
||||||
|
|
||||||
RETURNED VALUE
|
|
||||||
|
|
||||||
Ipc_Status_t - returns status of last read operation (always
|
|
||||||
IPC_STATUS_ERROR or IPC_STATUS_EOF).
|
|
||||||
|
|
||||||
GLOBAL VARIABLES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
NONE
|
|
||||||
|
|
||||||
=============================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Status_t
|
|
||||||
ipc_transport_terminate_server (void)
|
|
||||||
{
|
|
||||||
char buffer[17000]; /* temp buffer for incoming data */
|
|
||||||
int len; /* placeholder var to as arg to function */
|
|
||||||
Ipc_Status_t status; /* value to be returned from function */
|
|
||||||
int max_size; /* Max length of buffer */
|
|
||||||
|
|
||||||
max_size = sizeof (buffer);
|
|
||||||
do {
|
|
||||||
len = max_size;
|
|
||||||
status = ipc_transport_get_line (buffer, &len, IPC_WAIT);
|
|
||||||
} while ((status != IPC_STATUS_ERROR) &&
|
|
||||||
(status != IPC_STATUS_EOF));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* IPC_UNIX_SOCKETS */
|
|
||||||
|
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* Steve Tynor
|
|
||||||
*
|
|
||||||
* Generic Interprocess Communication module
|
|
||||||
*
|
|
||||||
* Used for debugging in absense of IPC interface.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ngspice/ngspice.h"
|
|
||||||
|
|
||||||
#ifdef IPC_DEBUG_VIA_STDIO
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
#include "ngspice/ipc.h"
|
|
||||||
|
|
||||||
#include "ngspice/ipcproto.h"
|
|
||||||
|
|
||||||
#include <assert.h> /* 12/1/97 jg */
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
Ipc_Status_t ipc_transport_initialize_server (
|
|
||||||
char *server_name,
|
|
||||||
Ipc_Mode_t m,
|
|
||||||
Ipc_Protocol_t p,
|
|
||||||
char *batch_filename )
|
|
||||||
{
|
|
||||||
NG_IGNORE(server_name);
|
|
||||||
NG_IGNORE(p);
|
|
||||||
NG_IGNORE(batch_filename);
|
|
||||||
|
|
||||||
assert (m == IPC_MODE_INTERACTIVE);
|
|
||||||
printf ("INITIALIZE_SERVER\n");
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
Ipc_Status_t ipc_transport_get_line (
|
|
||||||
char *str,
|
|
||||||
int *len,
|
|
||||||
Ipc_Wait_t wait )
|
|
||||||
{
|
|
||||||
NG_IGNORE(wait);
|
|
||||||
|
|
||||||
printf ("GET_LINE\n");
|
|
||||||
fgets (str, 512, stdin);
|
|
||||||
char *tmp = strchr(str, '\n');
|
|
||||||
if (tmp)
|
|
||||||
*tmp = '\0';
|
|
||||||
*len = (int) strlen (str);
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
Ipc_Status_t ipc_transport_send_line (
|
|
||||||
char *str,
|
|
||||||
int len )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
printf ("SEND_LINE: /");
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
putchar (str[i]);
|
|
||||||
printf ("/\n");
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
Ipc_Status_t ipc_transport_terminate_server (void)
|
|
||||||
{
|
|
||||||
return IPC_STATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* IPC_DEBUG_VIA_STDIO */
|
|
||||||
|
|
@ -1,520 +0,0 @@
|
||||||
/*============================================================================
|
|
||||||
FILE IPCtiein.c
|
|
||||||
|
|
||||||
MEMBER OF process XSPICE
|
|
||||||
|
|
||||||
Public Domain
|
|
||||||
|
|
||||||
Georgia Tech Research Corporation
|
|
||||||
Atlanta, Georgia 30332
|
|
||||||
PROJECT A-8503
|
|
||||||
|
|
||||||
AUTHORS
|
|
||||||
|
|
||||||
9/12/91 Bill Kuhn
|
|
||||||
|
|
||||||
MODIFICATIONS
|
|
||||||
|
|
||||||
<date> <person name> <nature of modifications>
|
|
||||||
|
|
||||||
SUMMARY
|
|
||||||
|
|
||||||
Provides a protocol independent interface between the simulator
|
|
||||||
and the IPC method used to interface to CAE packages.
|
|
||||||
|
|
||||||
INTERFACES
|
|
||||||
|
|
||||||
g_ipc (global variable)
|
|
||||||
|
|
||||||
ipc_handle_stop()
|
|
||||||
ipc_handle_returni()
|
|
||||||
ipc_handle_mintime()
|
|
||||||
ipc_handle_vtrans()
|
|
||||||
ipc_send_stdout()
|
|
||||||
ipc_send_stderr()
|
|
||||||
ipc_send_std_files()
|
|
||||||
ipc_screen_name()
|
|
||||||
ipc_get_devices()
|
|
||||||
ipc_free_devices()
|
|
||||||
ipc_check_pause_stop()
|
|
||||||
|
|
||||||
REFERENCED FILES
|
|
||||||
|
|
||||||
None.
|
|
||||||
|
|
||||||
NON-STANDARD FEATURES
|
|
||||||
|
|
||||||
None.
|
|
||||||
|
|
||||||
============================================================================*/
|
|
||||||
|
|
||||||
|
|
||||||
#define CONFIG
|
|
||||||
|
|
||||||
#include "ngspice/ngspice.h"
|
|
||||||
#include "ngspice/inpdefs.h"
|
|
||||||
#include "ngspice/gendefs.h"
|
|
||||||
#include "ngspice/cktdefs.h"
|
|
||||||
#include "bjt/bjtdefs.h"
|
|
||||||
#include "jfet/jfetdefs.h"
|
|
||||||
#include "mos1/mos1defs.h"
|
|
||||||
#include "mos2/mos2defs.h"
|
|
||||||
#include "mos3/mos3defs.h"
|
|
||||||
#include "ngspice/mifproto.h"
|
|
||||||
#include "ngspice/ipc.h"
|
|
||||||
#include "ngspice/ipctiein.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Global variable g_ipc is used by the SPICE mods that take care of
|
|
||||||
interprocess communications activities.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Ipc_Tiein_t g_ipc = {
|
|
||||||
IPC_FALSE, /* enabled */
|
|
||||||
IPC_MODE_INTERACTIVE, /* mode */
|
|
||||||
IPC_ANAL_DCOP, /* analysis mode */
|
|
||||||
IPC_FALSE, /* parse_error */
|
|
||||||
IPC_FALSE, /* run_error */
|
|
||||||
IPC_FALSE, /* errchk_sent */
|
|
||||||
IPC_FALSE, /* returni */
|
|
||||||
0.0, /* mintime */
|
|
||||||
0.0, /* lasttime */
|
|
||||||
0.0, /* cpu time */
|
|
||||||
NULL, /* send array */
|
|
||||||
NULL, /* log file */
|
|
||||||
{ /* vtrans struct */
|
|
||||||
0, /* size */
|
|
||||||
NULL, /* vsrc_name array */
|
|
||||||
NULL, /* device_name array */
|
|
||||||
},
|
|
||||||
IPC_FALSE, /* stop analysis */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_handle_stop
|
|
||||||
|
|
||||||
This function sets a flag in the g_ipc variable to signal that
|
|
||||||
a stop message has been received over the IPC channel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ipc_handle_stop(void)
|
|
||||||
{
|
|
||||||
g_ipc.stop_analysis = IPC_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_handle_returni
|
|
||||||
|
|
||||||
This function sets a flag in the g_ipc variable to signal that
|
|
||||||
a message has been received over the IPC channel specifying that
|
|
||||||
current values are to be returned in the results data sets.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ipc_handle_returni(void)
|
|
||||||
{
|
|
||||||
g_ipc.returni = IPC_TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_handle_mintime
|
|
||||||
|
|
||||||
This function sets a value in the g_ipc variable that specifies
|
|
||||||
how often data is to be returned as it is computed. If the
|
|
||||||
simulator takes timestep backups, data may still be returned
|
|
||||||
more often that that specified by 'mintime' so that glitches
|
|
||||||
are not missed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ipc_handle_mintime(double time)
|
|
||||||
{
|
|
||||||
g_ipc.mintime = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_handle_vtrans
|
|
||||||
|
|
||||||
This function processes arguments from a #VTRANS card received over
|
|
||||||
the IPC channel. The data on the card specifies that a particular
|
|
||||||
zero-valued voltage source name should be translated to the specified
|
|
||||||
instance name for which it was setup to monitor currents.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ipc_handle_vtrans(
|
|
||||||
char *vsrc, /* The name of the voltage source to be translated */
|
|
||||||
char *dev) /* The device name the vsource name should be translated to */
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int size;
|
|
||||||
|
|
||||||
|
|
||||||
if(g_ipc.vtrans.size == 0) {
|
|
||||||
g_ipc.vtrans.size = 1;
|
|
||||||
g_ipc.vtrans.vsrc_name = TMALLOC(char *, 1);
|
|
||||||
g_ipc.vtrans.device_name = TMALLOC(char *, 1);
|
|
||||||
g_ipc.vtrans.vsrc_name[0] = MIFcopy(vsrc);
|
|
||||||
g_ipc.vtrans.device_name[0] = MIFcopy(dev);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g_ipc.vtrans.size++;
|
|
||||||
|
|
||||||
size = g_ipc.vtrans.size;
|
|
||||||
i = g_ipc.vtrans.size - 1;
|
|
||||||
|
|
||||||
g_ipc.vtrans.vsrc_name = TREALLOC(char *, g_ipc.vtrans.vsrc_name, size);
|
|
||||||
g_ipc.vtrans.device_name = TREALLOC(char *, g_ipc.vtrans.device_name, size);
|
|
||||||
g_ipc.vtrans.vsrc_name[i] = MIFcopy(vsrc);
|
|
||||||
g_ipc.vtrans.device_name[i] = MIFcopy(dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_stdout
|
|
||||||
|
|
||||||
This function sends the data written to stdout over the IPC channel.
|
|
||||||
This stream was previously redirected to a temporary file during
|
|
||||||
the simulation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ipc_send_stdout(void)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
char buf[IPC_MAX_LINE_LEN+1];
|
|
||||||
|
|
||||||
/* rewind the redirected stdout stream */
|
|
||||||
rewind(stdout);
|
|
||||||
|
|
||||||
/* Begin reading from the top of file and send lines */
|
|
||||||
/* over the IPC channel. */
|
|
||||||
|
|
||||||
/* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */
|
|
||||||
/* we must wrap it because Mspice can't handle it */
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
while( (c=fgetc(stdout)) != EOF) {
|
|
||||||
if(c != '\n') {
|
|
||||||
buf[len] = (char) c;
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
if((c == '\n') || (len == IPC_MAX_LINE_LEN)) {
|
|
||||||
buf[len] = '\0';
|
|
||||||
ipc_send_line(buf);
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(len > 0) {
|
|
||||||
buf[len] = '\0';
|
|
||||||
ipc_send_line(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finally, rewind file again to discard the data already sent */
|
|
||||||
rewind(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_stderr
|
|
||||||
|
|
||||||
This function sends the data written to stderr over the IPC channel.
|
|
||||||
This stream was previously redirected to a temporary file during
|
|
||||||
the simulation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ipc_send_stderr(void)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
int len;
|
|
||||||
|
|
||||||
char buf[IPC_MAX_LINE_LEN+1];
|
|
||||||
|
|
||||||
/* rewind the redirected stderr stream */
|
|
||||||
rewind(stderr);
|
|
||||||
|
|
||||||
/* Begin reading from the top of file and send lines */
|
|
||||||
/* over the IPC channel. */
|
|
||||||
|
|
||||||
/* Don't send newlines. Also, if line is > IPC_MAX_LINE_LEN chars */
|
|
||||||
/* we must wrap it because Mspice can't handle it */
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
while( (c=fgetc(stderr)) != EOF) {
|
|
||||||
if(c != '\n') {
|
|
||||||
buf[len] = (char) c;
|
|
||||||
len++;
|
|
||||||
}
|
|
||||||
if((c == '\n') || (len == IPC_MAX_LINE_LEN)) {
|
|
||||||
buf[len] = '\0';
|
|
||||||
ipc_send_line(buf);
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(len > 0) {
|
|
||||||
buf[len] = '\0';
|
|
||||||
ipc_send_line(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finally, rewind file again to discard the data already sent */
|
|
||||||
rewind(stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_send_std_files
|
|
||||||
|
|
||||||
This function sends the data written to stdout and stderr over the
|
|
||||||
IPC channel. These streams were previously redirected to temporary
|
|
||||||
files during the simulation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Status_t ipc_send_std_files(void)
|
|
||||||
{
|
|
||||||
ipc_send_stdout();
|
|
||||||
ipc_send_stderr();
|
|
||||||
|
|
||||||
return(ipc_flush());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_screen_name
|
|
||||||
|
|
||||||
This function screens names of instances and nodes to limit the
|
|
||||||
data returned over the IPC channel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
Ipc_Boolean_t ipc_screen_name(char *name, char *mapped_name)
|
|
||||||
{
|
|
||||||
char *endp;
|
|
||||||
int i;
|
|
||||||
int len;
|
|
||||||
long l;
|
|
||||||
|
|
||||||
/* Return FALSE if name is in a subcircuit */
|
|
||||||
for(i = 0; name[i] != '\0'; i++) {
|
|
||||||
if(name[i] == ':')
|
|
||||||
return(IPC_FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determine if name is numeric and what value is */
|
|
||||||
l = strtol(name, &endp, 10);
|
|
||||||
|
|
||||||
/* If numeric */
|
|
||||||
if(*endp == '\0') {
|
|
||||||
/* Return FALSE if >100,000 -> added by ms_server in ATESSE 1.0 */
|
|
||||||
if(l >= 100000)
|
|
||||||
return(IPC_FALSE);
|
|
||||||
/* Otherwise, copy name to mapped name and return true */
|
|
||||||
else {
|
|
||||||
strcpy(mapped_name,name);
|
|
||||||
return(IPC_TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If node is an internal node from a semiconductor (indicated by a */
|
|
||||||
/* trailing #collector, #source, ...), do not return its current. */
|
|
||||||
/* Otherwise, map to upper case and eliminate trailing "#branch" if any. */
|
|
||||||
for(i = 0; name[i]; i++) {
|
|
||||||
if(name[i] == '#') {
|
|
||||||
if(strcmp(name + i, "#branch") == 0)
|
|
||||||
break;
|
|
||||||
else
|
|
||||||
return(IPC_FALSE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(islower_c(name[i]))
|
|
||||||
mapped_name[i] = toupper_c(name[i]);
|
|
||||||
else
|
|
||||||
mapped_name[i] = name[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mapped_name[i] = '\0';
|
|
||||||
len = i;
|
|
||||||
|
|
||||||
/* If len != 8 or 6'th char not equal to $, then doesn't need vtrans */
|
|
||||||
/* Otherwise, translate to device name that it monitors */
|
|
||||||
if(len != 8)
|
|
||||||
return(IPC_TRUE);
|
|
||||||
else if(name[5] != '$')
|
|
||||||
return(IPC_TRUE);
|
|
||||||
else {
|
|
||||||
/* Scan list of prefixes in VTRANS table and convert name */
|
|
||||||
for(i = 0; i < g_ipc.vtrans.size; i++) {
|
|
||||||
if(strncmp(mapped_name, g_ipc.vtrans.vsrc_name[i], 5) == 0) {
|
|
||||||
strcpy(mapped_name, g_ipc.vtrans.device_name[i]);
|
|
||||||
return(IPC_TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(IPC_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_get_devices
|
|
||||||
|
|
||||||
This function is used to setup the OUTinterface data structure that
|
|
||||||
determines what instances will have data returned over the IPC channel.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
int ipc_get_devices(
|
|
||||||
CKTcircuit *ckt, /* The circuit structure */
|
|
||||||
char *device, /* The device name as it appears in the info struct */
|
|
||||||
char ***names, /* Array of name strings to be built */
|
|
||||||
double **modtypes) /* Array of types to be built */
|
|
||||||
{
|
|
||||||
int index;
|
|
||||||
int num_instances;
|
|
||||||
GENmodel *model;
|
|
||||||
GENinstance *here;
|
|
||||||
char *inst_name;
|
|
||||||
int inst_name_len;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
BJTmodel *BJTmod;
|
|
||||||
JFETmodel *JFETmod;
|
|
||||||
MOS1model *MOS1mod;
|
|
||||||
MOS2model *MOS2mod;
|
|
||||||
MOS3model *MOS3mod;
|
|
||||||
|
|
||||||
/* Initialize local variables */
|
|
||||||
num_instances = 0;
|
|
||||||
|
|
||||||
/* Get the index into the circuit structure linked list of models */
|
|
||||||
index = INPtypelook(device);
|
|
||||||
|
|
||||||
/* Iterate through all models of this type */
|
|
||||||
for(model = ckt->CKThead[index]; model; model = model->GENnextModel) {
|
|
||||||
|
|
||||||
/* Iterate through all instance of this model */
|
|
||||||
for(here = model->GENinstances; here; here = here->GENnextInstance) {
|
|
||||||
|
|
||||||
/* Get the name of the instance */
|
|
||||||
inst_name = here->GENname;
|
|
||||||
inst_name_len = (int) strlen(inst_name);
|
|
||||||
|
|
||||||
/* Skip if it is a inside a subcircuit */
|
|
||||||
for(i = 0; i < inst_name_len; i++)
|
|
||||||
if(inst_name[i] == ':')
|
|
||||||
break;
|
|
||||||
if(i < inst_name_len)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Otherwise, add the name to the list */
|
|
||||||
num_instances++;
|
|
||||||
if(num_instances == 1)
|
|
||||||
*names = TMALLOC(char *, 1);
|
|
||||||
else
|
|
||||||
*names = TREALLOC(char *, *names, num_instances);
|
|
||||||
(*names)[num_instances-1] = MIFcopy(inst_name);
|
|
||||||
|
|
||||||
/* Then get the type if it is a Q J or M */
|
|
||||||
if(num_instances == 1)
|
|
||||||
*modtypes = TMALLOC(double, 1);
|
|
||||||
else
|
|
||||||
*modtypes = TREALLOC(double, *modtypes, num_instances);
|
|
||||||
|
|
||||||
if(strcmp(device,"BJT") == 0) {
|
|
||||||
BJTmod = (BJTmodel *) model;
|
|
||||||
(*modtypes)[num_instances-1] = BJTmod->BJTtype;
|
|
||||||
}
|
|
||||||
else if(strcmp(device,"JFET") == 0) {
|
|
||||||
JFETmod = (JFETmodel *) model;
|
|
||||||
(*modtypes)[num_instances-1] = JFETmod->JFETtype;
|
|
||||||
}
|
|
||||||
else if(strcmp(device,"Mos1") == 0) {
|
|
||||||
MOS1mod = (MOS1model *) model;
|
|
||||||
(*modtypes)[num_instances-1] = MOS1mod->MOS1type;
|
|
||||||
}
|
|
||||||
else if(strcmp(device,"Mos2") == 0) {
|
|
||||||
MOS2mod = (MOS2model *) model;
|
|
||||||
(*modtypes)[num_instances-1] = MOS2mod->MOS2type;
|
|
||||||
}
|
|
||||||
else if(strcmp(device,"Mos3") == 0) {
|
|
||||||
MOS3mod = (MOS3model *) model;
|
|
||||||
(*modtypes)[num_instances-1] = MOS3mod->MOS3type;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
(*modtypes)[num_instances-1] = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* end for all instances */
|
|
||||||
} /* end for all models */
|
|
||||||
|
|
||||||
return(num_instances);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_free_devices
|
|
||||||
|
|
||||||
This function frees temporary data created by ipc_get_devices().
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void ipc_free_devices(
|
|
||||||
int num_items, /* Number of things to free */
|
|
||||||
char **names, /* Array of name strings to be built */
|
|
||||||
double *modtypes) /* Array of types to be built */
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < num_items; i++)
|
|
||||||
{
|
|
||||||
FREE(names[i]);
|
|
||||||
names[i] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(num_items > 0)
|
|
||||||
{
|
|
||||||
FREE(names);
|
|
||||||
FREE(modtypes);
|
|
||||||
|
|
||||||
names = NULL;
|
|
||||||
modtypes = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
ipc_check_pause_stop
|
|
||||||
|
|
||||||
This function is called at various times during a simulation to check
|
|
||||||
for incoming messages of the form >STOP or >PAUSE signaling that
|
|
||||||
simulation should be stopped or paused. Processing of the messages
|
|
||||||
is handled by ipc_get_line().
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ipc_check_pause_stop(void)
|
|
||||||
{
|
|
||||||
char buf[1025];
|
|
||||||
int len;
|
|
||||||
|
|
||||||
/* If already seen stop analysis, don't call ipc_get_line, just return. */
|
|
||||||
/* This is provided so that the function can be called multiple times */
|
|
||||||
/* during the process of stopping */
|
|
||||||
if(g_ipc.stop_analysis)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Otherwise do a non-blocking call to ipc_get_line() to check for messages. */
|
|
||||||
/* We assume that the only possible messages at this point are >PAUSE */
|
|
||||||
/* and >STOP, so we don't do anything with the returned text if any */
|
|
||||||
ipc_get_line(buf, &len, IPC_NO_WAIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -794,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\inpmacs.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\ipc.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\jobdefs.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
||||||
|
|
@ -2612,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\evtshared.c" />
|
||||||
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
||||||
<ClCompile Include="..\src\xspice\idn\idndig.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\mif.c" />
|
||||||
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
||||||
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
||||||
|
|
|
||||||
|
|
@ -1011,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\inpmacs.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\ipc.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\jobdefs.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
||||||
|
|
@ -2832,11 +2830,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\evtsetup.c" />
|
||||||
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
||||||
<ClCompile Include="..\src\xspice\idn\idndig.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\mif.c" />
|
||||||
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
||||||
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
||||||
|
|
|
||||||
|
|
@ -1026,8 +1026,6 @@
|
||||||
<ClInclude Include="..\src\include\ngspice\inpmacs.h" />
|
<ClInclude Include="..\src\include\ngspice\inpmacs.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
<ClInclude Include="..\src\include\ngspice\inpptree.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\ipc.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\jobdefs.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
<ClInclude Include="..\src\include\ngspice\lsort.h" />
|
||||||
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
<ClInclude Include="..\src\include\ngspice\macros.h" />
|
||||||
|
|
@ -2847,11 +2845,6 @@
|
||||||
<ClCompile Include="..\src\xspice\evt\evtsetup.c" />
|
<ClCompile Include="..\src\xspice\evt\evtsetup.c" />
|
||||||
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
<ClCompile Include="..\src\xspice\evt\evttermi.c" />
|
||||||
<ClCompile Include="..\src\xspice\idn\idndig.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\mif.c" />
|
||||||
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
<ClCompile Include="..\src\xspice\mif\mifask.c" />
|
||||||
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
<ClCompile Include="..\src\xspice\mif\mifbindCSC.c" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue