2003-07-23 21:59:53 +02:00
|
|
|
/*============================================================================
|
|
|
|
|
FILE IPCtiein.c
|
|
|
|
|
|
|
|
|
|
MEMBER OF process XSPICE
|
|
|
|
|
|
|
|
|
|
Copyright 1991
|
|
|
|
|
Georgia Tech Research Corporation
|
|
|
|
|
Atlanta, Georgia 30332
|
|
|
|
|
All Rights Reserved
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
============================================================================*/
|
|
|
|
|
|
|
|
|
|
|
2004-07-09 20:37:25 +02:00
|
|
|
#define CONFIG
|
2003-07-23 21:59:53 +02:00
|
|
|
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/ngspice.h"
|
|
|
|
|
#include "ngspice/inpdefs.h"
|
|
|
|
|
#include "ngspice/gendefs.h"
|
|
|
|
|
#include "ngspice/cktdefs.h"
|
2003-07-23 21:59:53 +02:00
|
|
|
#include "bjt/bjtdefs.h"
|
|
|
|
|
#include "jfet/jfetdefs.h"
|
|
|
|
|
#include "mos1/mos1defs.h"
|
|
|
|
|
#include "mos2/mos2defs.h"
|
|
|
|
|
#include "mos3/mos3defs.h"
|
2011-12-11 19:05:00 +01:00
|
|
|
#include "ngspice/mifproto.h"
|
|
|
|
|
#include "ngspice/ipc.h"
|
|
|
|
|
#include "ngspice/ipctiein.h"
|
2003-07-23 21:59:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
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;
|
2010-10-28 21:32:34 +02:00
|
|
|
g_ipc.vtrans.vsrc_name = TMALLOC(char *, 1);
|
|
|
|
|
g_ipc.vtrans.device_name = TMALLOC(char *, 1);
|
2003-07-23 21:59:53 +02:00
|
|
|
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;
|
|
|
|
|
|
2010-10-28 21:32:34 +02:00
|
|
|
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);
|
2003-07-23 21:59:53 +02:00
|
|
|
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') {
|
2010-11-02 18:31:19 +01:00
|
|
|
buf[len] = (char) c;
|
2003-07-23 21:59:53 +02:00
|
|
|
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') {
|
2010-11-02 18:31:19 +01:00
|
|
|
buf[len] = (char) c;
|
2003-07-23 21:59:53 +02:00
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
2010-06-27 11:27:49 +02:00
|
|
|
Ipc_Status_t ipc_send_std_files(void)
|
2003-07-23 21:59:53 +02:00
|
|
|
{
|
|
|
|
|
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 {
|
2016-03-08 21:20:11 +01:00
|
|
|
if(islower_c(name[i]))
|
2016-03-08 21:24:40 +01:00
|
|
|
mapped_name[i] = toupper_c(name[i]);
|
2003-07-23 21:59:53 +02:00
|
|
|
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(
|
2011-05-08 14:52:58 +02:00
|
|
|
CKTcircuit *ckt, /* The circuit structure */
|
2003-07-23 21:59:53 +02:00
|
|
|
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;
|
2010-11-02 18:17:43 +01:00
|
|
|
inst_name_len = (int) strlen(inst_name);
|
2003-07-23 21:59:53 +02:00
|
|
|
|
|
|
|
|
/* 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)
|
2010-10-28 21:32:34 +02:00
|
|
|
*names = TMALLOC(char *, 1);
|
2003-07-23 21:59:53 +02:00
|
|
|
else
|
2010-10-28 21:32:34 +02:00
|
|
|
*names = TREALLOC(char *, *names, num_instances);
|
2003-07-23 21:59:53 +02:00
|
|
|
(*names)[num_instances-1] = MIFcopy(inst_name);
|
|
|
|
|
|
|
|
|
|
/* Then get the type if it is a Q J or M */
|
|
|
|
|
if(num_instances == 1)
|
2010-10-28 21:32:34 +02:00
|
|
|
*modtypes = TMALLOC(double, 1);
|
2003-07-23 21:59:53 +02:00
|
|
|
else
|
2010-10-28 21:32:34 +02:00
|
|
|
*modtypes = TREALLOC(double, *modtypes, num_instances);
|
2003-07-23 21:59:53 +02:00
|
|
|
|
|
|
|
|
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]);
|
2015-05-02 10:24:49 +02:00
|
|
|
names[i] = NULL;
|
2003-07-23 21:59:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|