Insert XSPICE bridging devices automatically when an analogue node

has the same name as an XSPICE event node (including digital nodes).
The function Evtcheck_nodes() is replaced by a new version in its
own file.
This commit is contained in:
Giles Atkinson 2022-04-08 14:00:33 +01:00 committed by Holger Vogt
parent 07bb809158
commit b1341c8e30
11 changed files with 754 additions and 73 deletions

View File

@ -43,13 +43,6 @@ Author: 1985 Wayne A. Christopher
#include "ngspice/randnumb.h"
#include "ngspice/compatmode.h"
#define line_free(line, flag) \
do { \
line_free_x(line, flag); \
line = NULL; \
} while(0)
static struct card *com_options = NULL;
static struct card *mc_deck = NULL;
static struct card *recent_deck = NULL;
@ -61,7 +54,6 @@ static void dotifeval(struct card *deck);
static void eval_agauss(struct card *deck, char *fcn);
static wordlist *inp_savecurrents(struct card *deck, struct card *options,
wordlist *wl, wordlist *controls);
void line_free_x(struct card *deck, bool recurse);
static void recifeval(struct card *pdeck);
static char *upper(register char *string);
static void rem_unused_mos_models(struct card* deck);
@ -188,6 +180,9 @@ com_listing(wordlist *wl)
inp_list(cp_out,
expand ? ft_curckt->ci_deck : ft_curckt->ci_origdeck,
ft_curckt->ci_options, type);
if (expand && ft_curckt->ci_auto && type != LS_RUNNABLE)
inp_list(cp_out, ft_curckt->ci_auto,
ft_curckt->ci_options, type);
}
} else {
fprintf(cp_err, "Error: no circuit loaded.\n");

View File

@ -12,5 +12,11 @@ void com_source(wordlist *wl);
void com_mc_source(wordlist *wl);
void com_circbyline(wordlist *wl);
void line_free_x(struct card *deck, bool recurse);
#define line_free(line, flag) \
do { \
line_free_x(line, flag); \
line = NULL; \
} while(0)
#endif

View File

@ -201,9 +201,6 @@ extern void inp_probe(struct card* card);
static void utf8_syntax_check(struct card *deck);
#endif
struct card* insert_new_line(
struct card* card, char* line, int linenum, int linenum_orig);
struct inp_read_t {
struct card *cc;
int line_number;
@ -411,7 +408,10 @@ static int is_cider_model(char *buf)
}
#endif
/* insert a new card, just behind the given card */
/* Insert a new card, just behind the given card.
* The new card takes ownership of the memory pointed to by "line".
*/
struct card *insert_new_line(
struct card *card, char *line, int linenum, int linenum_orig)
{

View File

@ -6,5 +6,7 @@
#ifndef ngspice_INPCOM_H
#define ngspice_INPCOM_H
struct card *insert_new_line(struct card *card, char *line,
int linenum, int linenum_orig);
#endif

View File

@ -233,6 +233,8 @@ com_remcirc(wordlist *wl)
line_free(dd, TRUE);
dd = ft_curckt->ci_meas;
line_free(dd, TRUE);
dd = ft_curckt->ci_auto;
line_free(dd, TRUE);
wl_free(ft_curckt->ci_commands);

View File

@ -88,7 +88,6 @@ static int finddev(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel *
/* espice fix integration */
static int finddev_special(CKTcircuit *ckt, char *name, GENinstance **devptr, GENmodel **modptr, int *device_or_model);
/* Input a single deck, and return a pointer to the circuit. */
CKTcircuit *
@ -166,6 +165,12 @@ if_inpdeck(struct card *deck, INPtables **tab)
/* Scan through the instance lines and parse the circuit. */
INPpas2(ckt, deck->nextcard, *tab, ft_curckt->ci_defTask);
#ifdef XSPICE
if (!Evtcheck_nodes(ckt, *tab)) {
ft_sperror(E_PRIVATE, "Evtcheck_nodes");
return NULL;
}
#endif
/* If option cshunt is given, add capacitors to each voltage node */
INPpas4(ckt, *tab);

View File

@ -128,6 +128,11 @@ void EVTaccept(
CKTcircuit *ckt, /* main circuit struct */
double time); /* time at which analog soln was accepted */
struct INPtables;
bool Evtcheck_nodes(
CKTcircuit *ckt, /* The circuit structure */
struct INPtables *stab); /* Symbol table. */
struct dvec *EVTfindvec(char *node);
#endif

View File

@ -40,6 +40,7 @@ struct circ {
struct card *ci_mcdeck; /* The compacted input deck, used by mc_source */
struct card *ci_options; /* The .option cards from the deck... */
struct card *ci_meas; /* .measure commands to run after simulation */
struct card *ci_auto ; /* Statements added automatically after parse */
struct card *ci_param; /* .param statements found in deck */
struct variable *ci_vars; /* ... and the parsed versions. */
bool ci_inprogress; /* We are in a break now. */

View File

@ -22,7 +22,8 @@ libevtxsp_la_SOURCES = \
evtplot.c \
evtqueue.c \
evttermi.c \
evtshared.c
evtshared.c \
evtcheck_nodes.c
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CFLAGS = $(STATIC)

View File

@ -0,0 +1,723 @@
/* Automatic insertion of XSPICE devices bridging event and analogue nodes.
* Giles Atkinson 2022.
* The contents of this file may belong in src/frontend, except that it is
* part of XSPICE.
*/
#include <ctype.h>
#include <errno.h>
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/devdefs.h"
#include "ngspice/inpdefs.h"
#include "ngspice/sperror.h"
#include "ngspice/wordlist.h"
#include "ngspice/fteext.h"
#include "ngspice/mif.h"
#include "ngspice/evt.h"
#include "ngspice/evtudn.h"
#include "ngspice/evtproto.h"
#include "ngspice/mif.h"
#include "../../frontend/inpcom.h"
#include "../../frontend/inp.h"
#include "../../frontend/subckt.h"
#include "../../frontend/variable.h"
#include "../../frontend/numparam/numpaif.h"
#include "../../misc/util.h"
/* Automatic insertion of bridge devices.
When using XSPICE to simulate digital devices in a mixed-mode simulation,
bridging devices must be included in the circuit to pass signals between the
analogue simulator and XSPICE. Such devices may be included in the netlist,
or they may can be inserted automatically. Different types of automatic
bridge may exist in the same circuit, depending on signal direction and
characteristics of the connected device, for example digital devices
powered by differing voltages. Non-digital XSPICE nodes are supported.
Bridging may be disabled by setting command variable "auto_bridge" to zero.
Values greater than one enable diagnostic outputs.
Automatic insertion works by checking node names; if the same name occurs in
both sides of the simulator, it indicates that a connection between
an analogue and a digital device has been specified. At this point no such
connection exists: it is created by adding the bridging device. Devices are
added by generating netlist lines describing them and then performing some
stages of ngspice's normal input processing.
To add a bridging device, one or two lines of netlist text are created.
Typically, one specifies the device itself (an XSPICE 'A' "device card")
and the other ("setup card") is the required model definition. Alternatively,
the setup card may use .include to read in a subcircuit definition and the
device card is a subcircuit ('X' card). Setup cards are processed once,
device cards, once per bridged node.
Inserted or included netlist lines use a restricted set of features. There
may be further includes and subcircuits, but nothing else apart from device
and model cards has been tested. Parameter and expression processing are
available, but parameters defined in the main circuit are inaccessible.
Models defined in the circuit may be used, but subcircuits are inaccessible.
These restictions arise from the fact that missing bridges are detected
after the circuit has been built. Previous parameter and subcircuit
definitions are no longer fully available.
The device card must be a format string for the C library function sprintf()
with one %d and two %s insertion indicators. The %d insertion makes the
device name unique and the string insertions supply a list of node names
that will be bridged. Optionally a final substitution for a double may be
included that will receive the value of internal variable, vcc (see below).
The results of formatting should be an XSPICE device card or a subcircuit call.
The setup and device cards to be used are determined by examining the
event node that is to be connected. The rules are a little complex,
but are intended to be very flexible, while easy to use in common
cases. If all XSPICE nodes are digital, using 3.3V supply and good
simulation of the device's electrical characteristics is not needed,
then nothing need be done. Other supply voltages can be handled by:
.param vcc=5
or similar, and the parameter may have different values in subcircuits.
Otherwise, the full rules follow. The third rule is intended to be useful
for device libraries whose devices are defined by subcircuits.
1: The program looks for a command interpreter variable
"auto_bridge_parm_TTTT" where TTTT is the node type string. So
"auto_bridge_parm_d" for digital nodes. The value should be the name of
a circuit parameter (.param card). If not found, ignore the next step,
except in the case of a digital node where the parameter name is assumed
to be "vcc". Initialise an internal variable, vcc, to zero.
2: Given a parameter name, find the most deeply-nested (in subcircuits) XSPICE
device that is connected to the node. Search upwards through the enclosing
subcircuits for a definition of the parameter. If found, set vcc from
the parameter.
3: If a command interpreter variable "no_auto_bridge_family": exists, go to
step 5. Search the connected device instances for a parameter, "Family"
with a string value. The first one found will be used. If the first
character of the value is not '*', the setup card will be ".include
FFFFF_DDD_bridge.cir" where FFFFF is the family and DDD is the signal
direction for the XSPICE device: "in", "out" or "inout". The device card
will be "Xauto_bridge%d %s %s bridge_FFFFF_DDD vcc=%g", so a suitably
parameterised subcircuit must be defined in the file.
4: If the first character was '*', look for a variable
"auto_bridge_FFFFF_TTTT_DDD" where FFFFF is the family, TTTT is the node
type string and DDD is the direction. So this might be
"auto_bridge_74HCT_d_inout" for a digital node. Use the variable's value
in step 6.
5: Look for a variable "auto_bridge_TTTT_DDD_NNNN" where TTTT and DDD are as
before and NNNN is the integer part of (vcc * 10).
6: Check and use the variable's value from step 2 or 5. It must be a list
of two or three elements: the setup card, device card and an optional
third value. If present, the third value in the list must be an integer,
specifying the maximum number of nodes handled by a single device. If
not present, or zero, there is no limit. If no variable was found, the
circuit fails, except for digital nodes where defaults are
supplied. Example:
set auto_bridge_real_out_0 = ( ".model real_output_bridge d_to_real"
"areal_bridge%d [ %s ] null [%s] delay=1e-6" )
(This would be on a single line and the spaces are important.)
For digital the defaults are:
( ".model auto_adc adc_bridge(in_low = %g in_high = %g)"
"auto_adc%d [ %s ] [ %s ] auto_adc" )
and
( ".model auto_dac dac_bridge(out_low = 0 out_high = %g)"
"auto_dac%d [ %s ] [ %s ] auto_dac" )
with vcc/2.0 or vcc substituted for %g as appropriate.
An example of an included subcircuit might be:
* Subcircuit for digital output buffer with impedance
.subckt auto_buf dig ana vcc=5
.model auto_dac dac_bridge(out_low = 0 out_high = {vcc})
auto_dac [ dig ] [ internal ] auto_dac
rint internal ana 100
.ends
and invoked by:
set auto_bridge_d_out_30 = ( ".include test_sub.cir"
"xauto_buf%d %s %s auto_buf vcc=%g"
1 )
*/
/* Working information about a type of bridge. */
struct bridge {
int udn_index; // Node type.
Mif_Dir_t direction; // IN, OUT or INOUT
double vcc; // A .param value used for matching.
const char *family; // Alternative match parameter.
struct bridge *next; // Linked list
int max, count; // How many nodes/device?
char *setup; // For model or inclusion card.
const char *format; // For device card.
int end_index; // Free buffer space
char held[256]; // Buffer with node names.
};
/* Enable/verbosity level */
#define AB_OFF 0
#define AB_SILENT 1
#define AB_DECK 2 // Show generated deck
#define BIG 999990000 // For fake linenumbers
/* Expand .include cards and subcircuits in a deck. */
static struct card *expand_deck(struct card *head)
{
struct card *card, *next;
char **pointers;
int i, dico;
/* Save the current parameter symbol table. */
dico = nupa_add_dicoslist();
/* Count the cards, allocate and fill a pointer array. */
for (i = 0, card = head; card; ++i, card = card->nextcard)
;
pointers = TMALLOC(char *, i + 1);
for (i = 0, card = head; card; ++i, card = card->nextcard)
pointers[i] = card->line;
pointers[i] = NULL;
/* Free the card headers. */
for (card = head; card; card = next) {
next = card->nextcard;
tfree(card);
}
/* The cards are passed to _inp_readall() via a global. */
circarray = pointers;
card = inp_readall(NULL, Infile_Path, FALSE, TRUE, NULL);
card = inp_subcktexpand(card);
/* Destroy the parameter table that was created in subcircuit/parameter
* expansion and restore the previous version.
*/
nupa_del_dicoS();
nupa_set_dicoslist(dico);
nupa_rem_dicoslist(dico);
return card;
}
/* Write a completed bridge instance card. */
static struct card *flush_card(struct bridge *bridge, int ln,
struct card *last)
{
char buff[2 * sizeof bridge->held + 128];
bridge->held[bridge->end_index] = '\0';
snprintf(buff, sizeof buff, bridge->format,
ln, bridge->held, bridge->held, bridge->vcc);
bridge->count = 0;
bridge->end_index = 0;
return insert_new_line(last, copy(buff), BIG + ln, 0);
}
/* Release memory used. */
static void free_bridges(struct bridge *bridge_list)
{
struct bridge *bridge;
while (bridge_list) {
/* Free the structure. Setup has gone. */
bridge = bridge_list;
bridge_list = bridge->next;
if (bridge->format)
tfree(bridge->format);
tfree(bridge);
}
}
/* Find an XSPICE device instance given its index number. Uses link chasing
* as at this point the indexable inst_table does not yet exist.
*/
static MIFinstance *find_inst(CKTcircuit *ckt, int index)
{
struct Evt_Inst_Info *chase;
int i;
for (i = 0, chase = ckt->evt->info.inst_list;
i < index && chase;
++i, chase = chase->next)
;
return chase ? chase->inst_ptr : NULL;
}
/* All ports are declared as outputs, but some may be INOUT. */
static Mif_Dir_t scan_ports(Evt_Node_Info_t *event_node, CKTcircuit *ckt)
{
Evt_Inst_Index_t *inst_list;
Evt_Inst_Info_t **inst_table;
inst_table = ckt->evt->info.inst_table;
for (inst_list = event_node->inst_list;
inst_list;
inst_list = inst_list->next) {
MIFinstance *inst;
int i;
inst = find_inst(ckt, inst_list->index);
for (i = 0; i < inst->num_conn; ++i) {
Mif_Conn_Data_t *conn;
int j;
conn = inst->conn[i];
if (conn->is_null || !conn->is_input)
continue;
for (j = 0; j < conn->size; ++j) {
Mif_Port_Data_t *port;
port = conn->port[j];
if (!strcmp(port->pos_node_str, event_node->name) ||
!strcmp(port->neg_node_str, event_node->name)) {
/* An inout connection to this node. */
return MIF_INOUT;
}
}
}
}
return MIF_OUT;
}
/* Examine a device and return its subcircuit nesting depth
* and possibly the value of its "family" parameter, if that exists.
*/
static int examine_device(MIFinstance *inst, const char **family)
{
struct MIFmodel *mp;
char *dot;
int i;
if (!*family) {
Mif_Param_Data_t *pdp;
IFparm *pp;
int type;
mp = MIFmodPtr(inst);
type = mp->MIFmodType;
pp = ft_sim->devices[type]->modelParms;
for (i = 0; i < inst->num_param; ++i) {
pdp = mp->param[i];
if (!pdp->is_null && pdp->eltype == IF_STRING &&
!strcmp(pp[i].keyword, "family")) {
/* Return value for "family" parameter. */
*family = pdp->element->svalue; // May be NULL
if (family && !family[0])
family = NULL; // Ignore empty string.
break;
}
}
}
for (i = 0, dot = inst->MIFname;
(dot = strchr(dot, '.'));
dot += 1, ++i)
;
return i;
}
/* Scan devices attached to node. Return the name of the deepest-nested
* one and the first "Family" parameter found.
*/
static const char *scan_devices(Evt_Node_Info_t *event_node,
CKTcircuit *ckt,
const char **family)
{
Evt_Inst_Index_t *inst_list;
MIFinstance *best_inst = NULL, *inst;
int best_depth = -1, depth, left;
/* Scan input connections. */
for (inst_list = event_node->inst_list;
inst_list;
inst_list = inst_list->next) {
inst = find_inst(ckt, inst_list->index);
depth = examine_device(inst, family);
if (depth > best_depth) {
best_depth = depth;
best_inst = inst;
}
}
if ((left = event_node->num_outputs)) {
Evt_Node_Info_t *node;
Evt_Output_Info_t *oip;
int i, my_index;
/* Find the index of this node (not stored). */
for (my_index = 0, node = ckt->evt->info.node_list;
node != event_node;
++my_index, node = node->next)
;
/* Scan output connections. */
for (i = 0, oip = ckt->evt->info.output_list;
oip;
++i, oip = oip->next) {
if (oip->node_index == my_index) {
inst = find_inst(ckt, oip->inst_index);
depth = examine_device(inst, family);
if (depth > best_depth) {
best_depth = depth;
best_inst = inst;
}
if (--left == 0)
break;
}
}
}
return best_inst ? best_inst->MIFname : NULL;
}
/* Can a bridge element be inserted? */
static struct bridge *find_bridge(Evt_Node_Info_t *event_node,
CKTcircuit *ckt,
struct bridge **bridge_list_p)
{
static const char * const dirs[] = {"in", "out", "inout"};
struct bridge *bridge;
Mif_Dir_t direction;
const char *format = NULL;
const char *type_name, *family, *s_family, *deep;
char *setup, *vcc_parm, *dot;
double vcc;
int max = 0, ok;
struct variable *cvar = NULL;
char buff[256];
/* Find the direction for this node. */
if (event_node->num_outputs == 0) {
direction = MIF_IN;
} else if (event_node->num_outputs < event_node->num_ports) {
direction = MIF_INOUT;
} else {
direction = scan_ports(event_node, ckt); // Ugly
}
/* Find the vcc parameter for this node. */
type_name = g_evt_udn_info[event_node->udn_index]->name;
snprintf(buff, sizeof buff, "auto_bridge_parm_%s", type_name);
if (cp_getvar(buff, CP_STRING, buff, sizeof buff))
vcc_parm = buff;
else if (event_node->udn_index == 0)
vcc_parm = "vcc";
else
vcc_parm = NULL;
/* Scan attached XSPICE devices for the deepest nested one and
* a device with a "family" parameter.
*/
family = NULL;
deep = scan_devices(event_node, ckt, &family);
if (family && cp_getvar("no_auto_bridge_family", CP_BOOL, NULL, 0))
family = NULL;
/* Look for a real parameter (.param type) in the device's subcircuit,
* and those enclosing it.
*/
snprintf(buff, sizeof buff, "%s", deep);
while ((dot = strrchr(buff, '.'))) {
snprintf(dot + 1, sizeof buff - (size_t)(dot - buff), vcc_parm);
vcc = nupa_get_param(buff, &ok);
if (ok)
break;
*dot = '\0';
}
if (dot == NULL) {
vcc = nupa_get_param(vcc_parm, &ok);
if (!ok && event_node->udn_index == 0) // Fallback default for digital.
vcc = 3.3;
} else {
vcc = 0;
}
if (family && *family == '*') {
s_family = family + 1;
family = NULL; // Not used for matching.
} else {
s_family = NULL;
}
/* Look for an existing entry. */
for (bridge = *bridge_list_p; bridge; bridge = bridge->next) {
if (bridge->udn_index == event_node->udn_index &&
bridge->direction == direction) {
if (family) {
if (!strcmp(family, bridge->family)) {
/* Return vcc for formatting: requires bridge->max == 1. */
bridge->vcc = vcc;
break;
}
} else if (bridge->vcc == vcc) { // Match vcc.
break;
}
}
}
if (bridge)
return bridge;
/* Determine if a bridging element exists, starting with the node type. */
if (family) {
/* Use standard pattern for known parts family. */
snprintf(buff, sizeof buff, ".include %s_%s_bridge.cir",
family, dirs[direction]);
setup = copy(buff);
snprintf(buff, sizeof buff,
"Xauto_bridge%%d %%s %%s bridge_%s_%s vcc=%%g",
family, dirs[direction]);
format = copy(buff);
max = 1;
} else if (s_family) {
/* Family variable lookup. */
snprintf(buff, sizeof buff, "auto_bridge_%s_%s_%s",
s_family, type_name, dirs[direction]);
cp_getvar(buff, CP_LIST, &cvar, sizeof cvar);
}
if (!format && !cvar) {
/* General variable lookup. */
snprintf(buff, sizeof buff, "auto_bridge_%s_%s_%d",
type_name, dirs[direction], (int)(vcc * 10));
cp_getvar(buff, CP_LIST, &cvar, sizeof cvar);
}
if (!format && cvar) {
struct variable *v1, *v2, *v3;
v1 = cvar->va_vlist;
if (v1 && v1->va_type == CP_STRING) {
v2 = v1->va_next;
if (v2->va_type == CP_STRING &&
v2->va_string && v2->va_string[0]) {
format = copy(v2->va_string);
setup = copy(v1->va_string);
v3 = v2->va_next;
if (v3 && v3->va_type == CP_NUM)
max = v3->va_num;
} else {
cvar = NULL;
}
} else {
cvar = NULL;
}
}
/* Last and probably most common case, default digital bridges. */
if (!format && event_node->udn_index == 0) {
if (direction == MIF_INOUT) {
return NULL; // Abandon hope, for now.
} else {
if (direction == MIF_IN) {
snprintf(buff, sizeof buff,
".model auto_adc adc_bridge(in_low = %g in_high = %g)",
vcc/2.0, vcc/2.0);
format = copy("auto_adc%d [ %s ] [ %s ] auto_adc");
} else { // MIF_OUT
#if 0
snprintf(buff, sizeof buff, ".include test_sub.cir");
format = copy("xauto_buf%d %s %s auto_buf vcc=%g");
max = 1;
#else
snprintf(buff, sizeof buff,
".model auto_dac dac_bridge"
"(out_low = 0 out_high = %g)",
vcc);
format = copy("auto_dac%d [ %s ] [ %s ] auto_dac");
#endif
}
setup = copy(buff);
}
}
if (!format)
return NULL;
/* Make a new bridge structure. */
bridge = TMALLOC(struct bridge, 1);
bridge->udn_index = event_node->udn_index;
bridge->direction = direction;
bridge->vcc = vcc;
bridge->family = family;
bridge->next = *bridge_list_p;
*bridge_list_p = bridge;
bridge->max = max;
bridge->count = 0;
bridge->setup = setup;
bridge->format = format;
bridge->end_index = 0;
return bridge;
}
/* Early detection of node type clashes and attempted fix by
* automatic insertion of a bridging device.
*/
bool Evtcheck_nodes(
CKTcircuit *ckt, /* The circuit structure */
INPtables *stab) /* Symbol table. */
{
struct bridge *bridge_list = NULL, *bridge;
CKTnode *analog_node;
Evt_Node_Info_t *event_node;
struct card *head = NULL, *lastcard = NULL, *card;
int ln = 0, do_expand = 0, show;
/* Is auto-bridge enabled? */
if (!cp_getvar("auto_bridge", CP_NUM, &show, sizeof show))
show = AB_SILENT;
/* Try to create joining device if any analog node name matches
* an event node. Failure is fatal.
*/
for (event_node = ckt->evt->info.node_list;
event_node;
event_node = event_node->next) {
for (analog_node = ckt->CKTnodes;
analog_node;
analog_node = analog_node->next) {
int nl;
if (strcmp(event_node->name, analog_node->name) == 0) {
if (show == AB_OFF)
return FALSE; // Auto-bridge disabled
bridge = find_bridge(event_node, ckt, &bridge_list);
if (!bridge) {
/* Fatal, circuit cannot run. */
errMsg = tprintf("Can not insert bridge for mixed-type "
"node %s\n",
analog_node->name);
free_bridges(bridge_list);
if (head)
line_free(head, TRUE);
return FALSE;
}
if (bridge->setup) {
/* Model/include card for bridge.
* bridge->setup must be dynamic (for tfree()).
*/
if (!strncmp(".inc", bridge->setup, 4))
do_expand = 1;
card = insert_new_line(lastcard, bridge->setup,
BIG + ln++, 0);
if (!lastcard)
head = card;
lastcard = card;
bridge->setup = NULL; // Output just once.
}
/* Card buffer full? */
nl = (int)strlen(analog_node->name);
if ((bridge->max && bridge->count >= bridge->max) ||
bridge->end_index + nl + 2 > (int)(sizeof bridge->held)) {
/* Buffer full, flush card. */
card = flush_card(bridge, ln++, lastcard);
if (!lastcard)
head = card;
lastcard = card;
}
/* Copy node name to card contents buffer. */
bridge->count++;
if (bridge->end_index)
bridge->held[bridge->end_index++] = ' ';
strcpy(bridge->held + bridge->end_index, analog_node->name);
bridge->end_index += nl;
}
}
}
/* Flush cards. */
for (bridge = bridge_list; bridge; bridge = bridge->next) {
if (bridge->end_index > 0) {
card = flush_card(bridge, ln++, lastcard);
if (!lastcard)
head = card;
lastcard = card;
}
}
if (!lastcard)
return TRUE; // No success, but also no failures - nothing to bridge.
if (show >= AB_DECK) {
for (card = head; card; card = card->nextcard)
printf("%d: %s\n", card->linenum, card->line);
}
/* If there are any .include cards, expand them. */
if (do_expand) {
head = expand_deck(head);
if (!head)
return FALSE;
}
/* Push the cards into the circuit. */
INPpas1(ckt, head, stab);
INPpas2(ckt, head, stab, ft_curckt->ci_defTask);
/* Store them so that they show in "listing e". */
ft_curckt->ci_auto = head;
free_bridges(bridge_list);
return TRUE;
}

View File

@ -48,8 +48,6 @@ NON-STANDARD FEATURES
#include "ngspice/evtproto.h"
static int EVTcheck_nodes(CKTcircuit *ckt);
static int EVTcount_hybrids(CKTcircuit *ckt);
static int EVTinit_info(CKTcircuit *ckt);
static int EVTinit_queue(CKTcircuit *ckt);
@ -87,9 +85,6 @@ int EVTinit(
int err; /* SPICE error return code 0 = OK */
/* static char *err_no_hybrids = "ERROR - no hybrids found in input deck";*/
/* Exit immediately if there are no event-driven instances */
/* but don't complain */
if(ckt->evt->counts.num_insts == 0)
@ -100,20 +95,6 @@ int EVTinit(
if(err)
return(err);
/* Exit with error if there are no hybrids in the circuit. */
/* Will probably remove this restriction later... */
/*
if(ckt->evt->counts.num_hybrids == 0) {
errMsg = TMALLOC(char, strlen(err_no_hybrids) + 1);
strcpy(errMsg, err_no_hybrids);
return(E_PRIVATE);
}
*/
/* Check that event nodes have not been used as analog nodes also */
err = EVTcheck_nodes(ckt);
if(err)
return(err);
/* Create info table arrays */
err = EVTinit_info(ckt);
if(err)
@ -193,46 +174,6 @@ static int EVTcount_hybrids(
}
/*
EVTcheck_nodes
Report error if any event node name is also used as an analog node.
*/
static int EVTcheck_nodes(
CKTcircuit *ckt) /* The circuit structure */
{
CKTnode *analog_node;
Evt_Node_Info_t *event_node;
static char *err_prefix = "ERROR - node ";
static char *err_collide = " cannot be both analog and digital";
/* Report error if any analog node name matches any event node name */
event_node = ckt->evt->info.node_list;
while(event_node) {
analog_node = ckt->CKTnodes;
while(analog_node) {
if(strcmp(event_node->name, analog_node->name) == 0) {
errMsg = tprintf("%s%s%s", err_prefix,
event_node->name,
err_collide);
fprintf(stdout, "%s\n", errMsg);
return(E_PRIVATE);
}
analog_node = analog_node->next;
}
event_node = event_node->next;
}
/* Return */
return(OK);
}
/*
EVTinit_info