📄 evtinit.c
字号:
/*============================================================================FILE EVTinit.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 EVTinit which allocates and initializes evt structure elements after the number of instances, nodes, etc. have been determined in parsing during INPpas2. EVTinit also checks to be sure no nodes have been used for both analog and event-driven algorithms simultaneously.INTERFACES int EVTinit(CKTcircuit *ckt)REFERENCED FILES None.NON-STANDARD FEATURES None.============================================================================*/#include <string.h>#include <stdio.h>#include "ngspice.h"#include "cktdefs.h"//#include "util.h"#include "sperror.h"#include "evtproto.h"static int EVTcheck_nodes(CKTcircuit *ckt);static int EVTcount_hybrids(CKTcircuit *ckt);static int EVTinit_info(CKTcircuit *ckt);static int EVTinit_queue(CKTcircuit *ckt);static int EVTinit_limits(CKTcircuit *ckt);/* Allocation macro with built-in check for out-of-memory *//* Adapted from SPICE 3C1 code in CKTsetup.c */#define CKALLOC(var,size,type) \ if(size) { \ if(!(var = (void *) MALLOC((size) * sizeof(type)))) \ return(E_NOMEM); \ }/*EVTinitAllocate and initialize additional evt structure elements now thatwe can determine the number of instances, nodes, etc.Also check to be sure that no nodes have been used in both event-drivenand analog domains.In this version, we also report an error if there are no hybrids in thecircuit. This restriction may be removed in the future to allow thesimulator to be used with digital only circuits...*/int EVTinit( CKTcircuit *ckt) /* the circuit structure */{ int err; /* SPICE error return code 0 = OK */ /* static char *err_no_hybrids = "ERROR - no hybrids found in input deck";*/ /* Exit immediately if there are no event-driven instances */ /* but don't complain */ if(ckt->evt->counts.num_insts == 0) return(OK); /* Count the number of hybrids and hybrid outputs */ err = EVTcount_hybrids(ckt); if(err) return(err); /* Exit with error if there are no hybrids in the circuit. */ /* Will probably remove this restriction later... *//* if(ckt->evt->counts.num_hybrids == 0) { errMsg = MALLOC(strlen(err_no_hybrids) + 1); strcpy(errMsg, err_no_hybrids); return(E_PRIVATE); }*/ /* Check that event nodes have not been used as analog nodes also */ err = EVTcheck_nodes(ckt); if(err) return(err); /* Create info table arrays */ err = EVTinit_info(ckt); if(err) return(err); /* Setup queues */ err = EVTinit_queue(ckt); if(err) return(err); /* Initialize limits */ err = EVTinit_limits(ckt); if(err) return(err); /* Note: Options were initialized in CKTinit so that INPpas2 */ /* could set values according to .options cards in deck. The */ /* structure 'jobs' will be setup immediately prior to each */ /* simulation job. The results data structure is also */ /* allocated immediately prior to each simulation job. */ /* Return */ return(OK);}/*EVTcount_hybridsCount the number of hybrids and the number of outputs on all hybrids.*/static int EVTcount_hybrids( CKTcircuit *ckt) /* The circuit structure */{ int i; int j; int num_hybrids; int num_hybrid_outputs; int num_conn; int num_port; MIFinstance *fast; Evt_Inst_Info_t *inst; /* Count number of hybrids and hybrid outputs in the inst list */ /* created during parsing. Note: other counts */ /* are created during parsing, but these were */ /* too difficult to do until now... */ num_hybrids = 0; num_hybrid_outputs = 0; inst = ckt->evt->info.inst_list; while(inst) { fast = inst->inst_ptr; if(fast->analog && fast->event_driven) { num_hybrids++; num_conn = fast->num_conn; for(i = 0; i < num_conn; i++) { if((! fast->conn[i]->is_null) && (fast->conn[i]->is_output)) { num_port = fast->conn[i]->size; for(j = 0; j < num_port; j++) if(! fast->conn[i]->port[j]->is_null) num_hybrid_outputs++; } } } inst = inst->next; } ckt->evt->counts.num_hybrids = num_hybrids; ckt->evt->counts.num_hybrid_outputs = num_hybrid_outputs; return(OK);}/*EVTcheck_nodesReport error if any event node name is also used as an analog node.*/static int EVTcheck_nodes( CKTcircuit *ckt) /* The circuit structure */{ CKTnode *analog_node; Evt_Node_Info_t *event_node; static char *err_prefix = "ERROR - node "; static char *err_collide = " cannot be both analog and digital"; /* Report error if any analog node name matches any event node name */ event_node = ckt->evt->info.node_list; while(event_node) { analog_node = ckt->CKTnodes; while(analog_node) { if(strcmp(event_node->name, analog_node->name) == 0) { errMsg = MALLOC(strlen(err_prefix) + strlen(event_node->name) + strlen(err_collide) + 1); sprintf(errMsg, "%s%s%s", err_prefix, event_node->name, err_collide); fprintf(stdout,errMsg); return(E_PRIVATE); } analog_node = analog_node->next; } event_node = event_node->next; } /* Return */ return(OK);}/*EVTinit_infoThis function creates the ``info'' pointer tables used in theevent-driven circuit representation. These arrays allow fasteraccess to data associated with instances, nodes, ports, andoutputs than could be provided by having to scan the linked-listrepresentations created during parsing.*/static int EVTinit_info( CKTcircuit *ckt) /* the circuit structure */{ int i; int j; int num_insts; int num_nodes; int num_ports; int num_outputs; Evt_Inst_Info_t *inst; Evt_Node_Info_t *node; Evt_Port_Info_t *port; Evt_Output_Info_t *output; Evt_Inst_Info_t **inst_table = NULL; Evt_Node_Info_t **node_table = NULL; Evt_Port_Info_t **port_table = NULL; Evt_Output_Info_t **output_table = NULL; int *hybrid_index = NULL; int num_hybrids; /* Allocate and initialize table of inst pointers */ num_insts = ckt->evt->counts.num_insts; CKALLOC(inst_table, num_insts, void *) inst = ckt->evt->info.inst_list; for(i = 0; i < num_insts; i++) { inst_table[i] = inst; inst = inst->next; } ckt->evt->info.inst_table = inst_table; /* Allocate and initialize table of node pointers */ num_nodes = ckt->evt->counts.num_nodes; CKALLOC(node_table, num_nodes, void *) node = ckt->evt->info.node_list; for(i = 0; i < num_nodes; i++) { node_table[i] = node; node = node->next; } ckt->evt->info.node_table = node_table; /* Allocate and initialize table of port pointers */ num_ports = ckt->evt->counts.num_ports; CKALLOC(port_table, num_ports, void *) port = ckt->evt->info.port_list; for(i = 0; i < num_ports; i++) { port_table[i] = port; port = port->next; } ckt->evt->info.port_table = port_table; /* Allocate and initialize table of output pointers */ num_outputs = ckt->evt->counts.num_outputs; CKALLOC(output_table, num_outputs, void *) output = ckt->evt->info.output_list; for(i = 0; i < num_outputs; i++) { output_table[i] = output; output = output->next; } ckt->evt->info.output_table = output_table; /* Allocate and create table of indexes into inst_table for hybrids */ num_hybrids = ckt->evt->counts.num_hybrids; CKALLOC(hybrid_index, num_hybrids, int) for(i = 0, j = 0; i < num_insts; i++) { if(inst_table[i]->inst_ptr->analog) hybrid_index[j++] = i; } ckt->evt->info.hybrid_index = hybrid_index; /* Return */ return(OK);}/*EVTinit_queueThis function prepares the event-driven queues for simulation.*/static int EVTinit_queue( CKTcircuit *ckt) /* the circuit structure */{ int num_insts; int num_nodes; int num_outputs; Evt_Inst_Queue_t *inst_queue; Evt_Node_Queue_t *node_queue; Evt_Output_Queue_t *output_queue; /* Allocate elements in the inst queue */ num_insts = ckt->evt->counts.num_insts; inst_queue = &(ckt->evt->queue.inst); CKALLOC(inst_queue->head, num_insts, void *) CKALLOC(inst_queue->current, num_insts, void *) CKALLOC(inst_queue->last_step, num_insts, void *) CKALLOC(inst_queue->free, num_insts, void *) CKALLOC(inst_queue->modified_index, num_insts, int) CKALLOC(inst_queue->modified, num_insts, Mif_Boolean_t) CKALLOC(inst_queue->pending_index, num_insts, int) CKALLOC(inst_queue->pending, num_insts, Mif_Boolean_t) CKALLOC(inst_queue->to_call_index, num_insts, int) CKALLOC(inst_queue->to_call, num_insts, Mif_Boolean_t) /* Allocate elements in the node queue */ num_nodes = ckt->evt->counts.num_nodes; node_queue = &(ckt->evt->queue.node); CKALLOC(node_queue->to_eval_index, num_nodes, int) CKALLOC(node_queue->to_eval, num_nodes, Mif_Boolean_t) CKALLOC(node_queue->changed_index, num_nodes, int) CKALLOC(node_queue->changed, num_nodes, Mif_Boolean_t) /* Allocate elements in the output queue */ num_outputs = ckt->evt->counts.num_outputs; output_queue = &(ckt->evt->queue.output); CKALLOC(output_queue->head, num_outputs, void *) CKALLOC(output_queue->current, num_outputs, void *) CKALLOC(output_queue->last_step, num_outputs, void *) CKALLOC(output_queue->free, num_outputs, void *) CKALLOC(output_queue->modified_index, num_outputs, int) CKALLOC(output_queue->modified, num_outputs, Mif_Boolean_t) CKALLOC(output_queue->pending_index, num_outputs, int) CKALLOC(output_queue->pending, num_outputs, Mif_Boolean_t) CKALLOC(output_queue->changed_index, num_outputs, int) CKALLOC(output_queue->changed, num_outputs, Mif_Boolean_t) /* Return */ return(OK);}/*EVTinit_limitsThis function initializes the iteration limits applicable to theevent-driven algorithm.*/static int EVTinit_limits( CKTcircuit *ckt) /* the circuit structure */{ /* Set maximum number of event load calls within a single event iteration */ /* to the number of event outputs. This should allow for the */ /* maximum possible number of events that can trickle through any */ /* circuit that does not contain loops. */ ckt->evt->limits.max_event_passes = ckt->evt->counts.num_outputs + 1; /* Set maximum number of alternations between analog and event-driven */ /* iterations to the number of event outputs on hybrids. */ ckt->evt->limits.max_op_alternations = ckt->evt->counts.num_hybrid_outputs + 1; /* Return */ return(OK);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -