You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

432 lines
12 KiB

/*============================================================================
FILE EVTinit.c
MEMBER OF process XSPICE
Copyright 1991
Georgia Tech Research Corporation
Atlanta, Georgia 30332
All Rights Reserved
PROJECT A-8503
AUTHORS
9/12/91 Bill Kuhn
MODIFICATIONS
<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 "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
//#include "util.h"
#include "ngspice/sperror.h"
#include "ngspice/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 = TMALLOC(type, size)) == NULL) \
return(E_NOMEM); \
}
/*
EVTinit
Allocate and initialize additional evt structure elements now that
we can determine the number of instances, nodes, etc.
Also check to be sure that no nodes have been used in both event-driven
and analog domains.
In this version, we also report an error if there are no hybrids in the
circuit. This restriction may be removed in the future to allow the
simulator 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 = TMALLOC(char, 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_hybrids
Count 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_nodes
Report 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 = TMALLOC(char, 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, "%s\n", errMsg);
return(E_PRIVATE);
}
analog_node = analog_node->next;
}
event_node = event_node->next;
}
/* Return */
return(OK);
}
/*
EVTinit_info
This function creates the ``info'' pointer tables used in the
event-driven circuit representation. These arrays allow faster
access to data associated with instances, nodes, ports, and
outputs than could be provided by having to scan the linked-list
representations 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, Evt_Inst_Info_t *)
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, Evt_Node_Info_t *)
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, Evt_Port_Info_t *)
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, Evt_Output_Info_t *)
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_queue
This 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, Evt_Inst_Event_t *)
CKALLOC(inst_queue->current, num_insts, Evt_Inst_Event_t **)
CKALLOC(inst_queue->last_step, num_insts, Evt_Inst_Event_t **)
CKALLOC(inst_queue->free, num_insts, Evt_Inst_Event_t *)
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, Evt_Output_Event_t *)
CKALLOC(output_queue->current, num_outputs, Evt_Output_Event_t **)
CKALLOC(output_queue->last_step, num_outputs, Evt_Output_Event_t **)
CKALLOC(output_queue->free, num_outputs, Evt_Output_Event_t *)
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_limits
This function initializes the iteration limits applicable to the
event-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);
}