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