int EVTload( CKTcircuit *ckt, /* The circuit structure */ int inst_index) /* The instance to call code model for */ { int i; int j; int num_conn; int num_port; int mod_type; Mif_Conn_Data_t *conn; Mif_Port_Data_t *port; Mif_Private_t cm_data; MIFinstance *inst; Evt_Node_Data_t *node_data; void *value_ptr; /* ***************************** */ /* Prepare the code model inputs */ /* ***************************** */ /* Get pointer to instance data structure and other data */ /* needed for fast access */ inst = ckt->evt->info.inst_table[inst_index]->inst_ptr; node_data = ckt->evt->data.node; /* Setup circuit data in struct to be passed to code model function */ if(inst->initialized) cm_data.circuit.init = MIF_FALSE; else cm_data.circuit.init = MIF_TRUE; cm_data.circuit.anal_init = MIF_FALSE; cm_data.circuit.anal_type = g_mif_info.circuit.anal_type; if(g_mif_info.circuit.anal_type == MIF_TRAN) cm_data.circuit.time = g_mif_info.circuit.evt_step; else cm_data.circuit.time = 0.0; cm_data.circuit.call_type = MIF_EVENT_DRIVEN; cm_data.circuit.temperature = ckt->CKTtemp - 273.15; /* Setup data needed by cm_... functions */ g_mif_info.ckt = ckt; g_mif_info.instance = inst; g_mif_info.errmsg = ""; g_mif_info.circuit.call_type = MIF_EVENT_DRIVEN; if(inst->initialized) g_mif_info.circuit.init = MIF_FALSE; else g_mif_info.circuit.init = MIF_TRUE; /* If after initialization and in transient analysis mode */ /* create a new state for the instance */ if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized) EVTcreate_state(ckt, inst_index); /* Loop through all connections on the instance and setup */ /* load, total_load, and msg on all ports, and changed flag */ /* and output pointer on all outputs */ num_conn = inst->num_conn; for(i = 0; i < num_conn; i++) { conn = inst->conn[i]; /* if connection is null, continue to next */ if(conn->is_null) continue; /* Loop through each port on the connection */ num_port = conn->size; for(j = 0; j < num_port; j++) { port = conn->port[j]; /* Skip if port is null */ if(port->is_null) continue; /* If port type is Digital or User-Defined */ if((port->type == MIF_DIGITAL) || (port->type == MIF_USER_DEFINED)) { /* Initialize the msg pointer on the port to NULL, */ /* initialize the load value to zero, and get the total load */ port->msg = NULL; port->load = 0.0; port->total_load = node_data->total_load[port->evt_data.node_index]; /* If connection is an output, initialize changed to true */ /* and create a new output event object in the free list */ /* if transient analysis mode */ if(conn->is_output) { port->changed = MIF_TRUE; if(g_mif_info.circuit.anal_type == MIF_TRAN) { EVTcreate_output_event(ckt, port->evt_data.node_index, port->evt_data.output_index, &value_ptr); port->output.pvalue = value_ptr; } } } else { /* Get the analog input value. All we need to do is */ /* set it to zero if mode is INITJCT. Otherwise, value */ /* should still be around from last successful analog call */ if(ckt->CKTmode & MODEINITJCT) port->input.rvalue = 0.0; } } /* end for number of ports */ } /* end for number of connections */ /* Prepare the structure to be passed to the code model */ cm_data.num_conn = inst->num_conn; cm_data.conn = inst->conn; cm_data.num_param = inst->num_param; cm_data.param = inst->param; cm_data.num_inst_var = inst->num_inst_var; cm_data.inst_var = inst->inst_var; cm_data.callback = &(inst->callback); /* ******************* */ /* Call the code model */ /* ******************* */ mod_type = MIFmodPtr(inst)->MIFmodType; DEVices[mod_type]->DEVpublic.cm_func (&cm_data); /* ****************************** */ /* Process the code model outputs */ /* ****************************** */ /* Loop through all connections and ports and process the msgs */ /* and event outputs */ num_conn = inst->num_conn; for(i = 0; i < num_conn; i++) { conn = inst->conn[i]; if(conn->is_null) continue; /* Loop through each port on the connection */ num_port = conn->size; for(j = 0; j < num_port; j++) { port = conn->port[j]; /* Skip if port is null */ if(port->is_null) continue; /* Process the message if any */ if(port->msg) EVTadd_msg(ckt, port->evt_data.port_index, port->msg); /* If this is the initialization pass, process the load factor */ if(! inst->initialized) { node_data->total_load[port->evt_data.node_index] += port->load; } /* If connection is not an event output, continue to next port */ if(! conn->is_output) continue; if((port->type != MIF_DIGITAL) && (port->type != MIF_USER_DEFINED)) continue; /* If output changed, process it */ EVTprocess_output(ckt, port->changed, port->evt_data.output_index, port->invert, port->delay); /* And prevent erroneous models from overwriting it during */ /* analog iterations */ if(g_mif_info.circuit.anal_type == MIF_TRAN) port->output.pvalue = NULL; } /* end for number of ports */ } /* end for number of connections */ /* Record statistics */ if(g_mif_info.circuit.anal_type == MIF_DC) (ckt->evt->data.statistics->op_load_calls)++; else if(g_mif_info.circuit.anal_type == MIF_TRAN) (ckt->evt->data.statistics->tran_load_calls)++; /* Mark that the instance has been called once */ inst->initialized = MIF_TRUE; return(OK); }
static void EVTdequeue_output( CKTcircuit *ckt, /* The circuit structure */ double time) /* The event time of the events to dequeue */ { int i; int j; int num_pending; int index; int output_index; double next_time; double event_time; Evt_Output_Queue_t *output_queue; Evt_Output_Event_t *output; Evt_Output_Event_t **output_ptr; /* Get pointers for fast access */ output_queue = &(ckt->evt->queue.output); /* Exit if nothing pending on output queue or if next_time */ /* != specified time */ if(output_queue->num_pending == 0) return; if(output_queue->next_time != time) return; /* Scan the list of outputs pending */ num_pending = output_queue->num_pending; for(i = 0; i < num_pending; i++) { /* Get the index of the output */ index = output_queue->pending_index[i]; /* Get pointer to next event in queue at this index */ output = *(output_queue->current[index]); /* If event time does not match current time, skip */ if(output->event_time != time) continue; /* It must match, so pull the event from the queue and process it */ EVTprocess_output(ckt, index, output->value); /* Move current to point to next non-removed item in list */ output_ptr = &(output->next); output = *output_ptr; while(output) { if(! output->removed) break; output_ptr = &(output->next); output = *output_ptr; } output_queue->current[index] = output_ptr; /* Mark that this index in the queue has been modified */ if(! output_queue->modified[index]) { output_queue->modified[index] = MIF_TRUE; output_queue->modified_index[(output_queue->num_modified)++] = index; } } /* Update/compact the pending list and update the next_time */ next_time = 1e30; for(i = 0, j = 0; i < num_pending; i++) { output_index = output_queue->pending_index[i]; output = *(output_queue->current[output_index]); /* If nothing in queue at last_step, remove this index from the pending list */ if(! output) { output_queue->pending[output_index] = MIF_FALSE; (output_queue->num_pending)--; } /* else, keep the index and update the next time */ else { output_queue->pending_index[j] = output_queue->pending_index[i]; j++; event_time = output->event_time; if(event_time < next_time) next_time = event_time; } } output_queue->next_time = next_time; }