Add two new XSPICE functions: EVTnew_value_call() and
EVTcancel_value_call(). EVTnew_value_call() specifies a function to be called for each confirmed new value produced on an XSPICE event node. To be used to add event node support for iplot.
This commit is contained in:
parent
f4963b1ada
commit
33f206b916
|
|
@ -78,6 +78,14 @@ struct Evt_Inst_Index {
|
|||
int index; /* the value of the index */
|
||||
};
|
||||
|
||||
struct Evt_Node_Cb {
|
||||
struct Evt_Node_Cb *next;
|
||||
Evt_New_Value_Cb_t fn; /* Function to be called. */
|
||||
Evt_Node_Cb_Type_t type; /* Data type to pass to fn. */
|
||||
const char *member; /* For event data type's plot fn. */
|
||||
void *ctx;
|
||||
};
|
||||
|
||||
struct Evt_Node_Info {
|
||||
Evt_Node_Info_t *next; /* the next in the linked list */
|
||||
char *name; /* Name of node in deck */
|
||||
|
|
@ -88,6 +96,7 @@ struct Evt_Node_Info {
|
|||
int num_outputs; /* Number of outputs connected to this node */
|
||||
int num_insts; /* The number of insts receiving node as input */
|
||||
Evt_Inst_Index_t *inst_list; /* Linked list of indexes of these instances */
|
||||
Evt_Node_Cb_t *cbs; /* New value callbacks. */
|
||||
};
|
||||
|
||||
struct Evt_Inst_Info {
|
||||
|
|
@ -195,8 +204,6 @@ struct Evt_Queue {
|
|||
/* ************** */
|
||||
|
||||
|
||||
|
||||
|
||||
struct Evt_Node {
|
||||
Evt_Node_t *next; /* pointer to next in linked list */
|
||||
Mif_Boolean_t op; /* true if computed from op analysis */
|
||||
|
|
@ -204,6 +211,7 @@ struct Evt_Node {
|
|||
void **output_value; /* Array of outputs posted to this node */
|
||||
void *node_value; /* Resultant computed from output values */
|
||||
void *inverted_value; /* Inverted copy of node_value */
|
||||
|
||||
};
|
||||
|
||||
struct Evt_Node_Data {
|
||||
|
|
@ -362,6 +370,4 @@ struct Evt_Ckt_Data {
|
|||
Evt_Option_t options; /* Data input on .options cards */
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -136,6 +136,28 @@ bool Evtcheck_nodes(
|
|||
struct INPtables *stab); /* Symbol table. */
|
||||
|
||||
struct dvec *EVTfindvec(char *node);
|
||||
|
||||
/* Set and remove call-backs on new node values. */
|
||||
|
||||
Mif_Boolean_t EVTnew_value_call(const char *node,
|
||||
Evt_New_Value_Cb_t fn,
|
||||
Evt_Node_Cb_Type_t type,
|
||||
void *ctx);
|
||||
|
||||
void EVTcancel_value_call(const char *node,
|
||||
Evt_New_Value_Cb_t fn,
|
||||
void *ctx);
|
||||
|
||||
/* Internal utility functions. */
|
||||
|
||||
void Evt_purge_free_outputs(void);
|
||||
|
||||
/* Parse a node name with member and find the node index. */
|
||||
|
||||
struct node_parse {
|
||||
char *node;
|
||||
char *member;
|
||||
};
|
||||
|
||||
int Evt_Parse_Node(const char *node, struct node_parse *result);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef ngspice_EVTTYPES_H
|
||||
#define ngspice_EVTTYPES_H
|
||||
|
||||
#include "miftypes.h"
|
||||
|
||||
typedef struct Evt_Output_Info Evt_Output_Info_t;
|
||||
typedef struct Evt_Port_Info Evt_Port_Info_t;
|
||||
|
|
@ -28,6 +28,11 @@ typedef struct Evt_Limit Evt_Limit_t;
|
|||
typedef struct Evt_Job Evt_Job_t;
|
||||
typedef struct Evt_Option Evt_Option_t;
|
||||
typedef struct Evt_Ckt_Data Evt_Ckt_Data_t;
|
||||
typedef struct Evt_Node_Cb Evt_Node_Cb_t;
|
||||
|
||||
typedef Mif_Boolean_t (*Evt_New_Value_Cb_t)(double when, Mif_Value_t *val_p,
|
||||
void *ctx, int is_last);
|
||||
|
||||
typedef enum Evt_Node_Cb_Type { Evt_Cbt_Raw, Evt_Cbt_Plot} Evt_Node_Cb_Type_t;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ NON-STANDARD FEATURES
|
|||
|
||||
#include "ngspice/mif.h"
|
||||
#include "ngspice/evt.h"
|
||||
#include "ngspice/evtudn.h"
|
||||
#include "ngspice/evtproto.h"
|
||||
|
||||
|
||||
|
|
@ -160,18 +161,62 @@ void EVTaccept(
|
|||
num_modified = node_data->num_modified;
|
||||
/* Loop through list of items modified since last time */
|
||||
for(i = 0; i < num_modified; i++) {
|
||||
Evt_Node_t *this;
|
||||
Evt_Node_Info_t *node_info;
|
||||
Evt_Node_Cb_t *cb, **cbpp;
|
||||
int udn_index;
|
||||
|
||||
/* Get the index of the node modified */
|
||||
index = node_data->modified_index[i];
|
||||
/* Reset the modified flag */
|
||||
node_data->modified[index] = MIF_FALSE;
|
||||
|
||||
/* Call any value-change functions registered for this node. */
|
||||
|
||||
node_info = node_table[index];
|
||||
udn_index = node_info->udn_index;
|
||||
|
||||
cbpp = &node_info->cbs;
|
||||
for (;;) {
|
||||
Mif_Value_t val;
|
||||
|
||||
cb = *cbpp;
|
||||
if (cb == NULL)
|
||||
break;
|
||||
|
||||
for (this = *node_data->last_step[index];
|
||||
this;
|
||||
this = this->next) {
|
||||
switch (cb->type) {
|
||||
case Evt_Cbt_Raw:
|
||||
val.pvalue = this->node_value;
|
||||
break;
|
||||
case Evt_Cbt_Plot:
|
||||
g_evt_udn_info[udn_index]->plot_val(this->node_value,
|
||||
(char *)cb->member,
|
||||
&val.rvalue);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((*cb->fn)(this->step, &val, cb->ctx, !this->next)) {
|
||||
/* Remove callback from chain. */
|
||||
|
||||
*cbpp = cb->next;
|
||||
txfree(cb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this == NULL) // Normal loop exit.
|
||||
cbpp = &cb->next;
|
||||
}
|
||||
|
||||
/* Optionally store node values for later examination.
|
||||
* The test of CKTtime here is copied from dctran.c.
|
||||
* CKTinitTime is from the tstart parameter of the "tran"
|
||||
* command or card.
|
||||
*/
|
||||
|
||||
if (node_table[index]->save && ckt->CKTtime >= ckt->CKTinitTime &&
|
||||
if (node_info->save && ckt->CKTtime >= ckt->CKTinitTime &&
|
||||
(ckt->CKTtime > 0 || !(ckt->CKTmode & MODEUIC))) {
|
||||
/* Update last_step for this index */
|
||||
node_data->last_step[index] = node_data->tail[index];
|
||||
|
|
@ -239,3 +284,77 @@ void EVTaccept(
|
|||
} /* EVTaccept */
|
||||
|
||||
|
||||
/* Functions to set-up and cancel value-changed callbacks. */
|
||||
|
||||
Mif_Boolean_t EVTnew_value_call(const char *node,
|
||||
Evt_New_Value_Cb_t fn,
|
||||
Evt_Node_Cb_Type_t type,
|
||||
void *ctx)
|
||||
{
|
||||
struct node_parse result;
|
||||
int index;
|
||||
|
||||
Evt_Ckt_Data_t *evt;
|
||||
CKTcircuit *ckt;
|
||||
Evt_Node_Info_t *node_info;
|
||||
Evt_Node_Cb_t *cb;
|
||||
|
||||
index = Evt_Parse_Node(node, &result);
|
||||
if (index < 0)
|
||||
return MIF_FALSE;
|
||||
ckt = g_mif_info.ckt;
|
||||
evt = ckt->evt;
|
||||
node_info = evt->info.node_table[index];
|
||||
cb = tmalloc(sizeof *cb);
|
||||
cb->next = node_info->cbs;
|
||||
node_info->cbs = cb;
|
||||
cb->fn = fn;
|
||||
cb->type = type;
|
||||
cb->member = copy(result.member);
|
||||
cb->ctx = ctx;
|
||||
txfree(result.node);
|
||||
return MIF_TRUE;
|
||||
}
|
||||
|
||||
void EVTcancel_value_call(const char *node,
|
||||
Evt_New_Value_Cb_t fn,
|
||||
void *ctx)
|
||||
{
|
||||
Evt_Ckt_Data_t *evt;
|
||||
CKTcircuit *ckt;
|
||||
Evt_Node_Info_t **node_table, *node_info;
|
||||
Evt_Node_Cb_t **cbpp, *cb;
|
||||
int i, num_nodes;
|
||||
|
||||
ckt = g_mif_info.ckt;
|
||||
if (!ckt)
|
||||
return;
|
||||
evt = ckt->evt;
|
||||
if (!evt)
|
||||
return;
|
||||
|
||||
/* Look for node name in the event-driven node list */
|
||||
|
||||
node_table = evt->info.node_table;
|
||||
num_nodes = evt->counts.num_nodes;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (cieq(node, node_table[i]->name))
|
||||
break;
|
||||
}
|
||||
if (i >= num_nodes)
|
||||
return;
|
||||
|
||||
node_info = node_table[i];
|
||||
cbpp = &node_info->cbs;
|
||||
cb = node_info->cbs;
|
||||
while (cb) {
|
||||
if (cb->fn == fn && cb->ctx == ctx) {
|
||||
*cbpp = cb->next;
|
||||
tfree(cb);
|
||||
} else {
|
||||
cbpp = &cb->next;
|
||||
}
|
||||
cb = *cbpp;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,10 +167,12 @@ Evt_Node_Data_destroy(Evt_Ckt_Data_t *evt, Evt_Node_Data_t *node_data)
|
|||
|
||||
for (i = 0; i < evt->counts.num_nodes; i++) {
|
||||
Evt_Node_Info_t *info = evt->info.node_table[i];
|
||||
Evt_Node_t *node;
|
||||
Evt_Node_t *node;
|
||||
|
||||
node = node_data->head[i];
|
||||
while (node) {
|
||||
Evt_Node_t *next = node->next;
|
||||
|
||||
Evt_Node_destroy(info, node);
|
||||
tfree(node);
|
||||
node = next;
|
||||
|
|
@ -178,6 +180,7 @@ Evt_Node_Data_destroy(Evt_Ckt_Data_t *evt, Evt_Node_Data_t *node_data)
|
|||
node = node_data->free[i];
|
||||
while (node) {
|
||||
Evt_Node_t *next = node->next;
|
||||
|
||||
Evt_Node_destroy(info, node);
|
||||
tfree(node);
|
||||
node = next;
|
||||
|
|
@ -193,6 +196,7 @@ Evt_Node_Data_destroy(Evt_Ckt_Data_t *evt, Evt_Node_Data_t *node_data)
|
|||
|
||||
for (i = 0; i < evt->counts.num_nodes; i++) {
|
||||
Evt_Node_Info_t *info = evt->info.node_table[i];
|
||||
|
||||
Evt_Node_destroy(info, &(node_data->rhs[i]));
|
||||
Evt_Node_destroy(info, &(node_data->rhsold[i]));
|
||||
}
|
||||
|
|
@ -287,6 +291,7 @@ static void
|
|||
Evt_Info_destroy(Evt_Info_t *info)
|
||||
{
|
||||
Evt_Inst_Info_t *inst = info->inst_list;
|
||||
|
||||
while (inst) {
|
||||
Evt_Inst_Info_t *next_inst = inst->next;
|
||||
tfree(inst);
|
||||
|
|
@ -295,14 +300,24 @@ Evt_Info_destroy(Evt_Info_t *info)
|
|||
tfree(info->inst_table);
|
||||
|
||||
Evt_Node_Info_t *nodei = info->node_list;
|
||||
|
||||
while (nodei) {
|
||||
Evt_Node_Info_t *next_nodei = nodei->next;
|
||||
Evt_Node_Cb_t *cb, *cb_next;
|
||||
|
||||
tfree(nodei->name);
|
||||
for (cb = nodei->cbs; cb; cb = cb_next) {
|
||||
cb_next = cb->next;
|
||||
if (cb->member)
|
||||
txfree(cb->member);
|
||||
tfree(cb);
|
||||
}
|
||||
|
||||
Evt_Inst_Index_t *p = nodei->inst_list;
|
||||
|
||||
while (p) {
|
||||
Evt_Inst_Index_t *next_p = p->next;
|
||||
tfree(p);
|
||||
txfree(p);
|
||||
p = next_p;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,15 +45,78 @@ NON-STANDARD FEATURES
|
|||
#include "ngspice/mif.h"
|
||||
#include "ngspice/mifproto.h"
|
||||
|
||||
/*saj for output */
|
||||
#include "ngspice/sim.h"
|
||||
#include "ngspice/dvec.h"
|
||||
//#include "ftedata.h"
|
||||
//#include "fteconstant.h"
|
||||
//#include "util.h"
|
||||
#include "ngspice/cpstd.h"
|
||||
|
||||
|
||||
/* Parse member qualifier from node name and find node index.
|
||||
* The node name may be qualified by a member name for nodes with
|
||||
* composite values such as Digital_t, as in "node_name(state)".
|
||||
*/
|
||||
|
||||
int Evt_Parse_Node(const char *node, struct node_parse *result)
|
||||
{
|
||||
Evt_Ckt_Data_t *evt;
|
||||
CKTcircuit *ckt;
|
||||
Evt_Node_Info_t **node_table;
|
||||
char *name, *ptr;
|
||||
int i, num_nodes;
|
||||
|
||||
ckt = g_mif_info.ckt;
|
||||
if (!ckt)
|
||||
return -1;
|
||||
evt = ckt->evt;
|
||||
if (!evt)
|
||||
return -1;
|
||||
if (!evt->info.node_table)
|
||||
return -1;
|
||||
if (evt->counts.num_nodes == 0)
|
||||
return -1;
|
||||
|
||||
/* Make a copy of the node name. Do not free this string. */
|
||||
|
||||
name = MIFcopy((char *)node);
|
||||
|
||||
/* Convert to all lower case */
|
||||
|
||||
strtolower(name);
|
||||
|
||||
/* Divide into the node name and member name */
|
||||
|
||||
result->node = name;
|
||||
for (ptr = name; *ptr != '\0'; ptr++)
|
||||
if (*ptr == '(')
|
||||
break;
|
||||
|
||||
if (*ptr == '(') {
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
result->member = ptr;
|
||||
for( ; *ptr != '\0'; ptr++)
|
||||
if (*ptr == ')')
|
||||
break;
|
||||
*ptr = '\0';
|
||||
} else {
|
||||
result->member = NULL;
|
||||
}
|
||||
|
||||
/* Look for node name in the event-driven node list */
|
||||
|
||||
node_table = evt->info.node_table;
|
||||
num_nodes = evt->counts.num_nodes;
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
if (cieq(name, node_table[i]->name))
|
||||
break;
|
||||
}
|
||||
if (i >= num_nodes) {
|
||||
tfree(name);
|
||||
return -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
EVTfindvec()
|
||||
|
|
@ -79,21 +142,17 @@ keyword "all" is supplied to the plot_val routine for the member name.
|
|||
struct dvec *EVTfindvec(
|
||||
char *node) /* The node name (and optional member name) */
|
||||
{
|
||||
char *name;
|
||||
char *member = "all";
|
||||
char *ptr;
|
||||
char *name;
|
||||
struct node_parse result;
|
||||
int index, i;
|
||||
int udn_index;
|
||||
int num_events;
|
||||
|
||||
int i;
|
||||
int num_nodes;
|
||||
int udn_index;
|
||||
int num_events;
|
||||
|
||||
Mif_Boolean_t found;
|
||||
Evt_Ckt_Data_t *evt;
|
||||
CKTcircuit *ckt;
|
||||
Evt_Node_Info_t **node_table;
|
||||
Evt_Node_t *head;
|
||||
Evt_Node_t *event;
|
||||
Evt_Ckt_Data_t *evt;
|
||||
CKTcircuit *ckt;
|
||||
Evt_Node_Info_t *node_info;
|
||||
Evt_Node_t *head;
|
||||
Evt_Node_t *event;
|
||||
|
||||
double *anal_point_vec;
|
||||
double *value_vec;
|
||||
|
|
@ -105,67 +164,26 @@ struct dvec *EVTfindvec(
|
|||
/* Exit immediately if event-driven stuff not allocated yet, */
|
||||
/* or if number of event nodes is zero. */
|
||||
|
||||
index = Evt_Parse_Node(node, &result);
|
||||
if (index < 0)
|
||||
return NULL;
|
||||
name = result.node;
|
||||
ckt = g_mif_info.ckt;
|
||||
if(! ckt)
|
||||
return(NULL);
|
||||
evt = ckt->evt;
|
||||
if(! evt)
|
||||
return(NULL);
|
||||
if(! evt->info.node_table)
|
||||
return(NULL);
|
||||
if(evt->counts.num_nodes == 0)
|
||||
return(NULL);
|
||||
|
||||
/* Make a copy of the node name. */
|
||||
/* Do not free this string. It is assigned into the dvec structure below. */
|
||||
name = MIFcopy(node);
|
||||
|
||||
/* Convert to all lower case */
|
||||
strtolower(name);
|
||||
|
||||
/* Divide into the node name and member name */
|
||||
for(ptr = name; *ptr != '\0'; ptr++)
|
||||
if(*ptr == '(')
|
||||
break;
|
||||
|
||||
if(*ptr == '(') {
|
||||
*ptr = '\0';
|
||||
ptr++;
|
||||
member = ptr;
|
||||
for( ; *ptr != '\0'; ptr++)
|
||||
if(*ptr == ')')
|
||||
break;
|
||||
*ptr = '\0';
|
||||
}
|
||||
|
||||
/* Look for node name in the event-driven node list */
|
||||
num_nodes = evt->counts.num_nodes;
|
||||
node_table = evt->info.node_table;
|
||||
|
||||
for(i = 0, found = MIF_FALSE; i < num_nodes; i++) {
|
||||
if(cieq(name, node_table[i]->name)) {
|
||||
found = MIF_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(! found) {
|
||||
if (!evt->data.node) {
|
||||
tfree(name);
|
||||
return(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the UDN type index */
|
||||
udn_index = node_table[i]->udn_index;
|
||||
|
||||
if (!evt->data.node) {
|
||||
// fprintf(stderr, "Warning: No event data available! \n Simulation not yet run?\n");
|
||||
tfree(name);
|
||||
return(NULL);
|
||||
}
|
||||
node_info = evt->info.node_table[index];
|
||||
udn_index = node_info->udn_index;
|
||||
|
||||
/* Count the number of events */
|
||||
head = evt->data.node->head[i];
|
||||
|
||||
head = evt->data.node->head[index];
|
||||
for(event = head, num_events = 0; event; event = event->next)
|
||||
num_events++;
|
||||
|
||||
|
|
@ -187,9 +205,9 @@ struct dvec *EVTfindvec(
|
|||
|
||||
/* Get the next value by calling the appropriate UDN plot_val function */
|
||||
value = 0.0;
|
||||
g_evt_udn_info[udn_index]->plot_val (event->node_value,
|
||||
member,
|
||||
&value);
|
||||
g_evt_udn_info[udn_index]->plot_val(event->node_value,
|
||||
result.member ? result.member : "all",
|
||||
&value);
|
||||
|
||||
/* Put the first value of the horizontal line in the vector */
|
||||
anal_point_vec[i] = event->step;
|
||||
|
|
@ -206,8 +224,7 @@ struct dvec *EVTfindvec(
|
|||
/* Allocate dvec structures and assign the vectors into them. */
|
||||
/* See FTE/OUTinterface.c:plotInit() for initialization example. */
|
||||
|
||||
ptr = tprintf("%s_steps", name);
|
||||
scale = dvec_alloc(ptr,
|
||||
scale = dvec_alloc(tprintf("%s_steps", name),
|
||||
SV_TIME,
|
||||
(VF_REAL | VF_EVENT_NODE) & ~VF_PERMANENT,
|
||||
i, anal_point_vec);
|
||||
|
|
|
|||
|
|
@ -330,6 +330,7 @@ static void EVTnode_insert(
|
|||
node->name = MIFcopy(node_name);
|
||||
node->udn_index = udn_index;
|
||||
node->save = MIF_TRUE; /* Backward compatible behaviour: save all. */
|
||||
node->cbs = NULL;
|
||||
index = ckt->evt->counts.num_nodes;
|
||||
(ckt->evt->counts.num_nodes)++;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue