void EVTcall_hybrids( CKTcircuit *ckt) /* the main circuit structure */ { int i; int num_hybrids; int *hybrid_index; /* Get needed data for fast access */ num_hybrids = ckt->evt->counts.num_hybrids; hybrid_index = ckt->evt->info.hybrid_index; /* Call EVTload for all hybrids */ for(i = 0; i < num_hybrids; i++) EVTload(ckt, hybrid_index[i]); }
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 = TMALLOC(char, 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", NULL); return(E_ITERLIM); }