1 /*============================================================================
2 FILE    EVTop.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 EVTop which is used to perform an
23     operating point analysis in place of CKTop when there are
24     event-driven instances in the circuit.  It alternates between doing
25     event-driven iterations with EVTiter and doing analog iterations with
26     NIiter/CKTop until no more event-driven outputs change.
27 
28 INTERFACES
29 
30     EVTop()
31 
32 REFERENCED FILES
33 
34     None.
35 
36 NON-STANDARD FEATURES
37 
38     None.
39 
40 ============================================================================*/
41 
42 #include "ngspice/ngspice.h"
43 #include "ngspice/cktdefs.h"
44 //#include "util.h"
45 #include "ngspice/sperror.h"
46 
47 #include "ngspice/mif.h"
48 #include "ngspice/evt.h"
49 #include "ngspice/enh.h"
50 #include "ngspice/evtproto.h"
51 #include "ngspice/evtudn.h"
52 
53 
54 static void EVTnode_compare(
55     CKTcircuit    *ckt,
56     int           node_index,
57     Evt_Node_t    *node1,
58     Evt_Node_t    *node2,
59     Mif_Boolean_t *equal);
60 
61 
62 
63 /*
64 EVTop
65 
66 This function is used to perform an operating point analysis
67 in place of CKTop when there are event-driven instances in the
68 circuit.  It alternates between doing event-driven iterations
69 with EVTiter and doing analog iterations with NIiter/CKTop
70 until no more event-driven outputs change.
71 */
72 
73 
EVTop(CKTcircuit * ckt,long firstmode,long continuemode,int max_iter,Mif_Boolean_t first_call)74 int EVTop(
75     CKTcircuit     *ckt,          /* The circuit structure */
76     long           firstmode,     /* The SPICE 3C1 CKTop() firstmode parameter */
77     long           continuemode,  /* The SPICE 3C1 CKTop() continuemode paramter */
78     int            max_iter,      /* The SPICE 3C1 CKTop() max iteration parameter */
79     Mif_Boolean_t  first_call)    /* Is this the first time through? */
80 {
81 
82     int         i;
83     int         num_insts;
84     int         converged;
85     int         output_index;
86     int         port_index;
87 
88     char        *err_msg;
89 
90     Mif_Boolean_t       firstime;
91 
92     Evt_Inst_Queue_t    *inst_queue;
93     Evt_Output_Queue_t  *output_queue;
94 
95     Evt_Output_Info_t   **output_table;
96     Evt_Port_Info_t     **port_table;
97 
98 
99     /* get data to local storage for fast access */
100     num_insts = ckt->evt->counts.num_insts;
101     inst_queue = &(ckt->evt->queue.inst);
102 
103     /* Initialize to_call entries in event inst queue */
104     /* to force calling all event/hybrid instance the first */
105     /* time through */
106 
107     if(first_call) {
108         for(i = 0; i < num_insts; i++) {
109             inst_queue->to_call[i] = MIF_TRUE;
110             inst_queue->to_call_index[i] = i;
111         }
112         inst_queue->num_to_call = num_insts;
113     }
114 
115 
116     /* Alternate between event-driven and analog solutions until */
117     /* there are no changed event-driven outputs */
118 
119     firstime = MIF_TRUE;
120     for(;;) {
121 
122         /* Call EVTiter to establish initial outputs from */
123         /* event/hybrid instances with states (e.g. flip-flops) */
124 
125         ckt->CKTmode = firstmode;
126         converged = EVTiter(ckt);
127         if(converged != 0)
128             return(converged);
129 
130         /* Now do analog solution for current state of hybrid outputs */
131 
132         /* If first analog solution, call CKTop */
133         if(firstime) {
134             firstime = MIF_FALSE;
135             converged = CKTop(ckt,
136                               firstmode,
137                               continuemode,
138                               max_iter);
139             if(converged != 0)
140                 return(converged);
141         }
142         /* Otherwise attempt to converge with mode = continuemode */
143         else {
144             ckt->CKTmode = continuemode;
145             converged = NIiter(ckt,max_iter);
146             if(converged != 0) {
147                 converged = CKTop(ckt,
148                               firstmode,
149                               continuemode,
150                               max_iter);
151                 if(converged != 0)
152                     return(converged);
153             }
154         }
155 
156         /* Call all hybrids to allow new event outputs to be posted */
157         EVTcall_hybrids(ckt);
158 
159         /* Increment count of successful alternations */
160         (ckt->evt->data.statistics->op_alternations)++;
161 
162         /* If .option card specified not to alternate solutions, exit */
163         /* immediately with this first pass solution */
164         if(! ckt->evt->options.op_alternate)
165             return(0);
166 
167         /* If no hybrid instances produced different event outputs, */
168         /* alternation is completed, so exit */
169         if(ckt->evt->queue.output.num_changed == 0)
170             return(0);
171 
172         /* If too many alternations, exit with error */
173         if(ckt->evt->data.statistics->op_alternations >=
174                 ckt->evt->limits.max_op_alternations) {
175 
176             SPfrontEnd->IFerrorf (ERR_WARNING,
177                 "Too many analog/event-driven solution alternations");
178 
179             err_msg = TMALLOC(char, 10000);
180             output_queue = &(ckt->evt->queue.output);
181             output_table = ckt->evt->info.output_table;
182             port_table = ckt->evt->info.port_table;
183 
184             for(i = 0; i < output_queue->num_changed; i++) {
185                 output_index = output_queue->changed_index[i];
186                 port_index = output_table[output_index]->port_index;
187                 sprintf(err_msg, "\n    Instance: %s\n    Connection: %s\n    Port: %d",
188                         port_table[port_index]->inst_name,
189                         port_table[port_index]->conn_name,
190                         port_table[port_index]->port_num);
191                 ENHreport_conv_prob(ENH_EVENT_NODE,
192                                     port_table[port_index]->node_name,
193                                     err_msg);
194             }
195             FREE(err_msg);
196 
197             return(E_ITERLIM);
198         }
199 
200     } /* end forever */
201 }
202 
203 
204 
205 /*
206 EVTop_save
207 
208 Save result from operating point iteration into the node data area.
209 */
210 
EVTop_save(CKTcircuit * ckt,Mif_Boolean_t op,double step)211 void EVTop_save(
212     CKTcircuit    *ckt,  /* The circuit structure */
213     Mif_Boolean_t op,    /* True if from a DCOP analysis, false if TRANOP, etc. */
214     double        step)
215 {
216 
217     int         i;
218     int         num_nodes;
219 
220     Mif_Boolean_t       equal;
221 
222     Evt_Node_Data_t     *node_data;
223 
224     Evt_Node_t          *rhsold;
225     Evt_Node_t          **head;
226     Evt_Node_t          **here;
227 
228     /*	char buff[128];*/
229 
230 
231     /* Get pointers for fast access */
232     node_data = ckt->evt->data.node;
233     rhsold = node_data->rhsold;
234     head = node_data->head;
235 
236     /* For number of event nodes, copy rhsold to node data */
237     /* and set the op member if appropriate */
238     num_nodes = ckt->evt->counts.num_nodes;
239 
240     for(i = 0; i < num_nodes; i++)
241 	{
242         /* if head is null, just copy there */
243         if(head[i] == NULL)
244 		{
245             EVTnode_copy(ckt, i, &(rhsold[i]), &(head[i]));
246 
247             head[i]->op = op;
248             head[i]->step = step;
249 
250         }
251         /* Otherwise, add to the end of the list */
252         else
253 		{
254             /* Locate end of list */
255             here = &(head[i]);
256             for(;;)
257 			{
258                 if((*here)->next)
259                     here = &((*here)->next);
260                 else
261                     break;
262             }
263             /* Compare entry at end of list to rhsold */
264 
265             EVTnode_compare(ckt, i, &(rhsold[i]), *here, &equal);
266 
267             /* If new value in rhsold is different, add it to the list */
268             if(!equal)
269 			{
270                 here = &((*here)->next);
271                 EVTnode_copy(ckt, i, &(rhsold[i]), here);
272                 (*here)->op = op;
273                 (*here)->step = step;
274             }
275         } /* end else add to end of list */
276     }  /* end for number of nodes */
277 
278 }
279 
280 
281 
282 /* ************************************************************ */
283 
284 
285 /*
286 EVTnode_compare
287 
288 This function compares the resolved values of the old and
289 new states on a node.  The actual comparison is done by
290 calling the appropriate user-defined node compare function.
291 */
292 
293 
EVTnode_compare(CKTcircuit * ckt,int node_index,Evt_Node_t * node1,Evt_Node_t * node2,Mif_Boolean_t * equal)294 static void EVTnode_compare(
295     CKTcircuit    *ckt,        /* The circuit structure */
296     int           node_index,  /* The index for the node in question */
297     Evt_Node_t    *node1,      /* The first value */
298     Evt_Node_t    *node2,      /* The second value */
299     Mif_Boolean_t *equal)      /* The computed result */
300 {
301 
302     Evt_Node_Data_t     *node_data;
303     Evt_Node_Info_t     **node_table;
304 
305     int                 udn_index;
306 
307 
308     /* Get data for fast access */
309     node_data = ckt->evt->data.node;
310     node_table = ckt->evt->info.node_table;
311     udn_index = node_table[node_index]->udn_index;
312 
313 
314     /* Do compare based on changes in resolved node value only */
315     g_evt_udn_info[udn_index]->compare (
316             node1->node_value,
317             node2->node_value,
318             equal);
319 }
320