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); }
int MIFload( GENmodel *inModel, /* The head of the model list */ CKTcircuit *ckt) /* The circuit structure */ { MIFmodel *model; MIFinstance *here; Mif_Private_t cm_data; /* data to be passed to/from code model */ Mif_Port_Type_t type; Mif_Port_Data_t *fast; Mif_Smp_Ptr_t *smp_data_out; Mif_Port_Ptr_t *smp_ptr; Mif_Port_Type_t in_type; Mif_Port_Type_t out_type; Mif_Boolean_t is_input; Mif_Boolean_t is_output; Mif_Cntl_Src_Type_t cntl_src_type; Mif_Analysis_t anal_type; Mif_Complex_t czero; Mif_Complex_t ac_gain; int mod_type; int num_conn; int num_port; int num_port_k; int i; int j; int k; int l; /*int tag;*/ double *rhs; double *rhsOld; double partial; double temp; double *double_ptr0; double *double_ptr1; /*double *input;*/ /* double *oldinput;*/ char *byte_ptr0; char *byte_ptr1; double last_input; double conv_limit; double cntl_input; Evt_Node_Data_t *node_data; /* Prepare a zero complex number for AC gain initializations */ czero.real = 0.0; czero.imag = 0.0; /* Setup for access into MIF specific model data */ model = (MIFmodel *) inModel; mod_type = model->MIFmodType; /* Setup pointers for fast access to rhs and rhsOld elements of ckt struct */ rhs = ckt->CKTrhs; rhsOld = ckt->CKTrhsOld; node_data = ckt->evt->data.node; /* *********************************************************************** */ /* Setup the circuit data in the structure to be passed to the code models */ /* *********************************************************************** */ /* anal_init is set if this is the first iteration at any step in */ /* an analysis */ if(!(ckt->CKTmode & MODEINITFLOAT)) g_mif_info.circuit.anal_init = MIF_TRUE; cm_data.circuit.anal_init = g_mif_info.circuit.anal_init; /* anal_type is determined by CKTload */ anal_type = g_mif_info.circuit.anal_type; cm_data.circuit.anal_type = anal_type; /* get the analysis freq from the ckt struct if this is an AC analysis */ /* otherwise, set the freq to zero */ if(anal_type == MIF_AC) cm_data.circuit.frequency = ckt->CKTomega; else cm_data.circuit.frequency = 0.0; /* get the analysis times from the ckt struct if this is a transient analysis */ /* otherwise, set the times to zero */ if(anal_type == MIF_TRAN) { cm_data.circuit.time = ckt->CKTtime; cm_data.circuit.t[0] = ckt->CKTtime; for(i = 1; i < 8; i++) { cm_data.circuit.t[i] = cm_data.circuit.t[i-1] - ckt->CKTdeltaOld[i-1]; if(cm_data.circuit.t[i] < 0.0) cm_data.circuit.t[i] = 0.0; } } else { cm_data.circuit.time = 0.0; for(i = 0; i < 8; i++) { cm_data.circuit.t[i] = 0.0; } } cm_data.circuit.call_type = MIF_ANALOG; cm_data.circuit.temperature = ckt->CKTtemp - 273.15; g_mif_info.circuit.call_type = MIF_ANALOG; g_mif_info.ckt = ckt; /* ***************************************************************** */ /* loop through all models of this type */ /* ***************************************************************** */ for( ; model != NULL; model = model->MIFnextModel) { /* If not an analog or hybrid model, continue to next */ if(! model->analog) continue; /* ***************************************************************** */ /* loop through all instances of this model */ /* ***************************************************************** */ for(here = model->MIFinstances; here != NULL; here = here->MIFnextInstance) { /* If not an analog or hybrid instance, continue to next */ if(! here->analog) continue; /* ***************************************************************** */ /* Prepare the data needed by the cm_.. functions */ /* ***************************************************************** */ g_mif_info.instance = here; g_mif_info.errmsg = ""; if(here->initialized) { cm_data.circuit.init = MIF_FALSE; g_mif_info.circuit.init = MIF_FALSE; } else { cm_data.circuit.init = MIF_TRUE; g_mif_info.circuit.init = MIF_TRUE; } /* ***************************************************************** */ /* if tran analysis and anal_init is true, copy state 1 to state 0 */ /* Otherwise the data in state 0 would be invalid */ /* ***************************************************************** */ if((anal_type == MIF_TRAN) && g_mif_info.circuit.anal_init) { for(i = 0; i < here->num_state; i++) { double_ptr0 = ckt->CKTstate0 + here->state[i].index; double_ptr1 = ckt->CKTstate1 + here->state[i].index; byte_ptr0 = (char *) double_ptr0; byte_ptr1 = (char *) double_ptr1; for(j = 0; j < here->state[i].bytes; j++) byte_ptr0[j] = byte_ptr1[j]; } } /* ***************************************************************** */ /* If not AC analysis, loop through all connections on this instance */ /* and load the input values for each input port of each connection */ /* ***************************************************************** */ num_conn = here->num_conn; for(i = 0; i < num_conn; i++) { /* If AC analysis, skip getting input values. The input values */ /* should stay the same as they were at the last iteration of */ /* the operating point analysis */ if(anal_type == MIF_AC) break; /* if the connection is null, skip to next connection */ if(here->conn[i]->is_null) continue; /* if this connection is not an input, skip to next connection */ if(! here->conn[i]->is_input) continue; /* Get number of ports on this connection */ num_port = here->conn[i]->size; /* loop through all ports on this connection */ for(j = 0; j < num_port; j++) { /*setup a pointer for fast access to port data */ fast = here->conn[i]->port[j]; /* skip if this port is null */ if(fast->is_null) continue; /* determine the type of this port */ type = fast->type; /* If port type is Digital or User-Defined, we only need */ /* to get the total load. The input values are pointers */ /* already set by EVTsetup() */ if((type == MIF_DIGITAL) || (type == MIF_USER_DEFINED)) { fast->total_load = node_data->total_load[fast->evt_data.node_index]; } /* otherwise, it is an analog node and we get the input value */ else { /* load the input values based on type and mode */ if(ckt->CKTmode & MODEINITJCT) /* first iteration step for DC */ fast->input.rvalue = 0.0; else if((ckt->CKTmode & MODEINITTRAN) || (ckt->CKTmode & MODEINITPRED)) /* first iteration step at timepoint */ fast->input.rvalue = ckt->CKTstate1[fast->old_input]; else { /* subsequent iterations */ /* record last iteration's input value for convergence limiting */ last_input = fast->input.rvalue; /* get the new input value */ switch(type) { case MIF_VOLTAGE: case MIF_DIFF_VOLTAGE: case MIF_CONDUCTANCE: case MIF_DIFF_CONDUCTANCE: fast->input.rvalue = rhsOld[fast->smp_data.pos_node] - rhsOld[fast->smp_data.neg_node]; break; case MIF_CURRENT: case MIF_DIFF_CURRENT: case MIF_VSOURCE_CURRENT: case MIF_RESISTANCE: case MIF_DIFF_RESISTANCE: fast->input.rvalue = rhsOld[fast->smp_data.ibranch]; break; case MIF_DIGITAL: case MIF_USER_DEFINED: break; } /* end switch on type of port */ /* If convergence limiting enabled, limit maximum input change */ if(ckt->enh->conv_limit.enabled) { /* compute the maximum the input is allowed to change */ conv_limit = fabs(last_input) * ckt->enh->conv_limit.step; if(conv_limit < ckt->enh->conv_limit.abs_step) conv_limit = ckt->enh->conv_limit.abs_step; /* if input has changed too much, limit it and signal not converged */ if(fabs(fast->input.rvalue - last_input) > conv_limit) { if((fast->input.rvalue - last_input) > 0.0) fast->input.rvalue = last_input + conv_limit; else fast->input.rvalue = last_input - conv_limit; (ckt->CKTnoncon)++; /* report convergence problem if last call */ if(ckt->enh->conv_debug.report_conv_probs) { ENHreport_conv_prob(ENH_ANALOG_INSTANCE, here->MIFname, ""); } } } } /* end else */ /* Save value of input for use with MODEINITTRAN */ ckt->CKTstate0[fast->old_input] = fast->input.rvalue; } /* end else analog type */ } /* end for number of ports */ } /* end for number of connections */ /* ***************************************************************** */ /* loop through all connections on this instance and zero out all */ /* outputs/partials/AC gains for each output port of each connection */ /* ***************************************************************** */ num_conn = here->num_conn; for(i = 0; i < num_conn; i++) { /* if the connection is null or is not an output */ /* skip to next connection */ if(here->conn[i]->is_null || (! here->conn[i]->is_output)) continue; /* loop through all ports on this connection */ num_port = here->conn[i]->size; for(j = 0; j < num_port; j++) { /*setup a pointer for fast access to port data */ fast = here->conn[i]->port[j]; /* skip if this port is null */ if(fast->is_null) continue; /* determine the type of this port */ type = fast->type; /* If not an analog node, continue to next port */ if((type == MIF_DIGITAL) || (type == MIF_USER_DEFINED)) continue; /* initialize the output to zero */ fast->output.rvalue = 0.0; /* loop through all connections and ports that */ /* could be inputs for this port and zero the partials */ for(k = 0; k < num_conn; k++) { if(here->conn[k]->is_null || (! here->conn[k]->is_input)) continue; num_port_k = here->conn[k]->size; for(l = 0; l < num_port_k; l++) { /* skip if this port is null */ if(here->conn[k]->port[l]->is_null) continue; fast->partial[k].port[l] = 0.0; fast->ac_gain[k].port[l] = czero; } /* end for number of ports */ } /* end for number of connections */ } /* end for number of ports */ } /* end for number of connections */ /* ***************************************************************** */ /* Prepare the structure to be passed to the code model */ /* ***************************************************************** */ cm_data.num_conn = here->num_conn; cm_data.conn = here->conn; cm_data.num_param = here->num_param; cm_data.param = here->param; cm_data.num_inst_var = here->num_inst_var; cm_data.inst_var = here->inst_var; /* Initialize the auto_partial flag to false */ g_mif_info.auto_partial.local = MIF_FALSE; /* ******************* */ /* Call the code model */ /* ******************* */ DEVices[mod_type]->DEVpublic.cm_func (&cm_data); /* Automatically compute partials if requested by .options auto_partial */ /* or by model through call to cm_analog_auto_partial() in DC or TRAN analysis */ if((anal_type != MIF_AC) && (g_mif_info.auto_partial.global || g_mif_info.auto_partial.local)) MIFauto_partial(here, DEVices[mod_type]->DEVpublic.cm_func, &cm_data); /* ***************************************************************** */ /* Loop through all connections on this instance and */ /* load the data into the matrix for each output port */ /* and for each V source associated with a current input. */ /* For AC analysis, we only load the +-1s required to satisfy */ /* KCL and KVL in the matrix equations. */ /* ***************************************************************** */ num_conn = here->num_conn; for(i = 0; i < num_conn; i++) { /* if the connection is null, skip to next connection */ if(here->conn[i]->is_null) continue; /* prepare things for convenient access later */ is_input = here->conn[i]->is_input; is_output = here->conn[i]->is_output; /* loop through all ports on this connection */ num_port = here->conn[i]->size; for(j = 0; j < num_port; j++) { /*setup a pointer for fast access to port data */ fast = here->conn[i]->port[j]; /* skip if this port is null */ if(fast->is_null) continue; /* determine the type of this port */ type = fast->type; /* If not an analog node, continue to next port */ if((type == MIF_DIGITAL) || (type == MIF_USER_DEFINED)) continue; /* create a pointer to the smp data for quick access */ smp_data_out = &(fast->smp_data); /* if it is a current input */ /* load the matrix data needed for the associated zero-valued V source */ if(is_input && (type == MIF_CURRENT || type == MIF_DIFF_CURRENT)) { *(smp_data_out->pos_ibranch) += 1.0; *(smp_data_out->neg_ibranch) -= 1.0; *(smp_data_out->ibranch_pos) += 1.0; *(smp_data_out->ibranch_neg) -= 1.0; /* rhs[smp_data_out->ibranch] += 0.0; */ } /* end if current input */ /* if it has a voltage source output, */ /* load the matrix with the V source output data */ if( (is_output && (type == MIF_VOLTAGE || type == MIF_DIFF_VOLTAGE)) || (type == MIF_RESISTANCE || type == MIF_DIFF_RESISTANCE) ) { *(smp_data_out->pos_branch) += 1.0; *(smp_data_out->neg_branch) -= 1.0; *(smp_data_out->branch_pos) += 1.0; *(smp_data_out->branch_neg) -= 1.0; if(anal_type != MIF_AC) rhs[smp_data_out->branch] += fast->output.rvalue; } /* end if V source output */ /* if it has a current source output, */ /* load the matrix with the V source output data */ if( (is_output && (type == MIF_CURRENT || type == MIF_DIFF_CURRENT)) || (type == MIF_CONDUCTANCE || type == MIF_DIFF_CONDUCTANCE) ) { if(anal_type != MIF_AC) { rhs[smp_data_out->pos_node] -= fast->output.rvalue; rhs[smp_data_out->neg_node] += fast->output.rvalue; } } /* end if current output */ } /* end for number of ports */ } /* end for number of connections */ /* ***************************************************************** */ /* loop through all output connections on this instance and */ /* load the partials/AC gains into the matrix */ /* ***************************************************************** */ for(i = 0; i < num_conn; i++) { /* if the connection is null or is not an output */ /* skip to next connection */ if((here->conn[i]->is_null) || (! here->conn[i]->is_output)) continue; /* loop through all ports on this connection */ num_port = here->conn[i]->size; for(j = 0; j < num_port; j++) { /*setup a pointer for fast access to port data */ fast = here->conn[i]->port[j]; /* skip if this port is null */ if(fast->is_null) continue; /* determine the type of this output port */ out_type = fast->type; /* If not an analog node, continue to next port */ if((out_type == MIF_DIGITAL) || (out_type == MIF_USER_DEFINED)) continue; /* create a pointer to the smp data for quick access */ smp_data_out = &(fast->smp_data); /* for this port, loop through all connections */ /* and all ports to touch on each possible input */ for(k = 0; k < num_conn; k++) { /* if the connection is null or is not an input */ /* skip to next connection */ if((here->conn[k]->is_null) || (! here->conn[k]->is_input)) continue; num_port_k = here->conn[k]->size; /* loop through all the ports of this connection */ for(l = 0; l < num_port_k; l++) { /* skip if this port is null */ if(here->conn[k]->port[l]->is_null) continue; /* determine the type of this input port */ in_type = here->conn[k]->port[l]->type; /* If not an analog node, continue to next port */ if((in_type == MIF_DIGITAL) || (in_type == MIF_USER_DEFINED)) continue; /* get the partial to local variable for fast access */ partial = fast->partial[k].port[l]; ac_gain = fast->ac_gain[k].port[l]; /* create a pointer to the matrix pointer data for quick access */ smp_ptr = &(smp_data_out->input[k].port[l]); /* get the input value */ cntl_input = here->conn[k]->port[l]->input.rvalue; /* determine type of controlled source according */ /* to input and output types */ cntl_src_type = MIFget_cntl_src_type(in_type, out_type); switch(cntl_src_type) { case MIF_VCVS: if(anal_type == MIF_AC) { smp_ptr->e.branch_poscntl[0] -= ac_gain.real; smp_ptr->e.branch_negcntl[0] += ac_gain.real; smp_ptr->e.branch_poscntl[1] -= ac_gain.imag; smp_ptr->e.branch_negcntl[1] += ac_gain.imag; } else { smp_ptr->e.branch_poscntl[0] -= partial; smp_ptr->e.branch_negcntl[0] += partial; rhs[smp_data_out->branch] -= partial * cntl_input; } break; case MIF_ICIS: if(anal_type == MIF_AC) { smp_ptr->f.pos_ibranchcntl[0] += ac_gain.real; smp_ptr->f.neg_ibranchcntl[0] -= ac_gain.real; smp_ptr->f.pos_ibranchcntl[1] += ac_gain.imag; smp_ptr->f.neg_ibranchcntl[1] -= ac_gain.imag; } else { smp_ptr->f.pos_ibranchcntl[0] += partial; smp_ptr->f.neg_ibranchcntl[0] -= partial; temp = partial * cntl_input; rhs[smp_data_out->pos_node] += temp; rhs[smp_data_out->neg_node] -= temp; } break; case MIF_VCIS: if(anal_type == MIF_AC) { smp_ptr->g.pos_poscntl[0] += ac_gain.real; smp_ptr->g.pos_negcntl[0] -= ac_gain.real; smp_ptr->g.neg_poscntl[0] -= ac_gain.real; smp_ptr->g.neg_negcntl[0] += ac_gain.real; smp_ptr->g.pos_poscntl[1] += ac_gain.imag; smp_ptr->g.pos_negcntl[1] -= ac_gain.imag; smp_ptr->g.neg_poscntl[1] -= ac_gain.imag; smp_ptr->g.neg_negcntl[1] += ac_gain.imag; } else { smp_ptr->g.pos_poscntl[0] += partial; smp_ptr->g.pos_negcntl[0] -= partial; smp_ptr->g.neg_poscntl[0] -= partial; smp_ptr->g.neg_negcntl[0] += partial; temp = partial * cntl_input; rhs[smp_data_out->pos_node] += temp; rhs[smp_data_out->neg_node] -= temp; } break; case MIF_ICVS: if(anal_type == MIF_AC) { smp_ptr->h.branch_ibranchcntl[0] -= ac_gain.real; smp_ptr->h.branch_ibranchcntl[1] -= ac_gain.imag; } else { smp_ptr->h.branch_ibranchcntl[0] -= partial; rhs[smp_data_out->branch] -= partial * cntl_input; } break; case MIF_minus_one: break; } /* end switch on controlled source type */ } /* end for number of input ports */ } /* end for number of input connections */ } /* end for number of output ports */ } /* end for number of output connections */ here->initialized = MIF_TRUE; } /* end for all instances */ } /* end for all models */ return(OK); }
int BSIM3v1SconvTest(GENmodel *inModel, CKTcircuit *ckt) { BSIM3v1Smodel *model = (BSIM3v1Smodel*)inModel; BSIM3v1Sinstance *here; double delvbd, delvbs, delvds, delvgd, delvgs, vbd, vbs, vds; double cbd, cbhat, cbs, cd, cdhat, tol, vgd, vgdo, vgs; /* loop through all the BSIM3v1S device models */ for (; model != NULL; model = model->BSIM3v1SnextModel) { /* loop through all the instances of the model */ for (here = model->BSIM3v1Sinstances; here != NULL ; here=here->BSIM3v1SnextInstance) { if (here->BSIM3v1Sowner != ARCHme) continue; vbs = model->BSIM3v1Stype * (*(ckt->CKTrhsOld+here->BSIM3v1SbNode) - *(ckt->CKTrhsOld+here->BSIM3v1SsNodePrime)); vgs = model->BSIM3v1Stype * (*(ckt->CKTrhsOld+here->BSIM3v1SgNode) - *(ckt->CKTrhsOld+here->BSIM3v1SsNodePrime)); vds = model->BSIM3v1Stype * (*(ckt->CKTrhsOld+here->BSIM3v1SdNodePrime) - *(ckt->CKTrhsOld+here->BSIM3v1SsNodePrime)); vbd = vbs - vds; vgd = vgs - vds; vgdo = *(ckt->CKTstate0 + here->BSIM3v1Svgs) - *(ckt->CKTstate0 + here->BSIM3v1Svds); delvbs = vbs - *(ckt->CKTstate0 + here->BSIM3v1Svbs); delvbd = vbd - *(ckt->CKTstate0 + here->BSIM3v1Svbd); delvgs = vgs - *(ckt->CKTstate0 + here->BSIM3v1Svgs); delvds = vds - *(ckt->CKTstate0 + here->BSIM3v1Svds); delvgd = vgd-vgdo; cd = here->BSIM3v1Scd; if (here->BSIM3v1Smode >= 0) { cdhat = cd - here->BSIM3v1Sgbd * delvbd + here->BSIM3v1Sgmbs * delvbs + here->BSIM3v1Sgm * delvgs + here->BSIM3v1Sgds * delvds; } else { cdhat = cd - (here->BSIM3v1Sgbd - here->BSIM3v1Sgmbs) * delvbd - here->BSIM3v1Sgm * delvgd + here->BSIM3v1Sgds * delvds; } /* * check convergence */ if ((here->BSIM3v1Soff == 0) || (!(ckt->CKTmode & MODEINITFIX))) { tol = ckt->CKTreltol * MAX(fabs(cdhat), fabs(cd)) + ckt->CKTabstol; if (fabs(cdhat - cd) >= tol) { #ifdef STRANGE_PATCH /* gtri - begin - wbk - report conv prob */ if(ckt->enh->conv_debug.report_conv_probs) { ENHreport_conv_prob(ENH_ANALOG_INSTANCE, (char *) here->BSIM3v1Sname, ""); } /* gtri - end - wbk - report conv prob */ #endif /* STRANGE_PATCH */ ckt->CKTnoncon++; return(OK); } cbs = here->BSIM3v1Scbs; cbd = here->BSIM3v1Scbd; cbhat = cbs + cbd + here->BSIM3v1Sgbd * delvbd + here->BSIM3v1Sgbs * delvbs; tol = ckt->CKTreltol * MAX(fabs(cbhat), fabs(cbs + cbd)) + ckt->CKTabstol; if (fabs(cbhat - (cbs + cbd)) > tol) { #ifdef STRANGE_PATCH /* gtri - begin - wbk - report conv prob */ if(ckt->enh->conv_debug.report_conv_probs) { ENHreport_conv_prob(ENH_ANALOG_INSTANCE, (char *) here->BSIM3v1Sname, ""); } /* gtri - end - wbk - report conv prob */ #endif /* STRANGE_PATCH */ ckt->CKTnoncon++; return(OK); } } } } return(OK); }
int MIFconvTest( GENmodel *inModel, /* The head of the model list */ CKTcircuit *ckt) /* The circuit structure */ { MIFmodel *model; MIFinstance *here; int i; double value; double last_value; char *byte_aligned_double_ptr; double *double_ptr; double tol; Mif_Boolean_t gotone = MIF_FALSE; /* Setup for access into MIF specific model data */ model = (MIFmodel *) inModel; /* loop through all models of this type */ for( ; model != NULL; model = model->MIFnextModel) { /* Loop through all instances of this model */ for(here = model->MIFinstances; here != NULL; here = here->MIFnextInstance) { /* Loop through all items registered for convergence */ for(i = 0; i < here->num_conv; i++) { /* Get the current value and the last value */ byte_aligned_double_ptr = (char *) ckt->CKTstate0; byte_aligned_double_ptr += here->conv[i].byte_index; double_ptr = (double *) byte_aligned_double_ptr; value = *double_ptr; last_value = here->conv[i].last_value; /* If none have failed so far, check convergence */ if(! gotone) { tol = ckt->CKTreltol * MAX(fabs(value), fabs(last_value)) + ckt->CKTabstol; if (fabs(value - last_value) > tol) { if(ckt->enh->conv_debug.report_conv_probs) { ENHreport_conv_prob(ENH_ANALOG_INSTANCE, here->MIFname, ""); } ckt->CKTnoncon++; gotone = MIF_TRUE; } } /* Rotate the current value to last_value */ here->conv[i].last_value = value; } /* end for number of conv items */ } /* end for all instances */ } /* end for all models of this type */ return(OK); }