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
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);
|
|
}
|