1 /*============================================================================
2 FILE    EVTload.c
3 
4 MEMBER OF process XSPICE
5 
6 Public Domain
7 
8 Georgia Tech Research Corporation
9 Atlanta, Georgia 30332
10 PROJECT A-8503
11 
12 AUTHORS
13 
14     9/12/91  Bill Kuhn
15 
16 MODIFICATIONS
17 
18     <date> <person name> <nature of modifications>
19 
20 SUMMARY
21 
22     This file contains function EVTload which is used to call a
23     specified event-driven or hybrid code model during an event-driven
24     iteration.  The 'CALL_TYPE' is set to 'EVENT_DRIVEN' when the
25     model is called from this function.
26 
27 INTERFACES
28 
29     int EVTload(CKTcircuit *ckt, int inst_index)
30 
31 REFERENCED FILES
32 
33     None.
34 
35 NON-STANDARD FEATURES
36 
37     None.
38 
39 ============================================================================*/
40 
41 #include "ngspice/ngspice.h"
42 #include "ngspice/cktdefs.h"
43 //#include "util.h"
44 #include "ngspice/devdefs.h"
45 #include "ngspice/sperror.h"
46 
47 #include "ngspice/mif.h"
48 #include "ngspice/evt.h"
49 #include "ngspice/evtudn.h"
50 
51 #include "ngspice/mifproto.h"
52 #include "ngspice/evtproto.h"
53 
54 
55 static void EVTcreate_state(
56     CKTcircuit  *ckt,
57     int         inst_index);
58 
59 static void EVTadd_msg(
60     CKTcircuit  *ckt,
61     int         port_index,
62     char        *msg_text);
63 
64 static void EVTcreate_output_event(
65     CKTcircuit  *ckt,
66     int         node_index,
67     int         output_index,
68     void        **value_ptr);
69 
70 static void EVTprocess_output(
71     CKTcircuit          *ckt,
72     Mif_Boolean_t       changed,
73     int                 output_index,
74     Mif_Boolean_t       invert,
75     double              delay);
76 
77 
78 
79 /*
80 EVTload
81 
82 This function calls the code model function for the specified
83 instance with CALL_TYPE set to EVENT_DRIVEN.  Event outputs,
84 messages, etc. are processed on return from the code model.
85 Analog outputs, partials, etc. should not be computed by the
86 code model when the call type is event-driven and are
87 ignored.
88 */
89 
EVTload(CKTcircuit * ckt,int inst_index)90 int EVTload(
91     CKTcircuit *ckt,        /* The circuit structure */
92     int        inst_index)  /* The instance to call code model for */
93 {
94 
95     int                 i;
96     int                 j;
97 
98     int                 num_conn;
99     int                 num_port;
100     int                 mod_type;
101 
102     Mif_Conn_Data_t     *conn;
103     Mif_Port_Data_t     *port;
104 
105     Mif_Private_t       cm_data;
106 
107     MIFinstance         *inst;
108 
109     Evt_Node_Data_t     *node_data;
110 
111     void                *value_ptr;
112 
113 
114     /* ***************************** */
115     /* Prepare the code model inputs */
116     /* ***************************** */
117 
118     /* Get pointer to instance data structure and other data */
119     /* needed for fast access */
120     inst = ckt->evt->info.inst_table[inst_index]->inst_ptr;
121     node_data = ckt->evt->data.node;
122 
123     /* Setup circuit data in struct to be passed to code model function */
124 
125     if(inst->initialized)
126         cm_data.circuit.init = MIF_FALSE;
127     else
128         cm_data.circuit.init = MIF_TRUE;
129 
130     cm_data.circuit.anal_init = MIF_FALSE;
131     cm_data.circuit.anal_type = g_mif_info.circuit.anal_type;
132 
133     if(g_mif_info.circuit.anal_type == MIF_TRAN)
134         cm_data.circuit.time = g_mif_info.circuit.evt_step;
135     else
136         cm_data.circuit.time = 0.0;
137 
138     cm_data.circuit.call_type = MIF_EVENT_DRIVEN;
139     cm_data.circuit.temperature = ckt->CKTtemp - 273.15;
140 
141 
142     /* Setup data needed by cm_... functions */
143 
144     g_mif_info.ckt = ckt;
145     g_mif_info.instance = inst;
146     g_mif_info.errmsg = "";
147     g_mif_info.circuit.call_type = MIF_EVENT_DRIVEN;
148 
149     if(inst->initialized)
150         g_mif_info.circuit.init = MIF_FALSE;
151     else
152         g_mif_info.circuit.init = MIF_TRUE;
153 
154 
155     /* If after initialization and in transient analysis mode */
156     /* create a new state for the instance */
157 
158     if((g_mif_info.circuit.anal_type == MIF_TRAN) && inst->initialized)
159         EVTcreate_state(ckt, inst_index);
160 
161 
162     /* Loop through all connections on the instance and setup */
163     /* load, total_load, and msg on all ports, and changed flag */
164     /* and output pointer on all outputs */
165 
166     num_conn = inst->num_conn;
167     for(i = 0; i < num_conn; i++) {
168 
169         conn = inst->conn[i];
170 
171         /* if connection is null, continue to next */
172         if(conn->is_null)
173             continue;
174 
175         /* Loop through each port on the connection */
176         num_port = conn->size;
177         for(j = 0; j < num_port; j++) {
178 
179             port = conn->port[j];
180 
181             /* Skip if port is null */
182             if(port->is_null)
183                 continue;
184 
185             /* If port type is Digital or User-Defined */
186             if((port->type == MIF_DIGITAL) || (port->type == MIF_USER_DEFINED)) {
187 
188                 /* Initialize the msg pointer on the port to NULL, */
189                 /* initialize the load value to zero, and get the total load */
190                 port->msg = NULL;
191                 port->load = 0.0;
192                 port->total_load = node_data->total_load[port->evt_data.node_index];
193 
194                 /* If connection is an output, initialize changed to true */
195                 /* and create a new output event object in the free list */
196                 /* if transient analysis mode */
197                 if(conn->is_output) {
198                     port->changed = MIF_TRUE;
199                     if(g_mif_info.circuit.anal_type == MIF_TRAN) {
200                         EVTcreate_output_event(ckt,
201                                          port->evt_data.node_index,
202                                          port->evt_data.output_index,
203                                          &value_ptr);
204                         port->output.pvalue = value_ptr;
205                     }
206                 }
207             }
208             else {
209                 /* Get the analog input value.  All we need to do is */
210                 /* set it to zero if mode is INITJCT.  Otherwise, value */
211                 /* should still be around from last successful analog call */
212                 if(ckt->CKTmode & MODEINITJCT)
213                     port->input.rvalue = 0.0;
214             }
215 
216         } /* end for number of ports */
217     } /* end for number of connections */
218 
219 
220     /* Prepare the structure to be passed to the code model */
221     cm_data.num_conn = inst->num_conn;
222     cm_data.conn = inst->conn;
223     cm_data.num_param = inst->num_param;
224     cm_data.param = inst->param;
225     cm_data.num_inst_var = inst->num_inst_var;
226     cm_data.inst_var = inst->inst_var;
227     cm_data.callback = &(inst->callback);
228 
229 
230     /* ******************* */
231     /* Call the code model */
232     /* ******************* */
233 
234     mod_type = MIFmodPtr(inst)->MIFmodType;
235     DEVices[mod_type]->DEVpublic.cm_func (&cm_data);
236 
237 
238     /* ****************************** */
239     /* Process the code model outputs */
240     /* ****************************** */
241 
242     /* Loop through all connections and ports and process the msgs */
243     /* and event outputs */
244 
245     num_conn = inst->num_conn;
246     for(i = 0; i < num_conn; i++) {
247 
248         conn = inst->conn[i];
249         if(conn->is_null)
250             continue;
251 
252         /* Loop through each port on the connection */
253         num_port = conn->size;
254         for(j = 0; j < num_port; j++) {
255 
256             port = conn->port[j];
257 
258             /* Skip if port is null */
259             if(port->is_null)
260                 continue;
261 
262             /* Process the message if any */
263             if(port->msg)
264                 EVTadd_msg(ckt, port->evt_data.port_index, port->msg);
265 
266             /* If this is the initialization pass, process the load factor */
267             if(! inst->initialized) {
268                 node_data->total_load[port->evt_data.node_index] +=
269                         port->load;
270             }
271 
272             /* If connection is not an event output, continue to next port */
273             if(! conn->is_output)
274                 continue;
275             if((port->type != MIF_DIGITAL) && (port->type != MIF_USER_DEFINED))
276                 continue;
277 
278             /* If output changed, process it */
279             EVTprocess_output(ckt, port->changed,
280                                    port->evt_data.output_index,
281                                    port->invert, port->delay);
282 
283             /* And prevent erroneous models from overwriting it during */
284             /* analog iterations */
285             if(g_mif_info.circuit.anal_type == MIF_TRAN)
286                 port->output.pvalue = NULL;
287 
288         } /* end for number of ports */
289     } /* end for number of connections */
290 
291 
292     /* Record statistics */
293     if(g_mif_info.circuit.anal_type == MIF_DC)
294         (ckt->evt->data.statistics->op_load_calls)++;
295     else if(g_mif_info.circuit.anal_type == MIF_TRAN)
296         (ckt->evt->data.statistics->tran_load_calls)++;
297 
298     /* Mark that the instance has been called once */
299     inst->initialized = MIF_TRUE;
300 
301     return(OK);
302 }
303 
304 
305 
306 /*
307 EVTcreate_state
308 
309 This function creates a new state storage area for a particular instance
310 during an event-driven simulation.  New states must be created so
311 that old states are saved and can be accessed by code models in the
312 future.  The new state is initialized to the previous state value.
313 */
314 
315 
EVTcreate_state(CKTcircuit * ckt,int inst_index)316 static void EVTcreate_state(
317     CKTcircuit  *ckt,         /* The circuit structure */
318     int         inst_index)   /* The instance to create state for */
319 {
320     size_t              total_size;
321 
322     Evt_State_Data_t    *state_data;
323 
324     Evt_State_t         *new_state;
325     Evt_State_t         *prev_state;
326 
327     /* Get variables for fast access */
328     state_data = ckt->evt->data.state;
329 
330     /* Exit immediately if no states on this instance */
331     if(state_data->desc[inst_index] == NULL)
332         return;
333 
334     /* Get size of state block to be allocated */
335     total_size = (size_t) state_data->total_size[inst_index];
336 
337     /* Allocate a new state for the instance */
338     if(state_data->free[inst_index])
339 	{
340         new_state = state_data->free[inst_index];
341         state_data->free[inst_index] = new_state->next;
342         new_state->next = NULL; // reusing dirty memory: next must be reset
343     }
344     else
345 	{
346 
347         new_state = TMALLOC(Evt_State_t, 1);
348         new_state->block = tmalloc(total_size);
349 
350     }
351 
352     /* Splice the new state into the state data linked list */
353     /* and update the tail pointer */
354     prev_state = *(state_data->tail[inst_index]);
355     prev_state->next = new_state;
356     new_state->prev = prev_state;
357     state_data->tail[inst_index] = &(prev_state->next);
358 
359     /* Copy the old state to the new state and set the step */
360     memcpy(new_state->block, prev_state->block, total_size);
361     new_state->step = g_mif_info.circuit.evt_step;
362 
363     /* Mark that the state data on the instance has been modified */
364     if(! state_data->modified[inst_index]) {
365         state_data->modified[inst_index] = MIF_TRUE;
366         state_data->modified_index[(state_data->num_modified)++] = inst_index;
367     }
368 }
369 
370 
371 /*
372 EVTcreate_output_event
373 
374 This function creates a new output event.
375 */
376 
EVTcreate_output_event(CKTcircuit * ckt,int node_index,int output_index,void ** value_ptr)377 static void EVTcreate_output_event(
378     CKTcircuit  *ckt,           /* The circuit structure */
379     int         node_index,     /* The node type port is on */
380     int         output_index,   /* The output index for this port */
381     void        **value_ptr)    /* The event created */
382 {
383     int                 udn_index;
384     Evt_Node_Info_t     **node_table;
385     Evt_Output_Queue_t  *output_queue;
386     Evt_Output_Event_t  *event;
387 
388 
389     /* Check the output queue free list and use the structure */
390     /* at the head of the list if non-null.  Otherwise, create a new one. */
391     output_queue = &(ckt->evt->queue.output);
392     if(output_queue->free[output_index]) {
393         *value_ptr = output_queue->free[output_index]->value;
394     }
395     else {
396         /* Create a new event */
397         event = TMALLOC(Evt_Output_Event_t, 1);
398         event->next = NULL;
399 
400         /* Initialize the value */
401         node_table = ckt->evt->info.node_table;
402         udn_index = node_table[node_index]->udn_index;
403         g_evt_udn_info[udn_index]->create (&(event->value));
404 
405         /* Put the event onto the free list and return the value pointer */
406         output_queue->free[output_index] = event;
407         *value_ptr = event->value;
408     }
409 }
410 
411 
412 
413 /*
414 EVTadd_msg
415 
416 This function records a message output by a code model into the
417 message results data structure.
418 */
419 
420 
EVTadd_msg(CKTcircuit * ckt,int port_index,char * msg_text)421 static void EVTadd_msg(
422     CKTcircuit  *ckt,          /* The circuit structure */
423     int         port_index,    /* The port to add message to */
424     char        *msg_text)     /* The message text */
425 {
426 
427     Evt_Msg_Data_t      *msg_data;
428 
429     Evt_Msg_t           **msg_ptr;
430     Evt_Msg_t           *msg;
431 
432 
433     /* Get pointers for fast access */
434     msg_data = ckt->evt->data.msg;
435     msg_ptr = msg_data->tail[port_index];
436 
437     /* Set pointer to location at which to add, and update tail */
438     if(*msg_ptr != NULL) {
439         msg_ptr = &((*msg_ptr)->next);
440         msg_data->tail[port_index] = msg_ptr;
441     }
442 
443     /* Add a new entry in the list of messages for this port */
444     if(msg_data->free[port_index]) {
445         *msg_ptr = msg_data->free[port_index];
446         msg_data->free[port_index] = msg_data->free[port_index]->next;
447         if ((*msg_ptr)->text)
448             tfree((*msg_ptr)->text);
449     }
450     else {
451         *msg_ptr = TMALLOC(Evt_Msg_t, 1);
452     }
453 
454     /* Fill in the values */
455     msg = *msg_ptr;
456     msg->next = NULL;
457     if((ckt->CKTmode & MODEDCOP) == MODEDCOP)
458         msg->op = MIF_TRUE;
459     else
460         msg->step = g_mif_info.circuit.evt_step;
461     msg->text = MIFcopy(msg_text);
462 
463     /* Update the modified indexes */
464     if(g_mif_info.circuit.anal_type == MIF_TRAN) {
465         if(! msg_data->modified[port_index]) {
466             msg_data->modified[port_index] = MIF_TRUE;
467             msg_data->modified_index[(msg_data->num_modified)++] = port_index;
468         }
469     }
470 
471 }
472 
473 
474 /*
475 EVTprocess_output
476 
477 This function processes an event-driven output produced by a code
478 model.  If transient analysis mode, the event is placed into the
479 output queue according to its (non-zero) delay.  If DC analysis,
480 the event is processed immediately.
481 */
482 
483 
EVTprocess_output(CKTcircuit * ckt,Mif_Boolean_t changed,int output_index,Mif_Boolean_t invert,double delay)484 static void EVTprocess_output(
485     CKTcircuit     *ckt,          /* The circuit structure */
486     Mif_Boolean_t  changed,       /* Has output changed? */
487     int            output_index,  /* The output of interest */
488     Mif_Boolean_t  invert,        /* Does output need to be inverted? */
489     double         delay)         /* The output delay in transient analysis */
490 {
491 
492     int                 num_outputs;
493     int                 node_index;
494     int                 udn_index;
495     int                 output_subindex;
496 
497     Evt_Output_Info_t   **output_table;
498     Evt_Node_Info_t     **node_table;
499 
500     Evt_Node_t          *rhs;
501     Evt_Node_t          *rhsold;
502 
503     Evt_Output_Queue_t  *output_queue;
504     Evt_Output_Event_t  *output_event;
505 
506     Mif_Boolean_t       equal;
507 
508 
509     output_queue = &(ckt->evt->queue.output);
510     output_table = ckt->evt->info.output_table;
511     node_table = ckt->evt->info.node_table;
512 
513     node_index = output_table[output_index]->node_index;
514     udn_index = node_table[node_index]->udn_index;
515 
516 
517     /* if transient analysis, just put the output event on the queue */
518     /* to be processed at a later time */
519     if(g_mif_info.circuit.anal_type == MIF_TRAN) {
520         /* If model signaled that output was not posted, */
521         /* leave the event struct on the free list and return */
522         if(!changed)
523             return;
524         if(delay <= 0.0) {
525             printf("\nERROR - Output delay <= 0 not allowed - output ignored!\n");
526             printf("  Instance: %s\n  Node: %s\n  Time: %f \n",
527                     g_mif_info.instance->MIFname, node_table[node_index]->name, g_mif_info.ckt->CKTtime);
528             return;
529         }
530         /* Remove the (now used) struct from the head of the free list */
531         output_event = output_queue->free[output_index];
532         output_queue->free[output_index] = output_event->next;
533         /* Invert the output value if necessary */
534         if(invert)
535             g_evt_udn_info[udn_index]->invert
536                 (output_event->value);
537         /* Add it to the queue */
538         EVTqueue_output(ckt, output_index, udn_index, output_event,
539                         g_mif_info.circuit.evt_step,
540                         g_mif_info.circuit.evt_step + delay);
541         return;
542     }
543     /* If not transient analysis, process immediately. */
544     /* Determine if output has changed from rhsold value */
545     /* and put entry in output queue changed list if so */
546     else {
547 
548         /* If model signaled that output was not posted, */
549         /* just return */
550         if(! changed)
551             return;
552 /*
553         if(delay > 0.0)
554             printf("\nWARNING - Non-zero output delay not allowed in DCOP - delay ignored!\n");
555 */
556         rhs = ckt->evt->data.node->rhs;
557         rhsold = ckt->evt->data.node->rhsold;
558 
559         /* Determine if changed */
560         num_outputs = node_table[node_index]->num_outputs;
561         if(num_outputs > 1) {
562             output_subindex = output_table[output_index]->output_subindex;
563             if(invert)
564                 g_evt_udn_info[udn_index]->invert
565                     (rhs[node_index].output_value[output_subindex]);
566             g_evt_udn_info[udn_index]->compare
567                     (rhs[node_index].output_value[output_subindex],
568                     rhsold[node_index].output_value[output_subindex],
569                     &equal);
570             if(! equal) {
571                 g_evt_udn_info[udn_index]->copy
572                     (rhs[node_index].output_value[output_subindex],
573                     rhsold[node_index].output_value[output_subindex]);
574             }
575         }
576         else {
577             if(invert)
578                 g_evt_udn_info[udn_index]->invert
579                     (rhs[node_index].node_value);
580             g_evt_udn_info[udn_index]->compare
581                     (rhs[node_index].node_value,
582                     rhsold[node_index].node_value,
583                     &equal);
584             if(! equal) {
585                 g_evt_udn_info[udn_index]->copy
586                     (rhs[node_index].node_value,
587                     rhsold[node_index].node_value);
588             }
589         }
590 
591         /* If changed, put in changed list of output queue */
592         if(! equal) {
593             if(! output_queue->changed[output_index]) {
594                 output_queue->changed[output_index] = MIF_TRUE;
595                 output_queue->changed_index[(output_queue->num_changed)++] =
596                         output_index;
597             }
598         }
599 
600         return;
601 
602     } /* end else process immediately */
603 }
604