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.
 
 
 
 
 
 

616 lines
17 KiB

/*============================================================================
FILE EVTsetup.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 EVTsetup which clears/allocates the
event-driven queues and data structures immediately prior to a new
analysis. In addition, it places entries in the job list so that
results data from multiple analysis can be retrieved similar to
SPICE3C1 saving multiple 'plots'.
INTERFACES
int EVTsetup(CKTcircuit *ckt)
REFERENCED FILES
None.
NON-STANDARD FEATURES
None.
============================================================================*/
#include "ngspice/ngspice.h"
//#include "misc.h"
#include "ngspice/cktdefs.h"
#include "ngspice/sperror.h"
//#include "util.h"
#include "ngspice/mif.h"
#include "ngspice/evt.h"
#include "ngspice/evtudn.h"
#include "ngspice/mifproto.h"
#include "ngspice/evtproto.h"
static int EVTsetup_queues(CKTcircuit *ckt);
static int EVTsetup_data(CKTcircuit *ckt);
static int EVTsetup_jobs(CKTcircuit *ckt);
static int EVTsetup_load_ptrs(CKTcircuit *ckt);
int EVTsetup_plot(CKTcircuit* ckt, char* plotname);
/* Allocation macros 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); \
}
#define CKREALLOC(var,size,type) \
if((size) == 1) { \
if((var = TMALLOC(type, size)) == NULL) \
return(E_NOMEM); \
} else if((size) > 1) { \
if((var = TREALLOC(type, (var), size)) == NULL) \
return(E_NOMEM); \
}
/*
EVTsetup
This function clears/allocates the event-driven queues and data structures
immediately prior to a new analysis. In addition, it places entries
in the job list so that results data from multiple analysis can be
retrieved similar to SPICE3C1 saving multiple 'plots'.
*/
int EVTsetup(
CKTcircuit *ckt) /* The circuit structure */
{
int err;
/* Exit immediately if no event-driven instances in circuit */
if(ckt->evt->counts.num_insts == 0)
return(OK);
/* Clear the inst, node, and output queues, and initialize the to_call */
/* elements in the instance queue to call all event-driven instances */
err = EVTsetup_queues(ckt);
if(err)
return(err);
/* Allocate and initialize the node, state, message, and statistics data */
err = EVTsetup_data(ckt);
if(err)
return(err);
/* Set the job pointers to the allocated results, states, messages, */
/* and statistics so that data will be accessable after run */
err = EVTsetup_jobs(ckt);
if(err)
return(err);
/* Setup the pointers in the MIFinstance structure for inputs, outputs, */
/* and total loads */
err = EVTsetup_load_ptrs(ckt);
if(err)
return(err);
/* Initialize additional event data */
g_mif_info.circuit.evt_step = 0.0;
/* Return OK */
return(OK);
}
int EVTunsetup(
CKTcircuit* ckt) /* The circuit structure */
{
int err;
/* Exit immediately if no event-driven instances in circuit */
if (ckt->evt->counts.num_insts == 0)
return(OK);
/* Clear the inst, node, and output queues, and initialize the to_call */
/* elements in the instance queue to call all event-driven instances */
err = EVTsetup_queues(ckt);
if (err)
return(err);
/* Initialize additional event data */
g_mif_info.circuit.evt_step = 0.0;
/* Return OK */
return(OK);
}
/*
EVTsetup_queues
This function clears the event-driven queues in preparation for
a new simulation.
*/
static int EVTsetup_queues(
CKTcircuit *ckt) /* The circuit structure */
{
int i;
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;
Evt_Inst_Event_t *inst_event;
Evt_Output_Event_t *output_event;
void *ptr;
/* ************************ */
/* Clear the instance queue */
/* ************************ */
num_insts = ckt->evt->counts.num_insts;
inst_queue = &(ckt->evt->queue.inst);
for(i = 0; i < num_insts; i++) {
inst_event = inst_queue->head[i];
while(inst_event) {
ptr = inst_event;
inst_event = inst_event->next;
FREE(ptr);
}
inst_event = inst_queue->free[i];
while(inst_event) {
ptr = inst_event;
inst_event = inst_event->next;
FREE(ptr);
}
inst_queue->head[i] = NULL;
inst_queue->current[i] = &(inst_queue->head[i]);
inst_queue->last_step[i] = &(inst_queue->head[i]);
inst_queue->free[i] = NULL;
}
inst_queue->next_time = 0.0;
inst_queue->last_time = 0.0;
inst_queue->num_modified = 0;
inst_queue->num_pending = 0;
inst_queue->num_to_call = 0;
for(i = 0; i < num_insts; i++) {
inst_queue->modified[i] = MIF_FALSE;
inst_queue->pending[i] = MIF_FALSE;
inst_queue->to_call[i] = MIF_FALSE;
}
/* ******************** */
/* Clear the node queue */
/* ******************** */
num_nodes = ckt->evt->counts.num_nodes;
node_queue = &(ckt->evt->queue.node);
node_queue->num_changed = 0;
node_queue->num_to_eval = 0;
for(i = 0; i < num_nodes; i++) {
node_queue->changed[i] = MIF_FALSE;
node_queue->to_eval[i] = MIF_FALSE;
}
/* ********************** */
/* Clear the output queue */
/* ********************** */
num_outputs = ckt->evt->counts.num_outputs;
output_queue = &(ckt->evt->queue.output);
for(i = 0; i < num_outputs; i++) {
output_event = output_queue->head[i];
while(output_event) {
ptr = output_event;
output_event = output_event->next;
FREE(ptr);
}
output_event = output_queue->free[i];
while(output_event) {
ptr = output_event;
output_event = output_event->next;
FREE(ptr);
}
output_queue->head[i] = NULL;
output_queue->current[i] = &(output_queue->head[i]);
output_queue->last_step[i] = &(output_queue->head[i]);
output_queue->free[i] = NULL;
}
output_queue->next_time = 0.0;
output_queue->last_time = 0.0;
output_queue->num_modified = 0;
output_queue->num_pending = 0;
output_queue->num_changed = 0;
for(i = 0; i < num_outputs; i++) {
output_queue->modified[i] = MIF_FALSE;
output_queue->pending[i] = MIF_FALSE;
output_queue->changed[i] = MIF_FALSE;
}
return(OK);
}
/*
EVTsetup_data
This function sets up the event-driven node, state, and
message data runtime structures in preparation for
a new simulation.
*/
static int EVTsetup_data(
CKTcircuit *ckt) /* The circuit structure */
{
Evt_Data_t *data;
int i;
int j;
int num_insts;
int num_ports;
int num_nodes;
int udn_index;
int num_outputs;
Mif_Boolean_t invert;
Evt_Node_Data_t *node_data;
Evt_State_Data_t *state_data;
Evt_Msg_Data_t *msg_data;
/* Evt_Statistic_t *statistics_data;*/
Evt_Node_t *rhs;
Evt_Node_t *rhsold;
Evt_Node_Info_t *node_info;
/* Allocate main substructures of data */
/* Note that we don't free any old structures */
/* since they are pointed to by jobs and need */
/* to be maintained so that results from multiple */
/* jobs are kept around like SPICE does */
data = &(ckt->evt->data);
CKALLOC(data->node, 1, Evt_Node_Data_t)
CKALLOC(data->state, 1, Evt_State_Data_t)
CKALLOC(data->msg, 1, Evt_Msg_Data_t)
CKALLOC(data->statistics, 1, Evt_Statistic_t)
/* Allocate node data */
num_nodes = ckt->evt->counts.num_nodes;
node_data = data->node;
CKALLOC(node_data->head, num_nodes, Evt_Node_t *)
CKALLOC(node_data->tail, num_nodes, Evt_Node_t **)
CKALLOC(node_data->last_step, num_nodes, Evt_Node_t **)
CKALLOC(node_data->free, num_nodes, Evt_Node_t *)
CKALLOC(node_data->modified_index, num_nodes, int)
CKALLOC(node_data->modified, num_nodes, Mif_Boolean_t)
CKALLOC(node_data->rhs, num_nodes, Evt_Node_t)
CKALLOC(node_data->rhsold, num_nodes, Evt_Node_t)
CKALLOC(node_data->total_load, num_nodes, double)
/* Initialize the node data */
for(i = 0; i < num_nodes; i++) {
node_data->tail[i] = &(node_data->head[i]);
node_data->last_step[i] = &(node_data->head[i]);
}
for(i = 0; i < num_nodes; i++) {
/* Get pointers to rhs & rhsold, the user-defined node type index, */
/* the number of outputs on the node and the invert flag */
rhs = &(node_data->rhs[i]);
rhsold = &(node_data->rhsold[i]);
node_info = ckt->evt->info.node_table[i];
udn_index = node_info->udn_index;
num_outputs = node_info->num_outputs;
invert = node_info->invert;
/* Initialize the elements within rhs and rhsold */
rhs->step = 0.0;
rhsold->step = 0.0;
if(num_outputs > 1) {
CKALLOC(rhs->output_value, num_outputs, void *)
CKALLOC(rhsold->output_value, num_outputs, void *)
for(j = 0; j < num_outputs; j++) {
g_evt_udn_info[udn_index]->create (&(rhs->output_value[j]));
g_evt_udn_info[udn_index]->initialize (rhs->output_value[j]);
g_evt_udn_info[udn_index]->create (&(rhsold->output_value[j]));
g_evt_udn_info[udn_index]->initialize (rhsold->output_value[j]);
}
}
g_evt_udn_info[udn_index]->create (&(rhs->node_value));
g_evt_udn_info[udn_index]->initialize (rhs->node_value);
g_evt_udn_info[udn_index]->create (&(rhsold->node_value));
g_evt_udn_info[udn_index]->initialize (rhsold->node_value);
if(invert) {
g_evt_udn_info[udn_index]->create (&(rhs->inverted_value));
g_evt_udn_info[udn_index]->initialize (rhs->inverted_value);
g_evt_udn_info[udn_index]->create (&(rhsold->inverted_value));
g_evt_udn_info[udn_index]->initialize (rhsold->inverted_value);
}
/* Initialize the total load value to zero */
node_data->total_load[i] = 0.0;
}
/* Allocate and initialize state data */
num_insts = ckt->evt->counts.num_insts;
state_data = data->state;
CKALLOC(state_data->head, num_insts, Evt_State_t *)
CKALLOC(state_data->tail, num_insts, Evt_State_t **)
CKALLOC(state_data->last_step, num_insts, Evt_State_t **)
CKALLOC(state_data->free, num_insts, Evt_State_t *)
CKALLOC(state_data->modified_index, num_insts, int)
CKALLOC(state_data->modified, num_insts, Mif_Boolean_t)
CKALLOC(state_data->total_size, num_insts, int)
CKALLOC(state_data->desc, num_insts, Evt_State_Desc_t *)
for(i = 0; i < num_insts; i++) {
state_data->tail[i] = &(state_data->head[i]);
state_data->last_step[i] = &(state_data->head[i]);
}
/* Allocate and initialize msg data */
num_ports = ckt->evt->counts.num_ports;
msg_data = data->msg;
CKALLOC(msg_data->head, num_ports, Evt_Msg_t *)
CKALLOC(msg_data->tail, num_ports, Evt_Msg_t **)
CKALLOC(msg_data->last_step, num_ports, Evt_Msg_t **)
CKALLOC(msg_data->free, num_ports, Evt_Msg_t *)
CKALLOC(msg_data->modified_index, num_ports, int)
CKALLOC(msg_data->modified, num_ports, Mif_Boolean_t)
for(i = 0; i < num_ports; i++) {
msg_data->tail[i] = &(msg_data->head[i]);
msg_data->last_step[i] = &(msg_data->head[i]);
}
/* Don't need to initialize statistics since they were */
/* calloc'ed above */
return(OK);
}
/*
EVTsetup_jobs
This function prepares the jobs data for a new simulation.
*/
static int EVTsetup_jobs(
CKTcircuit *ckt) /* The circuit structure */
{
int i;
int num_jobs;
Evt_Job_t *jobs;
Evt_Data_t *data;
jobs = &(ckt->evt->jobs);
data = &(ckt->evt->data);
/* Increment the number of jobs */
num_jobs = ++(jobs->num_jobs);
/* Allocate/reallocate necessary pointers */
CKREALLOC(jobs->job_name, num_jobs, char *)
CKREALLOC(jobs->job_plot, num_jobs, char *)
CKREALLOC(jobs->node_data, num_jobs, Evt_Node_Data_t *)
CKREALLOC(jobs->state_data, num_jobs, Evt_State_Data_t *)
CKREALLOC(jobs->msg_data, num_jobs, Evt_Msg_Data_t *)
CKREALLOC(jobs->statistics, num_jobs, Evt_Statistic_t *)
/* Fill in the pointers, etc. for this new job */
i = num_jobs - 1;
jobs->job_name[i] = MIFcopy(ckt->CKTcurJob->JOBname);
jobs->job_plot[i] = NULL; /* fill in later */
jobs->node_data[i] = data->node;
jobs->state_data[i] = data->state;
jobs->msg_data[i] = data->msg;
jobs->statistics[i] = data->statistics;
return(OK);
}
/*
EVTsetup_load_ptrs
This function setups up the required data in the MIFinstance
structure of event-driven and hybrid instances.
*/
static int EVTsetup_load_ptrs(
CKTcircuit *ckt) /* The circuit structure */
{
int i;
int j;
int k;
int num_insts;
int num_conn;
int num_port;
int num_outputs;
int node_index;
int output_subindex;
MIFinstance *fast;
Mif_Conn_Data_t *conn;
Mif_Port_Type_t type;
Mif_Port_Data_t *port;
Evt_Node_Data_t *node_data;
/* This function setups up the required data in the MIFinstance */
/* structure of event-driven and hybrid instances */
/* Loop through all event-driven and hybrid instances */
num_insts = ckt->evt->counts.num_insts;
for(i = 0; i < num_insts; i++) {
/* Get the MIFinstance pointer */
fast = ckt->evt->info.inst_table[i]->inst_ptr;
/* Reset init flag, required when any run is called a second time */
fast->initialized = FALSE;
/* Loop through all connections */
num_conn = fast->num_conn;
for(j = 0; j < num_conn; j++) {
/* Skip if connection is null */
if(fast->conn[j]->is_null)
continue;
conn = fast->conn[j];
/* Loop through all ports */
num_port = conn->size;
for(k = 0; k < num_port; k++) {
/* Get port data pointer for quick access */
port = conn->port[k];
if(port->is_null)
continue;
/* Skip if port is not digital or user-defined type */
type = port->type;
if((type != MIF_DIGITAL) && (type != MIF_USER_DEFINED))
continue;
/* Set input.pvalue to point to rhsold.node_value or to */
/* rhsold.inverted_value as appropriate */
node_index = port->evt_data.node_index;
node_data = ckt->evt->data.node;
if(conn->is_input) {
if(port->invert) {
port->input.pvalue = node_data->rhsold[node_index].
inverted_value;
}
else {
port->input.pvalue = node_data->rhsold[node_index].
node_value;
}
}
/* Set output.pvalue to point to rhs.node_value or rhs.output_value[i] */
/* where i is given by the output_subindex in output info */
/* depending on whether more than one output is connected to the node. */
/* Note that this is only for the DCOP analysis. During a transient */
/* analysis, new structures will be created and the pointers will */
/* be set by EVTload */
if(conn->is_output) {
num_outputs = ckt->evt->info.node_table[node_index]->num_outputs;
if(num_outputs <= 1) {
port->output.pvalue = node_data->rhs[node_index].
node_value;
}
else {
output_subindex = port->evt_data.output_subindex;
port->output.pvalue = node_data->rhs[node_index].
output_value[output_subindex];
}
}
} /* end for number of ports */
} /* end for number of connections */
} /* end for number of insts */
return(OK);
}
/* get the analog plot name and store it into the current event job */
int EVTsetup_plot(CKTcircuit* ckt, char *plotname) {
if (ckt->evt->counts.num_insts == 0)
return(OK);
Evt_Job_t* jobs = &(ckt->evt->jobs);
if (jobs) {
jobs->job_plot[jobs->num_jobs - 1] = copy(plotname);
return OK;
}
return 1;
}