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