📄 evtdump.c
字号:
/*============================================================================FILE EVTdump.cMEMBER OF process XSPICECopyright 1991Georgia Tech Research CorporationAtlanta, Georgia 30332All Rights ReservedPROJECT A-8503AUTHORS 6/15/92 Bill KuhnMODIFICATIONS <date> <person name> <nature of modifications>SUMMARY This file contains functions used to send event-driven node results data to the IPC channel when the simulator is used with CAE software.INTERFACES EVTdump()REFERENCED FILES None.NON-STANDARD FEATURES None.============================================================================*/#include <stdio.h>#include <string.h>#include "ngspice.h"//#include "misc.h"#include "cktdefs.h"//#include "util.h"#include "sperror.h"#include "mif.h"#include "evt.h"#include "evtproto.h"#include "evtudn.h"#include "ipc.h"#include "ipctiein.h"#include "ipcproto.h"static void EVTsend_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 *//*EVTdumpThis function is called to send event-driven node data to the IPCchannel. A ``mode'' argument determines how the data is located inthe event data structure and what data is sent.If the mode is DCOP, then this is necessarily the first call tothe function. In this case, the set of event-driven nodes isscanned to determine which should be sent. Only nodes that arenot inside subcircuits are sent. Next, the function sendsa ``dictionary'' of node names/types vs. node indexes.Finally, the function sends the DC operating point solutionsfor the event-driven nodes in the dictionary.If the mode is DCTRCURVE, it is assumed that the function hasalready been called with mode = DCOP. The function scans the solutionvector and sends data for any nodes that have changed.If the mode is TRAN, it is assumed that the function has alreadybeen called once with mode = DCOP. The function scans theevent data for nodes that have changed since the last acceptedanalog timepoint and sends the new data.Note: This function must be called BEFORE calling EVTop_save orEVTaccept() so that the state of the node data structure will allowit to determine what has changed.*/typedef struct evtdump_s { Mif_Boolean_t send; /* True if this node should be sent */ int ipc_index; /* Index for this node in dict sent to CAE system */ char *node_name_str; /* Node name */ char *udn_type_str; /* UDN type */} evtdump_dict_t;void EVTdump( 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; /* Return immediately if IPC is not enabled */ if(! g_ipc.enabled) return; /* 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 = (void *) MALLOC(num_nodes * sizeof(evtdump_dict_t)); /* 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 = 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)) { 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; }}/*EVTsend_lineThis function formats the event node data and sends it to the IPC channel.*/static void EVTsend_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 */ ipc_send_event(ipc_index, step, dvalue, svalue, pvalue, len);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -