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,
IPC_MODE_INTERACTIVE,
IPC_ANAL_DCOP,
IPC_FALSE,
IPC_FALSE,
IPC_FALSE,
IPC_FALSE,
0.0,
0.0,
0.0,
NULL,
NULL,
{
0,
NULL,
NULL,
},
IPC_FALSE,
};
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,
char *dev)
{
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(stdout);
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);
}
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(stderr);
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);
}
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;
for(i = 0; name[i] != '\0'; i++) {
if(name[i] == ':')
return(IPC_FALSE);
}
l = strtol(name, &endp, 10);
if(*endp == '\0') {
if(l >= 100000)
return(IPC_FALSE);
else {
strcpy(mapped_name,name);
return(IPC_TRUE);
}
}
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)
return(IPC_TRUE);
else if(name[5] != '$')
return(IPC_TRUE);
else {
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,
char *device,
char ***names,
double **modtypes)
{
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;
num_instances = 0;
index = INPtypelook(device);
for(model = ckt->CKThead[index]; model; model = model->GENnextModel) {
for(here = model->GENinstances; here; here = here->GENnextInstance) {
inst_name = here->GENname;
inst_name_len = (int) strlen(inst_name);
for(i = 0; i < inst_name_len; i++)
if(inst_name[i] == ':')
break;
if(i < inst_name_len)
continue;
num_instances++;
if(num_instances == 1)
*names = TMALLOC(char *, 1);
else
*names = TREALLOC(char *, *names, num_instances);
(*names)[num_instances-1] = MIFcopy(inst_name);
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;
}
}
}
return(num_instances);
}
ipc_free_devices
This function frees temporary data created by ipc_get_devices().
*/
void ipc_free_devices(
int num_items,
char **names,
double *modtypes)
{
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(g_ipc.stop_analysis)
return;
ipc_get_line(buf, &len, IPC_NO_WAIT);
}