📄 evtiter.c
字号:
/*============================================================================FILE EVTiter.cMEMBER OF process XSPICECopyright 1991Georgia Tech Research CorporationAtlanta, Georgia 30332All Rights ReservedPROJECT A-8503AUTHORS 9/12/91 Bill KuhnMODIFICATIONS <date> <person name> <nature of modifications>SUMMARY This file contains function EVTiter which iterates through event-driven outputs and instances until the outputs no longer change.INTERFACES int EVTiter(CKTcircuit *ckt)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 "evtudn.h"#include "evtproto.h"/*EVTiterThis function iterates through event-driven outputs and instancesuntil the outputs no longer change. The general algorithm usedis:Do: Scan list of changed outputs Put items on the node queue 'to_eval' list for each changed output. Scan list of changed nodes Resolve nodes with multiple outputs posted. Create inverted state for nodes with attached inverted inputs. Put items on the instance queue 'to_call' list for each changed node. If transient analysis, put state of the node into the node data structure. Scan instance to_call list Call EVTload for each instance on list.While there are changed outputs*/int EVTiter( CKTcircuit *ckt) /* the circuit structure */{ int i; int num_changed; int num_to_eval; int num_to_call; int output_index; /* int output_subindex;*/ int inst_index; int node_index; int port_index; int num_outputs; int udn_index; int passes; Evt_Ckt_Data_t *evt; Evt_Output_Queue_t *output_queue; Evt_Node_Queue_t *node_queue; Evt_Inst_Queue_t *inst_queue; Evt_Output_Info_t **output_table; Evt_Node_Info_t **node_table; Evt_Port_Info_t **port_table; Evt_Inst_Index_t *inst_list; Evt_Node_Data_t *node_data; Evt_Node_t *rhs; Evt_Node_t *rhsold; Evt_Node_t *node; Mif_Boolean_t equal; char *err_msg; /* Get temporary pointers for fast access */ evt = ckt->evt; output_queue = &(evt->queue.output); node_queue = &(evt->queue.node); inst_queue = &(evt->queue.inst); output_table = evt->info.output_table; node_table = evt->info.node_table; port_table = evt->info.port_table; node_data = evt->data.node; rhs = node_data->rhs; rhsold = node_data->rhsold; /* Loop until no more output change, or too many passes through loop */ for(passes = 0; passes < evt->limits.max_event_passes; passes++) { /* Create list of nodes to evaluate from list of changed outputs */ num_changed = output_queue->num_changed; for(i = 0; i < num_changed; i++) { /* Get index of node that output is connected to */ output_index = output_queue->changed_index[i]; node_index = output_table[output_index]->node_index; /* If not already on list of nodes to evaluate, add it */ if(! node_queue->to_eval[node_index]) { node_queue->to_eval[node_index] = MIF_TRUE; node_queue->to_eval_index[(node_queue->num_to_eval)++] = node_index; } /* Reset the changed flag on the output queue */ output_queue->changed[output_index] = MIF_FALSE; } output_queue->num_changed = 0; /* Evaluate nodes and for any which have changed, enter */ /* the instances that receive inputs from them on the list */ /* of instances to call */ num_to_eval = node_queue->num_to_eval; for(i = 0; i < num_to_eval; i++) { /* Get the node index, udn index and number of outputs */ node_index = node_queue->to_eval_index[i]; udn_index = node_table[node_index]->udn_index; num_outputs = node_table[node_index]->num_outputs; /* Resolve the node value if multiple outputs on it */ /* and test if new node value is different than old value */ if(num_outputs > 1) { (*(g_evt_udn_info[udn_index]->resolve)) (num_outputs, rhs[node_index].output_value, rhs[node_index].node_value); (*(g_evt_udn_info[udn_index]->compare)) (rhs[node_index].node_value, rhsold[node_index].node_value, &equal); if(! equal) { (*(g_evt_udn_info[udn_index]->copy)) (rhs[node_index].node_value, rhsold[node_index].node_value); } } /* Else, load function has already determined that they were */ /* not equal */ else equal = MIF_FALSE; /* If not equal, make inverted copy in rhsold if */ /* needed, and place indexes of instances with inputs connected */ /* to the node in the to_call list of inst queue */ if(! equal) { if(node_table[node_index]->invert) { (*(g_evt_udn_info[udn_index]->copy)) (rhsold[node_index].node_value, rhsold[node_index].inverted_value); (*(g_evt_udn_info[udn_index]->invert)) (rhsold[node_index].inverted_value); } inst_list = node_table[node_index]->inst_list; while(inst_list) { inst_index = inst_list->index; if(! inst_queue->to_call[inst_index]) { inst_queue->to_call[inst_index] = MIF_TRUE; inst_queue->to_call_index[(inst_queue->num_to_call)++] = inst_index; } inst_list = inst_list->next; } /* end while instances with inputs on node */ } /* end if not equal */ /* If transient analysis mode */ /* Save the node data onto the node results list and mark */ /* that it has been modified, even if the */ /* resolved node value has not changed */ if(g_mif_info.circuit.anal_type == MIF_TRAN) { node = *(node_data->tail[node_index]); node_data->tail[node_index] = &(node->next); EVTnode_copy(ckt, node_index, &(rhsold[node_index]), &(node->next)); node->next->step = g_mif_info.circuit.evt_step; if(! node_data->modified[node_index]) { node_data->modified[node_index] = MIF_TRUE; node_data->modified_index[(node_data->num_modified)++] = node_index; } } /* Reset the to_eval flag on the node queue */ node_queue->to_eval[node_index] = MIF_FALSE; } /* end for number of nodes to evaluate */ node_queue->num_to_eval = 0; /* Call the instances with inputs on nodes that have changed */ num_to_call = inst_queue->num_to_call; for(i = 0; i < num_to_call; i++) { inst_index = inst_queue->to_call_index[i]; inst_queue->to_call[inst_index] = MIF_FALSE; EVTload(ckt, inst_index); } inst_queue->num_to_call = 0; /* Record statistics */ if(g_mif_info.circuit.anal_type == MIF_DC) (ckt->evt->data.statistics->op_event_passes)++; /* If no outputs changed, iteration is over, so return with success! */ if(output_queue->num_changed == 0) return(0); } /* end for */ /* Too many passes through loop, report problems and exit with error */ err_msg = MALLOC(10000); for(i = 0; i < output_queue->num_changed; i++) { output_index = output_queue->changed_index[i]; port_index = output_table[output_index]->port_index; sprintf(err_msg, "\n Instance: %s\n Connection: %s\n Port: %d", port_table[port_index]->inst_name, port_table[port_index]->conn_name, port_table[port_index]->port_num); ENHreport_conv_prob(ENH_EVENT_NODE, port_table[port_index]->node_name, err_msg); } FREE(err_msg); (*(SPfrontEnd->IFerror)) (ERR_WARNING, "Too many iteration passes in event-driven circuits", (IFuid *) NULL); return(E_ITERLIM);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -