1 | /**CFile*********************************************************************** |
---|
2 | |
---|
3 | FileName [ioCheck.c] |
---|
4 | |
---|
5 | PackageName [io] |
---|
6 | |
---|
7 | Synopsis [Routines to test if a blif-mv file is consistent.] |
---|
8 | |
---|
9 | Description [Routines to test if a blif-mv file is consistent. They are |
---|
10 | also responsible for setting several internal data structures. Here are |
---|
11 | the list of checks we can do on an hsis network. For each model, we first |
---|
12 | check if there is no node labeled both as PI and PS or both as PI and PO. |
---|
13 | Then, for each subcircuit in the model, the compatibllity of the interface |
---|
14 | is verified namewise and rangewise. This is detailed below. Then, |
---|
15 | we verify that there is no combinational cycle in any model. Furthermore, |
---|
16 | for each latch in the model, we make sure that the input and the output |
---|
17 | of the latch are of the same type and that every latch has a reset table. |
---|
18 | Finally, we check to see if each variable is an output of at |
---|
19 | most one table. As for the check to be done for a subcircuit, we first check |
---|
20 | if the model to be instantiated is present in the hmanager. Then, we |
---|
21 | test if all the formal variables in the subcircuit definition exist |
---|
22 | in the model and at the same time they are of the same type of the |
---|
23 | corresponding actual variables. More thoroughly, we have to check |
---|
24 | if a flattened network has no cycle, but it is not currently implemented.] |
---|
25 | |
---|
26 | SeeAlso [] |
---|
27 | |
---|
28 | Author [Yuji Kukimoto, Rajeev Ranjan, Huey-Yih Wang] |
---|
29 | |
---|
30 | Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. |
---|
31 | All rights reserved. |
---|
32 | |
---|
33 | Permission is hereby granted, without written agreement and without license |
---|
34 | or royalty fees, to use, copy, modify, and distribute this software and its |
---|
35 | documentation for any purpose, provided that the above copyright notice and |
---|
36 | the following two paragraphs appear in all copies of this software. |
---|
37 | |
---|
38 | IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR |
---|
39 | DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT |
---|
40 | OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF |
---|
41 | CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
42 | |
---|
43 | THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, |
---|
44 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
---|
45 | FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN |
---|
46 | "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE |
---|
47 | MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] |
---|
48 | |
---|
49 | ******************************************************************************/ |
---|
50 | |
---|
51 | #include "ioInt.h" |
---|
52 | |
---|
53 | static char rcsid[] UNUSED = "$Id: ioCheck.c,v 1.11 2005/04/16 06:17:45 fabio Exp $"; |
---|
54 | |
---|
55 | /*---------------------------------------------------------------------------*/ |
---|
56 | /* Constant declarations */ |
---|
57 | /*---------------------------------------------------------------------------*/ |
---|
58 | |
---|
59 | |
---|
60 | /*---------------------------------------------------------------------------*/ |
---|
61 | /* Type declarations */ |
---|
62 | /*---------------------------------------------------------------------------*/ |
---|
63 | |
---|
64 | |
---|
65 | /*---------------------------------------------------------------------------*/ |
---|
66 | /* Stucture declarations */ |
---|
67 | /*---------------------------------------------------------------------------*/ |
---|
68 | |
---|
69 | |
---|
70 | /*---------------------------------------------------------------------------*/ |
---|
71 | /* Variable declarations */ |
---|
72 | /*---------------------------------------------------------------------------*/ |
---|
73 | |
---|
74 | |
---|
75 | /*---------------------------------------------------------------------------*/ |
---|
76 | /* Macro declarations */ |
---|
77 | /*---------------------------------------------------------------------------*/ |
---|
78 | |
---|
79 | |
---|
80 | /**AutomaticStart*************************************************************/ |
---|
81 | |
---|
82 | /*---------------------------------------------------------------------------*/ |
---|
83 | /* Static function prototypes */ |
---|
84 | /*---------------------------------------------------------------------------*/ |
---|
85 | |
---|
86 | static boolean _IoModelTestMasterNodeConsistency(Hrc_Model_t *model, Hrc_Node_t *hnode); |
---|
87 | static boolean _IoModelTestConnectionConsistency(Hrc_Manager_t *hmgr, Hrc_Model_t *model, Hrc_Node_t *hnode, array_t *subcktArray); |
---|
88 | static boolean _IoModelTestLatchConsistency(Hrc_Node_t *hnode); |
---|
89 | static boolean _IoModelTestResetConsistency(Hrc_Manager_t *hmgr, Hrc_Model_t *model, Hrc_Node_t *hnode, array_t *resetArray); |
---|
90 | static boolean _IoModelTestInternalConnectionConsistency(Hrc_Model_t *model, Hrc_Node_t *hnode, boolean isVerbose); |
---|
91 | static boolean _IoModelTestIsAcyclic(Hrc_Model_t *model, Hrc_Node_t *hnode, st_table *varToTable, st_table *outputVarToSubckt, st_table *visitTable); |
---|
92 | static void _IoModelTestIsAcyclicError(Hrc_Model_t *model, Var_Variable_t *var); |
---|
93 | static int _IoModelTestIsAcyclicRecursive(Hrc_Model_t *model, Hrc_Node_t *hnode, Var_Variable_t *var, st_table *varToTable, st_table *outputVarToSubckt, st_table *visitTable, boolean isResetLogic); |
---|
94 | |
---|
95 | /**AutomaticEnd***************************************************************/ |
---|
96 | |
---|
97 | |
---|
98 | /*---------------------------------------------------------------------------*/ |
---|
99 | /* Definition of exported functions */ |
---|
100 | /*---------------------------------------------------------------------------*/ |
---|
101 | |
---|
102 | |
---|
103 | /*---------------------------------------------------------------------------*/ |
---|
104 | /* Definition of internal functions */ |
---|
105 | /*---------------------------------------------------------------------------*/ |
---|
106 | |
---|
107 | /**Function******************************************************************** |
---|
108 | |
---|
109 | Synopsis [Checks to see if a given blif-mv network is consistent.] |
---|
110 | |
---|
111 | Description [] |
---|
112 | |
---|
113 | SideEffects [] |
---|
114 | |
---|
115 | SeeAlso [] |
---|
116 | |
---|
117 | ******************************************************************************/ |
---|
118 | boolean |
---|
119 | IoNetworkTestConsistency( |
---|
120 | Hrc_Manager_t *hmgr, |
---|
121 | array_t *modelArray, |
---|
122 | st_table *parserSubcktInfo, |
---|
123 | st_table *parserResetInfo, |
---|
124 | boolean isVerbose) |
---|
125 | { |
---|
126 | char *subcktArray, *resetArray; |
---|
127 | Hrc_Model_t *model; |
---|
128 | Hrc_Node_t *hnode; |
---|
129 | int i; |
---|
130 | |
---|
131 | for (i=0; i < array_n(modelArray); i++){ |
---|
132 | model = array_fetch(Hrc_Model_t *,modelArray,i); |
---|
133 | |
---|
134 | hnode = Hrc_ModelReadMasterNode(model); |
---|
135 | |
---|
136 | if (_IoModelTestMasterNodeConsistency(model,hnode) == 0){ |
---|
137 | return 0; |
---|
138 | } |
---|
139 | /* the following st_lookup should return 1 */ |
---|
140 | (void)st_lookup(parserSubcktInfo,(char *)model,&subcktArray); |
---|
141 | if ((array_t *)subcktArray != NIL(array_t)){ |
---|
142 | if (_IoModelTestConnectionConsistency(hmgr,model,hnode,(array_t *)subcktArray) == 0){ |
---|
143 | return 0; |
---|
144 | } |
---|
145 | } |
---|
146 | /* the following st_lookup should return 1 */ |
---|
147 | (void)st_lookup(parserResetInfo,(char *)model,&resetArray); |
---|
148 | if ((array_t *)resetArray != NIL(array_t)){ |
---|
149 | if (_IoModelTestResetConsistency(hmgr,model,hnode,(array_t *)resetArray) == 0){ |
---|
150 | return 0; |
---|
151 | } |
---|
152 | } |
---|
153 | if (_IoModelTestLatchConsistency(hnode) == 0){ |
---|
154 | return 0; |
---|
155 | } |
---|
156 | if (_IoModelTestInternalConnectionConsistency(model,hnode,isVerbose) == 0){ |
---|
157 | return 0; |
---|
158 | } |
---|
159 | } |
---|
160 | return 1; |
---|
161 | } |
---|
162 | |
---|
163 | /*---------------------------------------------------------------------------*/ |
---|
164 | /* Definition of static functions */ |
---|
165 | /*---------------------------------------------------------------------------*/ |
---|
166 | |
---|
167 | /**Function******************************************************************** |
---|
168 | |
---|
169 | Synopsis [Checks to see if there is no inconsistency in a model.] |
---|
170 | |
---|
171 | Description [] |
---|
172 | |
---|
173 | SideEffects [] |
---|
174 | |
---|
175 | SeeAlso [] |
---|
176 | |
---|
177 | ******************************************************************************/ |
---|
178 | static boolean |
---|
179 | _IoModelTestMasterNodeConsistency( |
---|
180 | Hrc_Model_t *model, |
---|
181 | Hrc_Node_t *hnode) |
---|
182 | { |
---|
183 | char *varName; |
---|
184 | Var_Variable_t *var; |
---|
185 | st_generator *gen; |
---|
186 | |
---|
187 | Hrc_NodeForEachVariable(hnode,gen,varName,var){ |
---|
188 | if (Var_VariableTestTypeConsistency(var) == 0){ |
---|
189 | st_free_gen(gen); |
---|
190 | return 0; |
---|
191 | } |
---|
192 | } |
---|
193 | return 1; |
---|
194 | } |
---|
195 | |
---|
196 | /**Function******************************************************************** |
---|
197 | |
---|
198 | Synopsis [Checks to see if there is no inconsistency in subcircuit connections.] |
---|
199 | |
---|
200 | Description [] |
---|
201 | |
---|
202 | SideEffects [] |
---|
203 | |
---|
204 | SeeAlso [] |
---|
205 | |
---|
206 | ******************************************************************************/ |
---|
207 | static boolean |
---|
208 | _IoModelTestConnectionConsistency( |
---|
209 | Hrc_Manager_t *hmgr, |
---|
210 | Hrc_Model_t *model, |
---|
211 | Hrc_Node_t *hnode, |
---|
212 | array_t *subcktArray) |
---|
213 | { |
---|
214 | int i, j; |
---|
215 | IoSubckt_t *subckt; |
---|
216 | char *nameOfSubcktModel, *instanceName, *formalName, *actualName, *actualPort; |
---|
217 | Hrc_Model_t *subcktModel; |
---|
218 | Hrc_Node_t *subcktHnode; |
---|
219 | st_table *tmpTable; |
---|
220 | st_table *outputCheckTable; |
---|
221 | array_t *formalNameArray, *actualNameArray, *actualInputArray, *actualOutputArray; |
---|
222 | Var_Variable_t *port, *var; |
---|
223 | |
---|
224 | for (i=0; i < array_n(subcktArray); i++){ |
---|
225 | subckt = array_fetch(IoSubckt_t *,subcktArray,i); |
---|
226 | nameOfSubcktModel = subckt->modelName; |
---|
227 | if ((subcktModel = Hrc_ManagerFindModelByName(hmgr,nameOfSubcktModel)) == NIL(Hrc_Model_t)){ |
---|
228 | error_append("Error: Model "); |
---|
229 | error_append(Hrc_ModelReadName(model)); |
---|
230 | error_append(" has a subcircuit whose model "); |
---|
231 | error_append(nameOfSubcktModel); |
---|
232 | error_append(" is not defined.\n"); |
---|
233 | return 0; |
---|
234 | } |
---|
235 | |
---|
236 | subcktHnode = Hrc_ModelReadMasterNode(subcktModel); |
---|
237 | instanceName = subckt->instanceName; |
---|
238 | formalNameArray = subckt->formalNameArray; |
---|
239 | actualNameArray = subckt->actualNameArray; |
---|
240 | assert(array_n(formalNameArray) == array_n(actualNameArray)); |
---|
241 | |
---|
242 | if (array_n(formalNameArray) != |
---|
243 | Hrc_NodeReadNumFormalInputs(subcktHnode) + Hrc_NodeReadNumFormalOutputs(subcktHnode)){ |
---|
244 | error_append("Error: Subcircuit "); |
---|
245 | error_append(instanceName); |
---|
246 | error_append(" in model "); |
---|
247 | error_append(Hrc_ModelReadName(model)); |
---|
248 | error_append(" and the corresponding model "); |
---|
249 | error_append(nameOfSubcktModel); |
---|
250 | error_append(" have different number of i/o ports.\n"); |
---|
251 | return 0; |
---|
252 | } |
---|
253 | |
---|
254 | /* creating a temporary hash table from formal names to actual names */ |
---|
255 | tmpTable = st_init_table(strcmp,st_strhash); |
---|
256 | for (j=0; j < array_n(formalNameArray); j++){ |
---|
257 | formalName = array_fetch(char *,formalNameArray,j); |
---|
258 | actualName = array_fetch(char *,actualNameArray,j); |
---|
259 | if (st_insert(tmpTable,(char *)formalName,(char *)actualName)){ |
---|
260 | error_append("Error: In subcircuit "); |
---|
261 | error_append(instanceName); |
---|
262 | error_append(" in model "); |
---|
263 | error_append(Hrc_ModelReadName(model)); |
---|
264 | error_append(", formal variable "); |
---|
265 | error_append(formalName); |
---|
266 | error_append(" is used more than once.\n"); |
---|
267 | st_free_table(tmpTable); |
---|
268 | return 0; |
---|
269 | } |
---|
270 | } |
---|
271 | |
---|
272 | /* create actualInputArray */ |
---|
273 | actualInputArray = array_alloc(Var_Variable_t *,0); |
---|
274 | actualOutputArray = array_alloc(Var_Variable_t *,0); |
---|
275 | Hrc_NodeForEachFormalInput(subcktHnode,j,port){ |
---|
276 | if (st_lookup(tmpTable,(char *)Var_VariableReadName(port),&actualPort) == 0){ |
---|
277 | error_append("Error: Subcircuit "); |
---|
278 | error_append(instanceName); |
---|
279 | error_append(" in model "); |
---|
280 | error_append(Hrc_ModelReadName(model)); |
---|
281 | error_append(" has no actual variable defined for variable "); |
---|
282 | error_append(Var_VariableReadName(port)); |
---|
283 | error_append(".\n"); |
---|
284 | return 0; |
---|
285 | } |
---|
286 | /* var should get a non-nil pointer */ |
---|
287 | var = Hrc_NodeFindVariableByName(hnode,actualPort); |
---|
288 | if (Var_VariablesTestHaveSameDomain(var,port) == 0){ |
---|
289 | error_append("Error: Formal variable "); |
---|
290 | error_append(Var_VariableReadName(port)); |
---|
291 | error_append(" and actual variable "); |
---|
292 | error_append(actualPort); |
---|
293 | error_append(" have different types in subcircuit "); |
---|
294 | error_append(instanceName); |
---|
295 | error_append(" in model "); |
---|
296 | error_append(Hrc_ModelReadName(model)); |
---|
297 | error_append(".\n"); |
---|
298 | return 0; |
---|
299 | } |
---|
300 | if (Var_VariableSetSI(var) == -1){ |
---|
301 | return 0; |
---|
302 | }; |
---|
303 | array_insert_last(Var_Variable_t *,actualInputArray,var); |
---|
304 | } |
---|
305 | |
---|
306 | /* create actualOutputArray */ |
---|
307 | outputCheckTable = st_init_table(strcmp,st_strhash); |
---|
308 | Hrc_NodeForEachFormalOutput(subcktHnode,j,port){ |
---|
309 | |
---|
310 | if (st_lookup(tmpTable,(char *)Var_VariableReadName(port),&actualPort) == 0){ |
---|
311 | error_append("Error: Subcircuit "); |
---|
312 | error_append(instanceName); |
---|
313 | error_append(" in model "); |
---|
314 | error_append(Hrc_ModelReadName(model)); |
---|
315 | error_append(" has no actual variable defined for variable "); |
---|
316 | error_append(Var_VariableReadName(port)); |
---|
317 | error_append(".\n"); |
---|
318 | return 0; |
---|
319 | } |
---|
320 | if (st_is_member(outputCheckTable,actualPort) == 1){ |
---|
321 | error_append("Error: Subcircuit "); |
---|
322 | error_append(instanceName); |
---|
323 | error_append(" in model "); |
---|
324 | error_append(Hrc_ModelReadName(model)); |
---|
325 | error_append(" has more than one output connected to the same variable "); |
---|
326 | error_append(actualPort); |
---|
327 | error_append(".\n"); |
---|
328 | return 0; |
---|
329 | } |
---|
330 | (void)st_insert(outputCheckTable,actualPort,(char *)0); |
---|
331 | /* var should get a non-nil pointer */ |
---|
332 | var = Hrc_NodeFindVariableByName(hnode,actualPort); |
---|
333 | if (Var_VariablesTestHaveSameDomain(var,port) == 0){ |
---|
334 | error_append("Error: Formal variable "); |
---|
335 | error_append(Var_VariableReadName(port)); |
---|
336 | error_append(" and actual variable "); |
---|
337 | error_append(actualPort); |
---|
338 | error_append(" have different types in subcircuit "); |
---|
339 | error_append(instanceName); |
---|
340 | error_append(" in model "); |
---|
341 | error_append(Hrc_ModelReadName(model)); |
---|
342 | error_append(".\n"); |
---|
343 | return 0; |
---|
344 | } |
---|
345 | if (Var_VariableSetSO(var) == -1){ |
---|
346 | return 0; |
---|
347 | }; |
---|
348 | array_insert_last(Var_Variable_t *,actualOutputArray,var); |
---|
349 | } |
---|
350 | st_free_table(outputCheckTable); |
---|
351 | st_free_table(tmpTable); |
---|
352 | if (Hrc_ModelAddSubckt(model,subcktModel,instanceName,actualInputArray,actualOutputArray) == 0){ |
---|
353 | error_append("Error: Model "); |
---|
354 | error_append(Hrc_ModelReadName(model)); |
---|
355 | error_append(" has two subcircuits with the same instance name "); |
---|
356 | error_append(instanceName); |
---|
357 | error_append("\n"); |
---|
358 | return 0; |
---|
359 | } |
---|
360 | } |
---|
361 | return 1; |
---|
362 | } |
---|
363 | |
---|
364 | |
---|
365 | /**Function******************************************************************** |
---|
366 | |
---|
367 | Synopsis [Checks to see if there is no inconsistency in a latch definition.] |
---|
368 | |
---|
369 | Description [] |
---|
370 | |
---|
371 | SideEffects [] |
---|
372 | |
---|
373 | SeeAlso [] |
---|
374 | |
---|
375 | ******************************************************************************/ |
---|
376 | static boolean |
---|
377 | _IoModelTestLatchConsistency(Hrc_Node_t *hnode) |
---|
378 | { |
---|
379 | Hrc_Latch_t *latch; |
---|
380 | Var_Variable_t *varIn, *varOut; |
---|
381 | st_generator *gen; |
---|
382 | char *latchName; |
---|
383 | |
---|
384 | Hrc_NodeForEachLatch(hnode,gen,latchName,latch){ |
---|
385 | varIn = Hrc_LatchReadInput(latch); |
---|
386 | varOut = Hrc_LatchReadOutput(latch); |
---|
387 | if (Var_VariablesTestHaveSameDomain(varIn,varOut) == 0){ |
---|
388 | error_append("Error: The input and the output of latch "); |
---|
389 | error_append(latchName); |
---|
390 | error_append(" have different domains.\n"); |
---|
391 | return 0; |
---|
392 | } |
---|
393 | if (Hrc_LatchReadResetTable(latch) == NIL(Tbl_Table_t)){ |
---|
394 | error_append("Error: Latch "); |
---|
395 | error_append(Var_VariableReadName(varOut)); |
---|
396 | error_append(" has no reset table.\n"); |
---|
397 | return 0; |
---|
398 | } |
---|
399 | } |
---|
400 | return 1; |
---|
401 | } |
---|
402 | |
---|
403 | /**Function******************************************************************** |
---|
404 | |
---|
405 | Synopsis [Checks to see if there is no inconsistency in reset declarations.] |
---|
406 | |
---|
407 | Description [] |
---|
408 | |
---|
409 | SideEffects [] |
---|
410 | |
---|
411 | SeeAlso [] |
---|
412 | |
---|
413 | ******************************************************************************/ |
---|
414 | |
---|
415 | static boolean |
---|
416 | _IoModelTestResetConsistency( |
---|
417 | Hrc_Manager_t *hmgr, |
---|
418 | Hrc_Model_t *model, |
---|
419 | Hrc_Node_t *hnode, |
---|
420 | array_t *resetArray) |
---|
421 | { |
---|
422 | int i; |
---|
423 | Var_Variable_t *output; |
---|
424 | Tbl_Table_t *resetTable; |
---|
425 | Hrc_Latch_t *latch; |
---|
426 | |
---|
427 | for (i=0; i < array_n(resetArray); i++){ |
---|
428 | resetTable = array_fetch(Tbl_Table_t *,resetArray,i); |
---|
429 | if (Tbl_TableReadNumOutputs(resetTable) != 1){ |
---|
430 | error_append("Error: Reset table with output "); |
---|
431 | error_append(Var_VariableReadName(Tbl_TableReadIndexVar(resetTable,0,1))); |
---|
432 | error_append(" has to be a single output table.\n"); |
---|
433 | return 0; |
---|
434 | } |
---|
435 | output = Tbl_TableReadIndexVar(resetTable,0,1); |
---|
436 | if (Var_VariableTestIsPS(output) == 0){ |
---|
437 | error_append("Error: Reset table with output "); |
---|
438 | error_append(Var_VariableReadName(output)); |
---|
439 | error_append(" is not attached to a latch.\n"); |
---|
440 | return 0; |
---|
441 | } |
---|
442 | latch = Hrc_NodeFindLatchByName(hnode,Var_VariableReadName(output)); |
---|
443 | if (Hrc_LatchSetResetTable(latch,resetTable) == 0){ |
---|
444 | error_append("Error: You try to overwrite the reset table of "); |
---|
445 | error_append(Var_VariableReadName(output)); |
---|
446 | error_append(".\n"); |
---|
447 | return 0; |
---|
448 | } |
---|
449 | /* once a reset table is associated with a latch, |
---|
450 | we remove the table from resetArray */ |
---|
451 | array_insert(Tbl_Table_t *,resetArray,i,NIL(Tbl_Table_t)); |
---|
452 | } |
---|
453 | return 1; |
---|
454 | } |
---|
455 | |
---|
456 | |
---|
457 | /**Function******************************************************************** |
---|
458 | |
---|
459 | Synopsis [Checks the consistency of the internal connection of a model.] |
---|
460 | |
---|
461 | Description [Checks the consistency of the internal connection of a model. |
---|
462 | Returns 1 if success. Otherwise returns 0.] |
---|
463 | |
---|
464 | SideEffects [] |
---|
465 | |
---|
466 | SeeAlso [] |
---|
467 | |
---|
468 | ******************************************************************************/ |
---|
469 | static boolean |
---|
470 | _IoModelTestInternalConnectionConsistency( |
---|
471 | Hrc_Model_t *model, |
---|
472 | Hrc_Node_t *hnode, |
---|
473 | boolean isVerbose) |
---|
474 | { |
---|
475 | st_table *varToTable, *outputVarToSubckt, *inputVarToSubckt, *visitTable; |
---|
476 | st_generator *gen; |
---|
477 | int i, j, status, warningStatus; |
---|
478 | Var_Variable_t *var, *actualOutput; |
---|
479 | Tbl_Table_t *table; |
---|
480 | char *varName, *subcktName, *latchName; |
---|
481 | Hrc_Subckt_t *subckt, *anotherSubckt; |
---|
482 | Hrc_Latch_t *latch; |
---|
483 | |
---|
484 | /* creates a hash table from variables to tables */ |
---|
485 | varToTable = st_init_table(st_ptrcmp,st_ptrhash); |
---|
486 | Hrc_NodeForEachNameTable(hnode,i,table){ |
---|
487 | Tbl_TableForEachOutputVar(table,j,var){ |
---|
488 | if (Var_VariableTestIsPI(var) == 1){ |
---|
489 | error_append("Error: Primary input "); |
---|
490 | error_append(Var_VariableReadName(var)); |
---|
491 | error_append(" is an output of a table in model "); |
---|
492 | error_append(Hrc_ModelReadName(model)); |
---|
493 | error_append(".\n"); |
---|
494 | st_free_table(varToTable); |
---|
495 | return 0; |
---|
496 | } |
---|
497 | if (st_insert(varToTable,(char *)var,(char *)table) == 1){ |
---|
498 | error_append("Error: Variable "); |
---|
499 | error_append(Var_VariableReadName(var)); |
---|
500 | error_append(" is an output of more than one table in model "); |
---|
501 | error_append(Hrc_ModelReadName(model)); |
---|
502 | error_append(".\n"); |
---|
503 | st_free_table(varToTable); |
---|
504 | return 0; |
---|
505 | } |
---|
506 | } |
---|
507 | } |
---|
508 | Hrc_NodeForEachLatch(hnode,gen,latchName,latch){ |
---|
509 | if (st_insert(varToTable,(char *)Hrc_LatchReadOutput(latch),(char *)Hrc_LatchReadResetTable(latch)) == 1){ |
---|
510 | error_append("Error: Latch output "); |
---|
511 | error_append(Var_VariableReadName(Hrc_LatchReadOutput(latch))); |
---|
512 | error_append(" is an output of a table in model "); |
---|
513 | error_append(Hrc_ModelReadName(model)); |
---|
514 | error_append(".\n"); |
---|
515 | st_free_table(varToTable); |
---|
516 | return 0; |
---|
517 | } |
---|
518 | } |
---|
519 | |
---|
520 | /* creates two hash tables |
---|
521 | one from output variables of subckts to subckts |
---|
522 | the other one from input variables of subckts to subckts */ |
---|
523 | outputVarToSubckt = st_init_table(st_ptrcmp,st_ptrhash); |
---|
524 | inputVarToSubckt = st_init_table(st_ptrcmp,st_ptrhash); |
---|
525 | |
---|
526 | Hrc_ModelForEachSubckt(model,gen,subcktName,subckt){ |
---|
527 | array_t *actualOutputs = Hrc_SubcktReadActualOutputVars(subckt); |
---|
528 | array_t *actualInputs = Hrc_SubcktReadActualInputVars(subckt); |
---|
529 | |
---|
530 | for (i=0; i < array_n(actualOutputs); i++){ |
---|
531 | actualOutput = array_fetch(Var_Variable_t *,actualOutputs,i); |
---|
532 | if (st_lookup(varToTable,(char *)actualOutput,&table) == 1){ |
---|
533 | error_append("Error: Subckt output "); |
---|
534 | error_append(Var_VariableReadName(actualOutput)); |
---|
535 | error_append(" in "); |
---|
536 | error_append(subcktName); |
---|
537 | error_append(" is an output of a table in model "); |
---|
538 | error_append(Hrc_ModelReadName(model)); |
---|
539 | error_append(".\n"); |
---|
540 | st_free_table(varToTable); |
---|
541 | st_free_table(outputVarToSubckt); |
---|
542 | st_free_gen(gen); |
---|
543 | return 0; |
---|
544 | } |
---|
545 | if (st_lookup(outputVarToSubckt,(char *)actualOutput,&anotherSubckt) == 1){ |
---|
546 | error_append("Error: Subckt output "); |
---|
547 | error_append(Var_VariableReadName(actualOutput)); |
---|
548 | error_append(" in "); |
---|
549 | error_append(subcktName); |
---|
550 | error_append(" is also a subckt output of "); |
---|
551 | error_append(Hrc_SubcktReadInstanceName(anotherSubckt)); |
---|
552 | error_append(" in model "); |
---|
553 | error_append(Hrc_ModelReadName(model)); |
---|
554 | error_append(".\n"); |
---|
555 | st_free_table(varToTable); |
---|
556 | st_free_table(outputVarToSubckt); |
---|
557 | st_free_gen(gen); |
---|
558 | return 0; |
---|
559 | } |
---|
560 | (void)st_insert(outputVarToSubckt,(char *)actualOutput,(char *)subckt); |
---|
561 | } |
---|
562 | |
---|
563 | for (i=0; i < array_n(actualInputs); i++){ |
---|
564 | Var_Variable_t *actualInput = array_fetch(Var_Variable_t *,actualInputs,i); |
---|
565 | (void)st_insert(inputVarToSubckt,(char *)actualInput,(char *)subckt); |
---|
566 | } |
---|
567 | |
---|
568 | } |
---|
569 | |
---|
570 | /* start checking the consistency of a hnode */ |
---|
571 | Hrc_NodeForEachVariable(hnode,gen,varName,var) { |
---|
572 | if (st_lookup(varToTable,(char *)var,&table) == 0){ |
---|
573 | if (Var_VariableTestIsPS(var) == 1 || Var_VariableTestIsPI(var) == 1){ |
---|
574 | continue; |
---|
575 | } |
---|
576 | else { |
---|
577 | if (st_lookup(outputVarToSubckt,(char *)var,&subckt) == 0) { |
---|
578 | error_append("Error: Variable "); |
---|
579 | error_append(varName); |
---|
580 | error_append(" is not defined as an output of a table in model "); |
---|
581 | error_append(Hrc_ModelReadName(model)); |
---|
582 | error_append(".\n"); |
---|
583 | st_free_table(varToTable); |
---|
584 | st_free_gen(gen); |
---|
585 | return 0; |
---|
586 | } |
---|
587 | } |
---|
588 | } |
---|
589 | } |
---|
590 | |
---|
591 | |
---|
592 | /* compute numFanoutTables */ |
---|
593 | Hrc_NodeForEachNameTable(hnode,i,table){ |
---|
594 | Tbl_TableForEachInputVar(table,j,var){ |
---|
595 | Var_VariableIncrementNumFanoutTables(var); |
---|
596 | } |
---|
597 | } |
---|
598 | |
---|
599 | /* acyclic check */ |
---|
600 | visitTable = st_init_table(st_ptrcmp,st_ptrhash); |
---|
601 | status = _IoModelTestIsAcyclic(model,hnode,varToTable,outputVarToSubckt,visitTable); |
---|
602 | warningStatus = 0; |
---|
603 | if (status == 1){ |
---|
604 | /* as a by-product of the acyclic check, visitTable now contains |
---|
605 | all the variables reachable from either PO, NS, or reset tables. |
---|
606 | We use this to detect all the variables not used in the hnode */ |
---|
607 | Hrc_NodeForEachVariable(hnode,gen,varName,var){ |
---|
608 | if (st_is_member(visitTable,(char *)var) == 0 && |
---|
609 | st_is_member(inputVarToSubckt,(char *)var) == 0 && |
---|
610 | Var_VariableTestIsPO(var) == 0 && |
---|
611 | Var_VariableTestIsNS(var) == 0 && |
---|
612 | Var_VariableTestIsPS(var) == 0 ){ |
---|
613 | warningStatus = 1; |
---|
614 | if (isVerbose){ |
---|
615 | /* the following is just a warning. We do not return a failure status */ |
---|
616 | error_append("Warning: Variable "); |
---|
617 | error_append(Var_VariableReadName(var)); |
---|
618 | error_append(" is not used in "); |
---|
619 | error_append(Hrc_ModelReadName(model)); |
---|
620 | error_append(".\n"); |
---|
621 | } |
---|
622 | } |
---|
623 | } |
---|
624 | } |
---|
625 | if (isVerbose == 0 && warningStatus == 1){ |
---|
626 | error_append("Warning: Some variables are unused in model "); |
---|
627 | error_append(Hrc_ModelReadName(model)); |
---|
628 | error_append(".\n"); |
---|
629 | } |
---|
630 | st_free_table(varToTable); |
---|
631 | st_free_table(outputVarToSubckt); |
---|
632 | st_free_table(inputVarToSubckt); |
---|
633 | st_free_table(visitTable); |
---|
634 | |
---|
635 | return 1; |
---|
636 | } |
---|
637 | |
---|
638 | |
---|
639 | /**Function******************************************************************** |
---|
640 | |
---|
641 | Synopsis [A DFS-based procedure for checking acyclicity.] |
---|
642 | |
---|
643 | Description [] |
---|
644 | |
---|
645 | SideEffects [] |
---|
646 | |
---|
647 | SeeAlso [] |
---|
648 | |
---|
649 | ******************************************************************************/ |
---|
650 | static boolean |
---|
651 | _IoModelTestIsAcyclic( |
---|
652 | Hrc_Model_t *model, |
---|
653 | Hrc_Node_t *hnode, |
---|
654 | st_table *varToTable, |
---|
655 | st_table *outputVarToSubckt, |
---|
656 | st_table *visitTable) |
---|
657 | { |
---|
658 | int i; |
---|
659 | Var_Variable_t *var; |
---|
660 | st_generator *gen; |
---|
661 | char *latchName; |
---|
662 | Hrc_Latch_t *latch; |
---|
663 | |
---|
664 | Hrc_NodeForEachFormalOutput(hnode,i,var){ |
---|
665 | if (_IoModelTestIsAcyclicRecursive(model,hnode,var,varToTable,outputVarToSubckt,visitTable,0) == 0){ |
---|
666 | _IoModelTestIsAcyclicError(model,var); |
---|
667 | return 0; |
---|
668 | } |
---|
669 | } |
---|
670 | Hrc_NodeForEachLatch(hnode,gen,latchName,latch){ |
---|
671 | Tbl_Table_t *resetTable; |
---|
672 | |
---|
673 | resetTable = Hrc_LatchReadResetTable(latch); |
---|
674 | Tbl_TableForEachInputVar(resetTable,i,var){ |
---|
675 | int status; |
---|
676 | if ((status = _IoModelTestIsAcyclicRecursive(model,hnode, |
---|
677 | var,varToTable,outputVarToSubckt,visitTable,1)) == 0){ |
---|
678 | _IoModelTestIsAcyclicError(model,var); |
---|
679 | st_free_gen(gen); |
---|
680 | return 0; |
---|
681 | } |
---|
682 | /* found a path from a PS to a reset table */ |
---|
683 | if (status == -1){ |
---|
684 | error_append(latchName); |
---|
685 | error_append(" in model "); |
---|
686 | error_append(Hrc_ModelReadName(model)); |
---|
687 | error_append(".\n"); |
---|
688 | st_free_gen(gen); |
---|
689 | return 0; |
---|
690 | } |
---|
691 | } |
---|
692 | } |
---|
693 | Hrc_NodeForEachLatch(hnode,gen,latchName,latch){ |
---|
694 | if (_IoModelTestIsAcyclicRecursive(model,hnode, |
---|
695 | (var = Hrc_LatchReadInput(latch)),varToTable,outputVarToSubckt,visitTable,0) == 0){ |
---|
696 | _IoModelTestIsAcyclicError(model,var); |
---|
697 | st_free_gen(gen); |
---|
698 | return 0; |
---|
699 | } |
---|
700 | } |
---|
701 | return 1; |
---|
702 | } |
---|
703 | |
---|
704 | /**Function******************************************************************** |
---|
705 | |
---|
706 | Synopsis [Prints out error messages during an acyclic check.] |
---|
707 | |
---|
708 | Description [] |
---|
709 | |
---|
710 | SideEffects [] |
---|
711 | |
---|
712 | SeeAlso [] |
---|
713 | |
---|
714 | ******************************************************************************/ |
---|
715 | static void |
---|
716 | _IoModelTestIsAcyclicError( |
---|
717 | Hrc_Model_t *model, |
---|
718 | Var_Variable_t *var) |
---|
719 | { |
---|
720 | error_append("Warning: Model "); |
---|
721 | error_append(Hrc_ModelReadName(model)); |
---|
722 | error_append(" may have a cyclic connection which involves variable "); |
---|
723 | error_append(Var_VariableReadName(var)); |
---|
724 | error_append("\n"); |
---|
725 | } |
---|
726 | |
---|
727 | /**Function******************************************************************** |
---|
728 | |
---|
729 | Synopsis [Recursive DFS routine for acyclic check.] |
---|
730 | |
---|
731 | Description [] |
---|
732 | |
---|
733 | SideEffects [] |
---|
734 | |
---|
735 | SeeAlso [] |
---|
736 | |
---|
737 | ******************************************************************************/ |
---|
738 | static int |
---|
739 | _IoModelTestIsAcyclicRecursive( |
---|
740 | Hrc_Model_t *model, |
---|
741 | Hrc_Node_t *hnode, |
---|
742 | Var_Variable_t *var, |
---|
743 | st_table *varToTable, |
---|
744 | st_table *outputVarToSubckt, |
---|
745 | st_table *visitTable, |
---|
746 | boolean isResetLogic) |
---|
747 | { |
---|
748 | int val, i; |
---|
749 | Var_Variable_t *input; |
---|
750 | Tbl_Table_t *table; |
---|
751 | Hrc_Subckt_t *subckt; |
---|
752 | |
---|
753 | if (st_lookup_int(visitTable,(char *)var, &val) == 1){ |
---|
754 | return (!val); |
---|
755 | } |
---|
756 | else{ |
---|
757 | (void)st_insert(visitTable,(char *)var,(char *)1); |
---|
758 | |
---|
759 | if (Var_VariableTestIsPI(var) == 0 && |
---|
760 | (isResetLogic || Var_VariableTestIsPS(var) == 0)){ |
---|
761 | if (isResetLogic && (Var_VariableTestIsPS(var) == 1)){ |
---|
762 | error_append("Warning: There is a path from latch output "); |
---|
763 | error_append(Var_VariableReadName(var)); |
---|
764 | error_append(" to reset table "); |
---|
765 | |
---|
766 | /* the error message is to be continued in _IoModelTestIsAcyclic() */ |
---|
767 | return -1; |
---|
768 | } |
---|
769 | if (st_lookup(varToTable,(char *)var,&table) == 1){ |
---|
770 | Tbl_TableForEachInputVar(table,i,input){ |
---|
771 | int status; |
---|
772 | if ((status = _IoModelTestIsAcyclicRecursive(model,hnode,input, |
---|
773 | varToTable,outputVarToSubckt,visitTable,isResetLogic)) == 0){ |
---|
774 | return 0; |
---|
775 | } |
---|
776 | if (status == -1){ |
---|
777 | return -1; |
---|
778 | } |
---|
779 | } |
---|
780 | } |
---|
781 | else { |
---|
782 | array_t *actualInputs; |
---|
783 | /* the return value of the following st_lookup should be 1 */ |
---|
784 | (void)st_lookup(outputVarToSubckt,(char *)var,&subckt); |
---|
785 | actualInputs = Hrc_SubcktReadActualInputVars(subckt); |
---|
786 | assert (actualInputs != NIL(array_t)); |
---|
787 | for (i=0; i < array_n(actualInputs); i++){ |
---|
788 | int status; |
---|
789 | input = array_fetch(Var_Variable_t *,actualInputs,i); |
---|
790 | if ((status = _IoModelTestIsAcyclicRecursive(model,hnode,input, |
---|
791 | varToTable,outputVarToSubckt,visitTable,0)) == 0){ |
---|
792 | return 0; |
---|
793 | } |
---|
794 | if (status == -1){ |
---|
795 | return -1; |
---|
796 | } |
---|
797 | } |
---|
798 | } |
---|
799 | } |
---|
800 | (void)st_insert(visitTable,(char *)var,(char *)0); |
---|
801 | return 1; |
---|
802 | } |
---|
803 | } |
---|
804 | |
---|
805 | |
---|
806 | |
---|
807 | |
---|
808 | |
---|
809 | |
---|
810 | |
---|
811 | |
---|
812 | |
---|
813 | |
---|
814 | |
---|
815 | |
---|
816 | |
---|
817 | |
---|