Exemple #1
0
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);

}
Exemple #2
0
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);
}
Exemple #3
0
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);
}
Exemple #4
0
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);
}