diff --git a/src/sharedspice.c b/src/sharedspice.c index 65661e18f..57ca15548 100644 --- a/src/sharedspice.c +++ b/src/sharedspice.c @@ -231,6 +231,7 @@ static bool immediate = FALSE; static bool coquit = FALSE; static jmp_buf errbufm, errbufc; static int intermj = 1; +bool wantevtdata = FALSE; // thread IDs @@ -968,6 +969,8 @@ bool ngSpice_SetBkpt(double time) IMPEXP int ngSpice_Init_Evt(SendEvtData* sevtdata, SendInitEvtData* sinitevtdata, void* userData) { + if (sevtdata) + wantevtdata = TRUE; } /* Get info about the event node vector. @@ -1933,3 +1936,7 @@ sharedsync(double *pckttime, double *pcktdelta, double olddelta, double finalt, } } } + +void shared_send_event(int index, double step, double dvalue, char *svalue, void *pvalue, int len) +{} + diff --git a/src/xspice/evt/evtdump.c b/src/xspice/evt/evtdump.c index b271e3131..4a7e521ba 100644 --- a/src/xspice/evt/evtdump.c +++ b/src/xspice/evt/evtdump.c @@ -55,7 +55,22 @@ NON-STANDARD FEATURES #include "ngspice/ipctiein.h" #include "ngspice/ipcproto.h" +#ifdef SHARED_MODULE +/* global flag, TRUE if callback is used */ +extern bool wantevtdata; +extern void shared_send_event(int, double, double, char *, void *, int); +static void EVTshareddump( + CKTcircuit *ckt, /* The circuit structure */ + Ipc_Anal_t mode, /* The analysis mode for this call */ + double step); /* The sweep step for a DCTRCURVE analysis, or */ + /* 0.0 for DCOP and TRAN */ +static void EVTsharedsend_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 */ +#endif static void EVTsend_line( int ipc_index, /* The index used in the dictionary */ @@ -136,11 +151,18 @@ void EVTdump( Mif_Boolean_t equal; - +#ifdef SHARED_MODULE + if((! g_ipc.enabled) && (!wantevtdata)) + return; + if ((!g_ipc.enabled) && (wantevtdata)) { + EVTshareddump(ckt, mode, step); + return; + } +#else /* Return immediately if IPC is not enabled */ if(! g_ipc.enabled) return; - +#endif /* Get number of event-driven nodes */ num_nodes = ckt->evt->counts.num_nodes; @@ -345,3 +367,241 @@ static void EVTsend_line( /* Send it to the IPC channel */ ipc_send_event(ipc_index, step, dvalue, svalue, pvalue, len); } + + +#ifdef SHARED_MODULE +static void EVTshareddump( + CKTcircuit *ckt, /* The circuit structure */ + Ipc_Anal_t mode, /* The analysis mode for this call */ + double step) /* The sweep step for a DCTRCURVE analysis, or */ + /* 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; + + /* 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; + } + +} + +/* +EVTsharedsend_line + +This function formats the event node data and sends it to the caller via sharedspice.c. +*/ + + +static void EVTsharedsend_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 */ + shared_send_event(ipc_index, step, dvalue, svalue, pvalue, len); +} + + +#endif