diff --git a/src/include/ngspice/evt.h b/src/include/ngspice/evt.h index 2917b76a5..7dfb35c27 100644 --- a/src/include/ngspice/evt.h +++ b/src/include/ngspice/evt.h @@ -172,7 +172,7 @@ struct Evt_Output_Queue { Evt_Output_Event_t **head; /* Beginning of linked lists */ Evt_Output_Event_t ***current; /* Beginning of pending events */ Evt_Output_Event_t ***last_step; /* Values of 'current' at last accepted timepoint */ - Evt_Output_Event_t **free; /* Linked lists of items freed by backups */ + Evt_Output_Event_t ***free_list; /* Pointers to linked lists of items freed by backups */ double last_time; /* Time at which last_step was set */ double next_time; /* Earliest next event time in queue */ int num_modified; /* Number modified since last accepted timepoint */ diff --git a/src/include/ngspice/evtproto.h b/src/include/ngspice/evtproto.h index 359133801..f37bb0fa7 100644 --- a/src/include/ngspice/evtproto.h +++ b/src/include/ngspice/evtproto.h @@ -134,5 +134,6 @@ bool Evtcheck_nodes( struct INPtables *stab); /* Symbol table. */ struct dvec *EVTfindvec(char *node); +void Evt_purge_free_outputs(void); #endif diff --git a/src/include/ngspice/evtudn.h b/src/include/ngspice/evtudn.h index 936c44daf..0e941a5b5 100644 --- a/src/include/ngspice/evtudn.h +++ b/src/include/ngspice/evtudn.h @@ -99,20 +99,22 @@ NON-STANDARD FEATURES void **evt_ipc_val, \ int *evt_ipc_val_size +/* Information about each Digital/User-defined type of node value. */ typedef struct { - char *name; - char *description; - void ((*create)(CREATE_ARGS)); - void ((*dismantle)(DISMANTLE_ARGS)); - void ((*initialize)(INITIALIZE_ARGS)); - void ((*invert)(INVERT_ARGS)); - void ((*copy)(COPY_ARGS)); - void ((*resolve)(RESOLVE_ARGS)); - void ((*compare)(COMPARE_ARGS)); - void ((*plot_val)(PLOT_VAL_ARGS)); - void ((*print_val)(PRINT_VAL_ARGS)); - void ((*ipc_val)(IPC_VAL_ARGS)); + char *name; + char *description; + Evt_Output_Event_t *free_list; /* Event structs for these values. */ + void ((*create)(CREATE_ARGS)); + void ((*dismantle)(DISMANTLE_ARGS)); + void ((*initialize)(INITIALIZE_ARGS)); + void ((*invert)(INVERT_ARGS)); + void ((*copy)(COPY_ARGS)); + void ((*resolve)(RESOLVE_ARGS)); + void ((*compare)(COMPARE_ARGS)); + void ((*plot_val)(PLOT_VAL_ARGS)); + void ((*print_val)(PRINT_VAL_ARGS)); + void ((*ipc_val)(IPC_VAL_ARGS)); } Evt_Udn_Info_t; diff --git a/src/include/ngspice/mifcmdat.h b/src/include/ngspice/mifcmdat.h index 213713c6c..4196c8ee0 100644 --- a/src/include/ngspice/mifcmdat.h +++ b/src/include/ngspice/mifcmdat.h @@ -226,6 +226,7 @@ typedef struct Mif_Port_Data_s { Mif_Boolean_t is_null; /* Set to true if null in SPICE deck */ Mif_Value_t input; /* The input value */ Mif_Value_t output; /* The output value */ + struct Evt_Output_Event *next_event; Mif_Partial_t *partial; /* Partials for this port wrt inputs */ Mif_AC_Gain_t *ac_gain; /* AC gains for this port wrt inputs */ int old_input; /* Index into CKTstate for old input */ diff --git a/src/xspice/evt/evtaccept.c b/src/xspice/evt/evtaccept.c index 1d031d7ed..0e68c26e6 100644 --- a/src/xspice/evt/evtaccept.c +++ b/src/xspice/evt/evtaccept.c @@ -126,13 +126,14 @@ void EVTaccept( num_modified = output_queue->num_modified; /* Loop through list of items modified since last time */ for(i = 0; i < num_modified; i++) { - Evt_Output_Event_t *stale, *next; + Evt_Output_Event_t *stale, *next, **free_list; /* Get the index of the output modified */ index = output_queue->modified_index[i]; /* Reset the modified flag */ output_queue->modified[index] = MIF_FALSE; /* Move stale entries to the free list. */ + free_list = output_queue->free_list[index]; next = output_queue->head[index]; while (next) { if (next->event_time >= time || @@ -141,8 +142,8 @@ void EVTaccept( } stale = next; next = next->next; - stale->next = output_queue->free[index]; - output_queue->free[index] = stale; + stale->next = *free_list; + *free_list = stale; } output_queue->head[index] = next; if (!next) diff --git a/src/xspice/evt/evtbackup.c b/src/xspice/evt/evtbackup.c index fe1e02784..f857c6816 100644 --- a/src/xspice/evt/evtbackup.c +++ b/src/xspice/evt/evtbackup.c @@ -530,7 +530,7 @@ static void EVTbackup_output_queue( Evt_Output_Queue_t *output_queue; - Evt_Output_Event_t **output_ptr; + Evt_Output_Event_t **output_ptr, **free_list; Evt_Output_Event_t *output; double next_time; @@ -554,12 +554,13 @@ static void EVTbackup_output_queue( output_ptr = output_queue->last_step[output_index]; output = *output_ptr; + free_list = output_queue->free_list[output_index]; while(output) { if(output->posted_time > new_time) { *output_ptr = output->next; - output->next = output_queue->free[output_index]; - output_queue->free[output_index] = output; + output->next = *free_list; + *free_list = output; output = *output_ptr; } else { diff --git a/src/xspice/evt/evtdest.c b/src/xspice/evt/evtdest.c index 454f1a94e..c80367686 100644 --- a/src/xspice/evt/evtdest.c +++ b/src/xspice/evt/evtdest.c @@ -82,18 +82,11 @@ Evt_Queue_destroy(Evt_Ckt_Data_t *evt, Evt_Queue_t *queue) tfree(event); event = next; } - event = output_queue->free[i]; - while (event) { - Evt_Output_Event_t *next = event->next; - tfree(event->value); - tfree(event); - event = next; - } } tfree(output_queue->head); tfree(output_queue->current); tfree(output_queue->last_step); - tfree(output_queue->free); + tfree(output_queue->free_list); tfree(output_queue->modified_index); tfree(output_queue->modified); @@ -101,6 +94,7 @@ Evt_Queue_destroy(Evt_Ckt_Data_t *evt, Evt_Queue_t *queue) tfree(output_queue->pending); tfree(output_queue->changed_index); tfree(output_queue->changed); + Evt_purge_free_outputs(); } /* diff --git a/src/xspice/evt/evtinit.c b/src/xspice/evt/evtinit.c index 1f2b1a041..283c1ea79 100644 --- a/src/xspice/evt/evtinit.c +++ b/src/xspice/evt/evtinit.c @@ -325,7 +325,7 @@ static int EVTinit_queue( 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->free_list, 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) @@ -333,7 +333,6 @@ static int EVTinit_queue( CKALLOC(output_queue->changed_index, num_outputs, int) CKALLOC(output_queue->changed, num_outputs, Mif_Boolean_t) - /* Return */ return(OK); } diff --git a/src/xspice/evt/evtload.c b/src/xspice/evt/evtload.c index f65353743..557eea16d 100644 --- a/src/xspice/evt/evtload.c +++ b/src/xspice/evt/evtload.c @@ -61,20 +61,13 @@ static void EVTadd_msg( int port_index, char *msg_text); -static void EVTcreate_output_event( - CKTcircuit *ckt, - int node_index, - int output_index, - void **value_ptr); +static Evt_Output_Event_t *EVTget_output_event( + CKTcircuit *ckt, + Mif_Port_Data_t *port); static void EVTprocess_output( CKTcircuit *ckt, - Mif_Boolean_t changed, - int output_index, - Mif_Boolean_t invert, - double delay); - - + Mif_Port_Data_t *port); /* EVTload @@ -101,14 +94,10 @@ int EVTload( Mif_Conn_Data_t *conn; Mif_Port_Data_t *port; - - Mif_Private_t cm_data; - + Evt_Node_Data_t *node_data; MIFinstance *inst; - Evt_Node_Data_t *node_data; - - void *value_ptr; + Mif_Private_t cm_data; /* ***************************** */ @@ -191,17 +180,16 @@ int EVTload( port->load = 0.0; port->total_load = node_data->total_load[port->evt_data.node_index]; - /* If connection is an output, initialize changed to true */ - /* and create a new output event object in the free list */ - /* if transient analysis mode */ + /* If connection is an output and transient analysis, + * initialize changed to true and ensure an output location. + */ if(conn->is_output) { port->changed = MIF_TRUE; - if(g_mif_info.circuit.anal_type == MIF_TRAN) { - EVTcreate_output_event(ckt, - port->evt_data.node_index, - port->evt_data.output_index, - &value_ptr); - port->output.pvalue = value_ptr; + if (g_mif_info.circuit.anal_type == MIF_TRAN) { + if (port->next_event == NULL) { + port->next_event = EVTget_output_event(ckt, port); + } + port->output.pvalue = port->next_event->value; } } } @@ -276,9 +264,9 @@ int EVTload( continue; /* If output changed, process it */ - EVTprocess_output(ckt, port->changed, - port->evt_data.output_index, - port->invert, port->delay); + + if (port->changed) + EVTprocess_output(ckt, port); /* And prevent erroneous models from overwriting it during */ /* analog iterations */ @@ -369,43 +357,40 @@ static void EVTcreate_state( /* -EVTcreate_output_event +EVTget_output_event This function creates a new output event. */ -static void EVTcreate_output_event( - CKTcircuit *ckt, /* The circuit structure */ - int node_index, /* The node type port is on */ - int output_index, /* The output index for this port */ - void **value_ptr) /* The event created */ +static Evt_Output_Event_t *EVTget_output_event( + CKTcircuit *ckt, /* The circuit structure */ + Mif_Port_Data_t *port) /* The output port. */ { int udn_index; Evt_Node_Info_t **node_table; Evt_Output_Queue_t *output_queue; - Evt_Output_Event_t *event; + Evt_Output_Event_t *event, **free_list; /* Check the output queue free list and use the structure */ /* at the head of the list if non-null. Otherwise, create a new one. */ + output_queue = &(ckt->evt->queue.output); - if(output_queue->free[output_index]) { - *value_ptr = output_queue->free[output_index]->value; - } - else { + free_list = output_queue->free_list[port->evt_data.output_index]; + if (*free_list) { + event = *free_list; + *free_list = event->next; + } else { /* Create a new event */ event = TMALLOC(Evt_Output_Event_t, 1); event->next = NULL; /* Initialize the value */ node_table = ckt->evt->info.node_table; - udn_index = node_table[node_index]->udn_index; + udn_index = node_table[port->evt_data.node_index]->udn_index; g_evt_udn_info[udn_index]->create (&(event->value)); - - /* Put the event onto the free list and return the value pointer */ - output_queue->free[output_index] = event; - *value_ptr = event->value; } + return event; } @@ -482,16 +467,14 @@ the event is processed immediately. static void EVTprocess_output( - CKTcircuit *ckt, /* The circuit structure */ - Mif_Boolean_t changed, /* Has output changed? */ - int output_index, /* The output of interest */ - Mif_Boolean_t invert, /* Does output need to be inverted? */ - double delay) /* The output delay in transient analysis */ + CKTcircuit *ckt, /* The circuit structure */ + Mif_Port_Data_t *port) { int num_outputs; int node_index; int udn_index; + int output_index; int output_subindex; Evt_Output_Info_t **output_table; @@ -503,33 +486,35 @@ static void EVTprocess_output( Evt_Output_Queue_t *output_queue; Evt_Output_Event_t *output_event; - Mif_Boolean_t equal; - + Mif_Boolean_t invert, equal; + double delay; output_queue = &(ckt->evt->queue.output); output_table = ckt->evt->info.output_table; node_table = ckt->evt->info.node_table; + output_index = port->evt_data.output_index; node_index = output_table[output_index]->node_index; udn_index = node_table[node_index]->udn_index; - + invert = port->invert; /* if transient analysis, just put the output event on the queue */ /* to be processed at a later time */ - if(g_mif_info.circuit.anal_type == MIF_TRAN) { - /* If model signaled that output was not posted, */ - /* leave the event struct on the free list and return */ - if(!changed) - return; + + if (g_mif_info.circuit.anal_type == MIF_TRAN) { + delay = port->delay; if(delay <= 0.0) { printf("\nERROR - Output delay <= 0 not allowed - output ignored!\n"); printf(" Instance: %s\n Node: %s\n Time: %f \n", - g_mif_info.instance->MIFname, node_table[node_index]->name, g_mif_info.ckt->CKTtime); + g_mif_info.instance->MIFname, node_table[node_index]->name, + g_mif_info.ckt->CKTtime); return; } - /* Remove the (now used) struct from the head of the free list */ - output_event = output_queue->free[output_index]; - output_queue->free[output_index] = output_event->next; + /* Remove the (now used) struct from the port data struct. */ + + output_event = port->next_event; + port->next_event = NULL; + /* Invert the output value if necessary */ if(invert) g_evt_udn_info[udn_index]->invert @@ -539,20 +524,11 @@ static void EVTprocess_output( g_mif_info.circuit.evt_step, g_mif_info.circuit.evt_step + delay); return; - } - /* If not transient analysis, process immediately. */ - /* Determine if output has changed from rhsold value */ - /* and put entry in output queue changed list if so */ - else { + } else { + /* If not transient analysis, process immediately. */ + /* Determine if output has changed from rhsold value */ + /* and put entry in output queue changed list if so */ - /* If model signaled that output was not posted, */ - /* just return */ - if(! changed) - return; -/* - if(delay > 0.0) - printf("\nWARNING - Non-zero output delay not allowed in DCOP - delay ignored!\n"); -*/ rhs = ckt->evt->data.node->rhs; rhsold = ckt->evt->data.node->rhsold; diff --git a/src/xspice/evt/evtsetup.c b/src/xspice/evt/evtsetup.c index 606c7959e..761a40bba 100644 --- a/src/xspice/evt/evtsetup.c +++ b/src/xspice/evt/evtsetup.c @@ -183,7 +183,6 @@ static int EVTsetup_queues( Evt_Inst_Event_t *inst_event; Evt_Output_Event_t *output_event; - void *ptr; /* ************************ */ @@ -255,16 +254,9 @@ static int EVTsetup_queues( 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; @@ -274,15 +266,51 @@ static int EVTsetup_queues( 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; - } + if (num_outputs > 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); + if (output_queue->free_list[0]) { + Evt_purge_free_outputs(); + } else { + Evt_Output_Info_t *output_info; + Evt_Node_Info_t *node; + + /* ********************************************************* * + * On first call for this circuit, set the free-list pointer + * for each output queue. + * ********************************************************* */ + + output_info = ckt->evt->info.output_list; + for (i = 0; i < num_outputs; i++) { + node = ckt->evt->info.node_table[output_info->node_index]; + output_queue->free_list[i] = + &g_evt_udn_info[node->udn_index]->free_list; + output_info = output_info->next; + } + } + } + return OK; } +void Evt_purge_free_outputs(void) +{ + Evt_Output_Event_t *output_event, *next; + int i; + + for (i = 0; i < g_evt_num_udn_types; ++i) { + output_event = g_evt_udn_info[i]->free_list; + while (output_event) { + next = output_event->next; + tfree(output_event->value); + tfree(output_event); + output_event = next; + } + } +} /* diff --git a/src/xspice/icm/xtraevt/int/udnfunc.c b/src/xspice/icm/xtraevt/int/udnfunc.c index 8a279f519..4c568d74f 100644 --- a/src/xspice/icm/xtraevt/int/udnfunc.c +++ b/src/xspice/icm/xtraevt/int/udnfunc.c @@ -182,6 +182,7 @@ Evt_Udn_Info_t udn_int_info = { "int", "integer valued data", + NULL, udn_int_create, udn_int_dismantle, diff --git a/src/xspice/icm/xtraevt/real/udnfunc.c b/src/xspice/icm/xtraevt/real/udnfunc.c index baacfad97..c0ba212dd 100644 --- a/src/xspice/icm/xtraevt/real/udnfunc.c +++ b/src/xspice/icm/xtraevt/real/udnfunc.c @@ -183,6 +183,7 @@ Evt_Udn_Info_t udn_real_info = { "real", "real valued data", + NULL, udn_real_create, udn_real_dismantle, diff --git a/src/xspice/idn/idndig.c b/src/xspice/idn/idndig.c index 25870229b..53c21dbad 100644 --- a/src/xspice/idn/idndig.c +++ b/src/xspice/idn/idndig.c @@ -345,6 +345,7 @@ Evt_Udn_Info_t idn_digital_info = { "d", "12 state digital data", +NULL, idn_digital_create, idn_digital_dismantle, idn_digital_initialize,