364 lines
9.7 KiB
C
364 lines
9.7 KiB
C
/*============================================================================
|
|
FILE EVTdequeue.c
|
|
|
|
MEMBER OF process XSPICE
|
|
|
|
Public Domain
|
|
|
|
Georgia Tech Research Corporation
|
|
Atlanta, Georgia 30332
|
|
PROJECT A-8503
|
|
|
|
AUTHORS
|
|
|
|
9/12/91 Bill Kuhn
|
|
|
|
MODIFICATIONS
|
|
|
|
<date> <person name> <nature of modifications>
|
|
|
|
SUMMARY
|
|
|
|
This file contains function EVTdequeue which removes any items on the
|
|
output and instance queues with event times matching the specified
|
|
simulation time.
|
|
|
|
INTERFACES
|
|
|
|
void EVTdequeue(CKTcircuit *ckt, double time)
|
|
|
|
REFERENCED FILES
|
|
|
|
None.
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
None.
|
|
|
|
============================================================================*/
|
|
|
|
#include "ngspice/ngspice.h"
|
|
|
|
#include "ngspice/cktdefs.h"
|
|
//#include "util.h"
|
|
|
|
#include "ngspice/mif.h"
|
|
#include "ngspice/evt.h"
|
|
#include "ngspice/evtudn.h"
|
|
|
|
#include "ngspice/evtproto.h"
|
|
|
|
|
|
static void EVTdequeue_output(CKTcircuit *ckt, double time);
|
|
static void EVTdequeue_inst(CKTcircuit *ckt, double time);
|
|
|
|
static void EVTprocess_output(
|
|
CKTcircuit *ckt,
|
|
int output_index,
|
|
void *value);
|
|
|
|
|
|
/*
|
|
EVTdequeue
|
|
|
|
This function removes any items on the output and instance queues
|
|
with event times matching the specified simulation time. EVTiter
|
|
is then called to determine which instances need to be called.
|
|
|
|
*/
|
|
|
|
|
|
void EVTdequeue(
|
|
CKTcircuit *ckt, /* The circuit structure */
|
|
double time) /* The event time of the events to dequeue */
|
|
{
|
|
|
|
/* Take all items on output queue with matching time */
|
|
/* and set changed flags in output queue */
|
|
EVTdequeue_output(ckt, time);
|
|
|
|
/* Take all items on inst queue with matching time */
|
|
/* and set to_call flags in inst queue */
|
|
EVTdequeue_inst(ckt, time);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
EVTdequeue_output
|
|
|
|
This function de-queues output events with times matching the
|
|
specified time.
|
|
*/
|
|
|
|
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 cleaned or event time does not match current time, skip */
|
|
if(!output || 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
EVTdequeue_inst
|
|
|
|
This function de-queues instance events with times matching the
|
|
specified time.
|
|
*/
|
|
|
|
|
|
void EVTdequeue_inst(
|
|
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 inst_index;
|
|
|
|
double next_time;
|
|
double event_time;
|
|
|
|
Evt_Inst_Queue_t *inst_queue;
|
|
|
|
Evt_Inst_Event_t *inst;
|
|
|
|
|
|
/* Get pointers for fast access */
|
|
inst_queue = &(ckt->evt->queue.inst);
|
|
|
|
/* Exit if nothing pending on inst queue or if next_time */
|
|
/* != specified time */
|
|
if(inst_queue->num_pending == 0)
|
|
return;
|
|
if(inst_queue->next_time != time)
|
|
return;
|
|
|
|
/* Scan the list of insts pending */
|
|
num_pending = inst_queue->num_pending;
|
|
for(i = 0; i < num_pending; i++) {
|
|
|
|
/* Get the index of the inst */
|
|
index = inst_queue->pending_index[i];
|
|
|
|
/* Get pointer to next event in queue at this index */
|
|
inst = *(inst_queue->current[index]);
|
|
|
|
/* If cleaned or event time does not match current time, skip */
|
|
if(!inst || inst->event_time != time)
|
|
continue;
|
|
|
|
/* It must match, so pull the event from the queue and process it */
|
|
if(! inst_queue->to_call[index]) {
|
|
inst_queue->to_call[index] = MIF_TRUE;
|
|
inst_queue->to_call_index[(inst_queue->num_to_call)++] =
|
|
index;
|
|
}
|
|
|
|
/* Move current to point to next item in list */
|
|
inst_queue->current[index] = &(inst->next);
|
|
|
|
/* Mark that this index in the queue has been modified */
|
|
if(! inst_queue->modified[index]) {
|
|
inst_queue->modified[index] = MIF_TRUE;
|
|
inst_queue->modified_index[(inst_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++) {
|
|
inst_index = inst_queue->pending_index[i];
|
|
inst = *(inst_queue->current[inst_index]);
|
|
/* If nothing in queue at last_step, remove this index from the pending list */
|
|
if(! inst) {
|
|
inst_queue->pending[inst_index] = MIF_FALSE;
|
|
(inst_queue->num_pending)--;
|
|
}
|
|
/* else, keep the index and update the next time */
|
|
else {
|
|
inst_queue->pending_index[j] = inst_queue->pending_index[i];
|
|
j++;
|
|
event_time = inst->event_time;
|
|
if(event_time < next_time)
|
|
next_time = event_time;
|
|
}
|
|
}
|
|
inst_queue->next_time = next_time;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
EVTprocess_output
|
|
|
|
This function processes a specified output after it is pulled
|
|
from the queue.
|
|
*/
|
|
|
|
|
|
static void EVTprocess_output(
|
|
CKTcircuit *ckt, /* The circuit structure */
|
|
int output_index, /* The index of the output to process */
|
|
void *value) /* The output value */
|
|
{
|
|
|
|
int num_outputs;
|
|
int node_index;
|
|
int udn_index;
|
|
int output_subindex;
|
|
|
|
Evt_Output_Info_t **output_table;
|
|
Evt_Node_Info_t **node_table;
|
|
|
|
Evt_Node_t *rhs;
|
|
Evt_Node_t *rhsold;
|
|
|
|
Evt_Output_Queue_t *output_queue;
|
|
|
|
Mif_Boolean_t equal;
|
|
|
|
|
|
output_table = ckt->evt->info.output_table;
|
|
node_table = ckt->evt->info.node_table;
|
|
|
|
node_index = output_table[output_index]->node_index;
|
|
num_outputs = node_table[node_index]->num_outputs;
|
|
udn_index = node_table[node_index]->udn_index;
|
|
|
|
rhs = ckt->evt->data.node->rhs;
|
|
rhsold = ckt->evt->data.node->rhsold;
|
|
|
|
/* Determine if output is different from rhsold value */
|
|
/* and copy it to rhs AND rhsold if so */
|
|
/* This is somewhat inefficient, but that's the way */
|
|
/* we have setup the structures (rhs and rhsold must match)... */
|
|
if(num_outputs > 1) {
|
|
output_subindex = output_table[output_index]->output_subindex;
|
|
g_evt_udn_info[udn_index]->compare
|
|
(value,
|
|
rhsold[node_index].output_value[output_subindex],
|
|
&equal);
|
|
if(! equal) {
|
|
g_evt_udn_info[udn_index]->copy
|
|
(value, rhs[node_index].output_value[output_subindex]);
|
|
g_evt_udn_info[udn_index]->copy
|
|
(value, rhsold[node_index].output_value[output_subindex]);
|
|
}
|
|
}
|
|
else {
|
|
g_evt_udn_info[udn_index]->compare
|
|
(value,
|
|
rhsold[node_index].node_value,
|
|
&equal);
|
|
if(! equal) {
|
|
g_evt_udn_info[udn_index]->copy
|
|
(value, rhs[node_index].node_value);
|
|
g_evt_udn_info[udn_index]->copy
|
|
(value, rhsold[node_index].node_value);
|
|
}
|
|
}
|
|
|
|
/* If different, put in changed list of output queue */
|
|
if(! equal) {
|
|
output_queue = &(ckt->evt->queue.output);
|
|
if(! output_queue->changed[output_index]) {
|
|
output_queue->changed[output_index] = MIF_TRUE;
|
|
output_queue->changed_index[(output_queue->num_changed)++] =
|
|
output_index;
|
|
}
|
|
}
|
|
}
|