source: vis_dev/vis-2.3/src/ntk/ntkNode.c @ 99

Last change on this file since 99 was 14, checked in by cecile, 13 years ago

vis2.3

File size: 44.8 KB
RevLine 
[14]1/**CFile***********************************************************************
2
3  FileName    [ntkNode.c]
4
5  PackageName [ntk]
6
7  Synopsis    [Routines to access the node data structure.]
8
9  Author      [Adnan Aziz, Tom Shiple]
10
11  Copyright   [Copyright (c) 1994-1996 The Regents of the Univ. of California.
12  All rights reserved.
13
14  Permission is hereby granted, without written agreement and without license
15  or royalty fees, to use, copy, modify, and distribute this software and its
16  documentation for any purpose, provided that the above copyright notice and
17  the following two paragraphs appear in all copies of this software.
18
19  IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
20  DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
21  OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
22  CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24  THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
25  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
26  FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN
27  "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE
28  MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.]
29
30******************************************************************************/
31
32#include "ntkInt.h"
33#include "baig.h"
34
35static char rcsid[] UNUSED = "$Id: ntkNode.c,v 1.15 2009/04/11 01:56:10 fabio Exp $";
36
37/*---------------------------------------------------------------------------*/
38/* Constant declarations                                                     */
39/*---------------------------------------------------------------------------*/
40#define UNASSIGNED_OUTPUT_INDEX -1
41#define LATCH_DATA    0
42#define LATCH_INITIAL 1
43
44
45
46/**AutomaticStart*************************************************************/
47
48/*---------------------------------------------------------------------------*/
49/* Static function prototypes                                                */
50/*---------------------------------------------------------------------------*/
51
52static void NetworkAddCombOutput(Ntk_Network_t *network, Ntk_Node_t *node);
53
54/**AutomaticEnd***************************************************************/
55
56
57/*---------------------------------------------------------------------------*/
58/* Definition of exported functions                                          */
59/*---------------------------------------------------------------------------*/
60
61/**Function********************************************************************
62
63  Synopsis    [Returns the name of a node.]
64
65  Description [Returns the (actual) name of a node.  User must not free this
66  string.  Every node must have a non-NULL name. It is an error to call this
67  function on a NULL node.]
68
69  SideEffects []
70
71  SeeAlso     [Ntk_NodeCreateInNetwork]
72
73******************************************************************************/
74char *
75Ntk_NodeReadName(
76  Ntk_Node_t * node)
77{
78  assert(node != NIL(Ntk_Node_t));
79  return (node->name);
80}
81
82
83/**Function********************************************************************
84
85  Synopsis    [Returns the network of a node.]
86
87  Description [Returns the network to which node belongs.  User must not free
88  this network.  Every node must have a non-NULL network.  It is an error to
89  call this function on a NULL node.]
90
91  SideEffects []
92
93  SeeAlso     [Ntk_NodeCreateInNetwork]
94
95******************************************************************************/
96Ntk_Network_t *
97Ntk_NodeReadNetwork(
98  Ntk_Node_t * node)
99{
100  assert(node != NIL(Ntk_Node_t));
101  return (node->network);
102}
103
104
105/**Function********************************************************************
106
107  Synopsis    [Returns the variable of a node.]
108
109  Description [Returns the multi-valued variable at the output of a node.
110  User must not free this variable.  Every node must have a non-NULL variable.
111  The returned variable actually belongs to the hierarchy manager from which
112  the node's network was derived.  However, in the context of the network, the
113  only information contained in the variable that should be used, is the
114  information relating to the number (and name, if symbolic) of values. It is
115  an error to call this function on a NULL node.]
116
117  SideEffects []
118
119  SeeAlso     [Ntk_NodeCreateInNetwork Var_VariableReadNumValues
120  Var_VariableReadIndexFromSymbolicValue
121  Var_VariableReadSymbolicValueFromIndex Var_VariableTestIsSymbolic
122  Var_VariableTestIsEnumerative]
123
124******************************************************************************/
125Var_Variable_t *
126Ntk_NodeReadVariable(
127  Ntk_Node_t * node)
128{
129  assert(node != NIL(Ntk_Node_t));
130  return (node->variable);
131}
132
133
134/**Function********************************************************************
135
136  Synopsis    [Returns the table of a node.]
137
138  Description [Returns the table which defines the function of this node.  User
139  must not free this table.  Every combinational node and every pseudo input
140  has a table.  It is an error to call this function on a NULL node or a node
141  that isn't combinational or a pseudo input.]
142
143  SideEffects []
144
145  SeeAlso [Ntk_NodeDeclareAsCombinational Ntk_NodeDeclareAsPseudoInput
146  Ntk_NodeSetTable]
147
148******************************************************************************/
149Tbl_Table_t *
150Ntk_NodeReadTable(
151  Ntk_Node_t * node)
152{
153  assert(node != NIL(Ntk_Node_t));
154  assert((node->type == NtkCombinational_c) || (node->type == NtkPseudoInput_c));
155  return (node->table);
156}
157
158/**Function********************************************************************
159
160  Synopsis    [Returns the AndInv Id  of a node.]
161
162  Description [Returns the AndInv Id of the node in the AndInv graph.]
163
164  SideEffects []
165
166  SeeAlso     []
167
168******************************************************************************/
169mAigEdge_t
170Ntk_NodeReadMAigId(
171  Ntk_Node_t * node)
172{
173  assert(node != NIL(Ntk_Node_t));
174  return (node->mAigId);
175}
176
177
178/**Function********************************************************************
179
180  Synopsis    [Sets the AndInv Id  of a node.]
181
182  Description [Setss the AndInv Id of the node to a given vlaue.]
183
184  SideEffects []
185
186  SeeAlso     []
187
188******************************************************************************/
189void
190Ntk_NodeSetMAigId(
191  Ntk_Node_t * node,
192  mAigEdge_t mAigId)
193{
194  assert(node != NIL(Ntk_Node_t));
195  node->mAigId = mAigId;
196}
197
198/**Function********************************************************************
199
200  Synopsis    [Sets the table of the node to supplied table.]
201
202  Description [Sets the table of the node to supplied table. THIS FUNCTION
203  SHOULD BE USED WITH UTMOST CAUTION. It is assumed that the reference count of
204  the supplied table is appropriately incremented. If a table already exists in
205  the node it is NOT deleted. It is the users responsibility to free memory
206  associated with the old table. Every combinational node and every pseudo
207  input has a table. It is an error to call this function on a NULL node or a
208  node that isn't combinational or a pseudo input. No checks are done to ensure
209  that the supplied table infact has an output column for the specified node or
210  the variables corresponding to the input columns are indeed those of the
211  fanin nodes.]
212
213  SideEffects [The old table pointed to by the node is NOT deleted.]
214
215  SeeAlso [Ntk_NodeDeclareAsCombinational Ntk_NodeDeclareAsPseudoInput
216  Ntk_NodeReadTable]
217
218******************************************************************************/
219void
220Ntk_NodeSetTable(
221  Ntk_Node_t * node,
222  Tbl_Table_t *table)
223{
224
225  assert(node != NIL(Ntk_Node_t));
226  assert((node->type == NtkCombinational_c) || (node->type == NtkPseudoInput_c));
227
228  node->table = table;
229}
230
231/**Function********************************************************************
232
233  Synopsis    [Returns the output index of a node.]
234
235  Description [Returns the output column of the node's table that defines the
236  node's function.  It is an error to call this function on a NULL node or a
237  node of type other than combinational or pseudo input.]
238
239  SideEffects []
240
241  SeeAlso     [Ntk_NodeDeclareAsCombinational Ntk_NodeDeclareAsPrimaryInput
242  Ntk_NodeReadTable]
243
244******************************************************************************/
245int
246Ntk_NodeReadOutputIndex(
247  Ntk_Node_t * node)
248{
249  assert(node != NIL(Ntk_Node_t));
250  assert((node->type == NtkCombinational_c) || (node->type == NtkPseudoInput_c));
251  return (node->outputIndex);
252}
253
254
255/**Function********************************************************************
256
257  Synopsis    [Returns the MDD id of a node.]
258
259  Description [Returns the MDD id of a node.  Whether or not a node has an MDD
260  id depends on which nodes were assigned an id in Ord_NetworkOrderVariables.
261  Returns NTK_UNASSIGNED_MDD_ID if node does not have an assigned MDD id.  It
262  is an error to call this function on a NULL node.]
263
264  SideEffects []
265
266  SeeAlso     [Ord_NetworkOrderVariables Ntk_NodeSetMddId]
267
268******************************************************************************/
269int
270Ntk_NodeReadMddId(
271  Ntk_Node_t * node)
272{
273  assert(node != NIL(Ntk_Node_t));
274  return (node->mddId);
275}
276
277
278/**Function********************************************************************
279
280  Synopsis    [Sets the MDD id of a node.]
281
282  Description [Sets the MDD id of a node. Any node can have its MDD id set. No
283  check is made to see if node already has an MDD id.  Use the constant
284  NTK_UNASSIGNED_MDD_ID to indicate that the id is not set.  If mddId is not
285  NTK_UNASSIGNED_MDD_ID, then this mddId/node pair will be added to the
286  network's mddId to node table, and any previous pair involving this node
287  will be removed from the table.  Note that this function does *not* register
288  this mddId with the MDD manager; this must be done by calling
289  mdd_create_variables. It is an error to call this function on a NULL node.]
290
291  SideEffects []
292
293  SeeAlso     [Ntk_NodeReadMddId Ord_NetworkOrderVariables
294  Ntk_NetworkFindNodeByMddId]
295
296******************************************************************************/
297void
298Ntk_NodeSetMddId(
299  Ntk_Node_t * node,
300  int  id)
301{
302  Ntk_Network_t *network = node->network;
303  char *entry;
304 
305  assert(node != NIL(Ntk_Node_t));
306
307  /* If the node already has an assigned id, then clean it from the table. */
308  if (node->mddId != NTK_UNASSIGNED_MDD_ID) {
309    entry = (char *) (long) node->mddId;
310    (void) st_delete(network->mddIdToNode, &entry, NIL(char *));
311  }
312
313  /* Set the new id, and add it to the table (if it's not unassigned). */
314  node->mddId = id;
315  if (id != NTK_UNASSIGNED_MDD_ID) {
316    st_insert(network->mddIdToNode, (char *) (long) id, (char *) node);
317  }
318}
319
320
321/**Function********************************************************************
322
323  Synopsis    [Returns the undef field of a node.]
324
325  Description [Returns the undef field of a node.  There is no restriction on how
326  this field is used.  However, you should use extreme caution to make sure
327  that you are not using this field to store more that one thing at a given
328  time (if you can't be sure, then use a hash table).  It is an error to call
329  this function on a NULL node.]
330
331  SideEffects []
332
333  SeeAlso     [Ntk_NodeSetUndef]
334
335******************************************************************************/
336void *
337Ntk_NodeReadUndef(
338  Ntk_Node_t * node)
339{
340  assert(node != NIL(Ntk_Node_t));
341  return (node->undef);
342}
343
344
345/**Function********************************************************************
346
347  Synopsis    [Sets the undef field of a node.]
348
349  Description [Sets the undef field of a node.  There is no restriction on
350  how this field is used.  It is an error to call this function on a NULL
351  node.]
352
353  SideEffects []
354
355  SeeAlso     [Ntk_NodeReadUndef]
356
357******************************************************************************/
358void
359Ntk_NodeSetUndef(
360  Ntk_Node_t * node,
361  void * value)
362{
363  assert(node != NIL(Ntk_Node_t));
364  node->undef = value;
365}
366
367
368/**Function********************************************************************
369
370  Synopsis    [Returns 1 if node is a primary input, else returns 0.]
371
372  Description [Returns 1 if node is a primary input, else returns 0.  A node
373  is a primary input only if it has been so declared using
374  Ntk_NodeDeclareAsPrimaryInput. It is an error to call this function on a
375  NULL node.]
376 
377  SideEffects []
378
379  SeeAlso     [Ntk_NodeDeclareAsPrimaryInput Ntk_NodeTestIsInput]
380 
381******************************************************************************/
382boolean
383Ntk_NodeTestIsPrimaryInput(
384  Ntk_Node_t * node)
385{
386  assert(node != NIL(Ntk_Node_t));
387  return (node->type == NtkPrimaryInput_c);
388}
389
390
391/**Function********************************************************************
392
393  Synopsis    [Returns 1 if node is a pseudo input, else returns 0.]
394
395  Description [Returns 1 if node is a pseudo input, else returns 0.  A node is
396  a pseudo input only if it has been so declared using
397  Ntk_NodeDeclareAsPseudoInput. A pseudo input has no fanins, but has a table
398  defining its function. It is an error to call this function on a NULL node.]
399 
400  SideEffects []
401
402  SeeAlso     [Ntk_NodeDeclareAsPseudoInput Ntk_NodeTestIsInput]
403 
404******************************************************************************/
405boolean
406Ntk_NodeTestIsPseudoInput(
407  Ntk_Node_t * node)
408{
409  assert(node != NIL(Ntk_Node_t));
410  return (node->type == NtkPseudoInput_c);
411}
412
413
414/**Function********************************************************************
415
416  Synopsis    [Returns 1 if node is a primary or pseudo input, else returns 0.]
417
418  Description [Returns 1 if node is a primary or pseudo input, else returns 0.
419  It is an error to call this function on a NULL node.]
420 
421  SideEffects []
422
423  SeeAlso     [Ntk_NodeDeclareAsPrimaryInput Ntk_NodeDeclareAsPseudoInput
424  Ntk_NodeTestIsPrimaryInput Ntk_NodeTestIsPseudoInput]
425 
426******************************************************************************/
427boolean
428Ntk_NodeTestIsInput(
429  Ntk_Node_t * node)
430{
431  assert(node != NIL(Ntk_Node_t));
432  return ((node->type == NtkPrimaryInput_c) || (node->type == NtkPseudoInput_c));
433 
434}
435
436
437/**Function********************************************************************
438
439  Synopsis    [Returns 1 if node is undefined, else returns 0.]
440
441  Description [Returns 1 if node is undefined, else returns 0. A node is
442  undefined if it has been created but not declared as anything. It is an
443  error to call this function on a NULL node.]
444 
445  SideEffects []
446
447  SeeAlso     [Ntk_NodeCreateInNetwork Ntk_NodeDeclareAsCombinational]
448
449******************************************************************************/
450boolean
451Ntk_NodeTestIsUndefined(
452  Ntk_Node_t * node)
453{
454  assert(node != NIL(Ntk_Node_t));
455  return (node->type == NtkUnassigned_c);
456}
457
458
459/**Function********************************************************************
460
461  Synopsis    [Returns 1 if node is a latch, else returns 0.]
462
463  Description [Returns 1 if node is a latch, else returns 0.  A node is a
464  latch only if it has been so declared using Ntk_NodeDeclareAsLatch. It is an
465  error to call this function on a NULL node.]
466 
467  SideEffects []
468
469  SeeAlso     [Ntk_NodeDeclareAsLatch]
470
471******************************************************************************/
472boolean
473Ntk_NodeTestIsLatch(
474  Ntk_Node_t * node)
475{
476  assert(node != NIL(Ntk_Node_t));
477  return (node->type == NtkLatch_c);
478}
479
480
481/**Function********************************************************************
482
483  Synopsis    [Returns 1 if node is a next state node, else returns 0.]
484
485  Description [Returns 1 if node is a next state node, else returns 0.  A next
486  state node is a shadow node whose origin node is a latch.  It is an
487  error to call this function on a NULL node.]
488 
489  SideEffects []
490
491  SeeAlso     [Ntk_NodeDeclareAsShadow]
492
493******************************************************************************/
494boolean
495Ntk_NodeTestIsNextStateNode(
496  Ntk_Node_t * node)
497{
498  assert(node != NIL(Ntk_Node_t));
499  if (Ntk_NodeTestIsShadow(node)) {
500    Ntk_Node_t *origin = Ntk_ShadowReadOrigin(node);
501    if (Ntk_NodeTestIsLatch(origin)) {
502      return (TRUE);
503    }
504  }
505 
506  return (FALSE);
507}
508
509
510/**Function********************************************************************
511
512  Synopsis    [Returns 1 if node is a shadow node, else returns 0.]
513
514  Description [Returns 1 if node is a shadow node, else returns 0.  A shadow
515  node is used to associate extra information with a node, in particular
516  another MDD id. It is an error to call this function on a NULL node.]
517 
518  SideEffects []
519
520  SeeAlso     [Ntk_NodeDeclareAsShadow Ntk_ShadowReadOrigin Ntk_NodeReadShadow]
521
522******************************************************************************/
523boolean
524Ntk_NodeTestIsShadow(
525  Ntk_Node_t * node)
526{
527  assert(node != NIL(Ntk_Node_t));
528  return (node->type == NtkShadow_c);
529}
530
531
532/**Function********************************************************************
533
534  Synopsis    [Returns 1 if node is a combinational input, else returns 0.]
535
536  Description [Returns 1 if node is a combinational input, else returns 0.  A
537  node is a combinational input if it is a primary input, a pseudo input, or a
538  latch. It is an error to call this function on a NULL node.]
539 
540  SideEffects []
541
542  SeeAlso     [Ntk_NodeDeclareAsPrimaryInput Ntk_NodeDeclareAsLatch
543  Ntk_NodeDeclareAsPseudoInput]
544
545******************************************************************************/
546boolean
547Ntk_NodeTestIsCombInput(
548  Ntk_Node_t * node)
549{
550  assert(node != NIL(Ntk_Node_t));
551  return ((node->type == NtkLatch_c)
552          || (node->type == NtkPrimaryInput_c)
553          || (node->type == NtkPseudoInput_c));
554}
555
556
557/**Function********************************************************************
558
559  Synopsis    [Returns 1 if node is a combinational output, else returns 0.]
560
561  Description [Returns 1 if node is a combinational output, else returns 0.  A
562  node is a combinational output if it is a primary output, a data input to a
563  latch, or an initial input to a latch. This is a constant time operation.
564  It is an error to call this function on a NULL node.]
565 
566  SideEffects []
567
568  SeeAlso     [Ntk_NodeDeclareAsPrimaryOutput Ntk_NodeDeclareAsLatch]
569 
570******************************************************************************/
571boolean
572Ntk_NodeTestIsCombOutput(
573  Ntk_Node_t * node)
574{
575  assert(node != NIL(Ntk_Node_t));
576  return (Ntk_NodeTestIsPrimaryOutput(node)
577          || Ntk_NodeTestIsLatchDataInput(node)
578          || Ntk_NodeTestIsLatchInitialInput(node));
579}
580
581
582/**Function********************************************************************
583
584  Synopsis    [Returns 1 if node is combinational, else returns 0.]
585
586  Description [Returns 1 if node is combinational, else returns 0.  A node is
587  combinational only if it has been so declared using
588  Ntk_NodeDeclareAsCombinational.  Combinational nodes have tables.]
589 
590  SideEffects []
591
592  SeeAlso     [Ntk_NodeDeclareAsCombinational]
593
594******************************************************************************/
595boolean
596Ntk_NodeTestIsCombinational(
597  Ntk_Node_t * node)
598{
599  assert(node != NIL(Ntk_Node_t));
600  return (node->type == NtkCombinational_c);
601}
602
603
604/**Function********************************************************************
605
606  Synopsis    [Returns 1 if node is a primary output, else returns 0.]
607
608  Description [Returns 1 if node is a primary output, else returns 0.  Any
609  node can be a primary output, except those of type shadow.  A node is a
610  primary output only if it has been so declared using
611  Ntk_NodeDeclareAsPrimaryOutput.  It is an error to call this function on a
612  NULL node.]
613 
614  SideEffects []
615
616  SeeAlso     [Ntk_NodeDeclareAsPrimaryOutput]
617 
618******************************************************************************/
619boolean
620Ntk_NodeTestIsPrimaryOutput(
621  Ntk_Node_t * node)
622{
623  assert(node != NIL(Ntk_Node_t));
624  return (node->outputFlag);
625}
626
627
628/**Function********************************************************************
629
630  Synopsis    [Returns 1 if node is a data input to a latch, else returns 0.]
631
632  Description [Returns 1 if node is a data input to a latch, else returns 0.
633  Nodes of all types can be data inputs to latches.  A node is declared as a
634  data input to a latch by virtue of a call to Ntk_NodeDeclareAsLatch. It is
635  an error to call this function on a NULL node.]
636 
637  SideEffects []
638
639  SeeAlso     [Ntk_NodeDeclareAsLatch]
640
641******************************************************************************/
642boolean
643Ntk_NodeTestIsLatchDataInput(
644  Ntk_Node_t * node)
645{
646  assert(node != NIL(Ntk_Node_t));
647  return (node->latchDataInput);
648}
649
650
651/**Function********************************************************************
652
653  Synopsis    [Returns 1 if node is an initial input to a latch, else returns 0.]
654
655  Description [Returns 1 if node is an initial input to a latch, else returns
656  0.  Nodes of all types can be initial inputs to latches. The initial input
657  to a latch gives the initial value of the latch. A node is declared as a
658  initial input to a latch by virtue of a call to Ntk_NodeDeclareAsLatch. It
659  is an error to call this function on a NULL node.]
660 
661  SideEffects []
662
663  SeeAlso     [Ntk_NodeDeclareAsLatch]
664
665******************************************************************************/
666boolean
667Ntk_NodeTestIsLatchInitialInput(
668  Ntk_Node_t * node)
669{
670  assert(node != NIL(Ntk_Node_t));
671  return (node->latchInitialInput);
672}
673
674
675/**Function********************************************************************
676
677  Synopsis    [Returns 1 if node is a constant, else returns 0.]
678
679  Description [Returns 1 if node is a constant, else returns 0.  A constant is
680  a combinational node that has no inputs, and whose output can take exactly
681  one of its values.  It is an error to call this function on a NULL node.]
682 
683  SideEffects []
684
685  SeeAlso     [Ntk_NodeDeclareAsCombinational]
686
687******************************************************************************/
688boolean
689Ntk_NodeTestIsConstant(
690  Ntk_Node_t * node)
691{
692  assert(node != NIL(Ntk_Node_t));
693  return (node->constant);
694}
695
696
697/**Function********************************************************************
698
699  Synopsis    [Returns the shadow of a node.]
700
701  Description [Returns the shadow of a node if one exists, else returns NULL.
702  A shadow node can serve as a placeholder for an extra MDD variable, such as
703  a next state variable.  It is an error to call this function on a node that
704  is a shadow.]
705 
706  SideEffects []
707
708  SeeAlso     [Ntk_NodeDeclareAsShadow Ntk_ShadowReadOrigin Ntk_NodeTestIsShadow]
709
710******************************************************************************/
711Ntk_Node_t *
712Ntk_NodeReadShadow(
713  Ntk_Node_t * node)
714{
715  assert(node != NIL(Ntk_Node_t));
716  assert(node->type != NtkShadow_c);
717  return (node->shadowInfo.shadow);
718}
719
720
721/**Function********************************************************************
722
723  Synopsis    [Returns the origin node of a shadow node.]
724
725  Description [Returns the origin node of a shadow node.  The origin of a
726  shadow node is that node that is "casting" the shadow.  A shadow is used as
727  a placeholder for a node, in particular a place to store an additional MDD
728  variable.  It is an error to call this function on a node that is not a
729  shadow.]
730 
731  SideEffects []
732
733  SeeAlso     [Ntk_NodeDeclareAsShadow Ntk_NodeReadShadow Ntk_NodeTestIsShadow]
734
735******************************************************************************/
736Ntk_Node_t *
737Ntk_ShadowReadOrigin(
738  Ntk_Node_t * shadow)
739{
740  assert(shadow != NIL(Ntk_Node_t));
741  assert(shadow->type == NtkShadow_c);
742  return (shadow->shadowInfo.origin);
743}
744
745
746/**Function********************************************************************
747
748  Synopsis    [Returns the of data input of a latch.]
749
750  Description [Returns the data input of a latch.  The data input determines the
751  value of the latch output at the next clock. It is an error to call this
752  function on a node that is not a latch.]
753 
754  SideEffects []
755
756  SeeAlso     [Ntk_NodeDeclareAsLatch]
757
758******************************************************************************/
759Ntk_Node_t *
760Ntk_LatchReadDataInput(
761  Ntk_Node_t * node)
762{
763  Ntk_Node_t *data;
764 
765  assert(node != NIL(Ntk_Node_t));
766  assert(node->type == NtkLatch_c);
767  data = array_fetch(Ntk_Node_t *, node->fanins, LATCH_DATA);
768 
769  return (data);
770}
771
772
773/**Function********************************************************************
774
775  Synopsis    [Returns the initial input of a latch.]
776
777  Description [Returns the initial input of a latch.  The initial value
778  of the latch is determined by the value of the initial input. It is
779  an error to call this function on a node that is not a latch.]
780 
781  SideEffects []
782
783  SeeAlso     [Ntk_NodeDeclareAsLatch]
784
785******************************************************************************/
786Ntk_Node_t *
787Ntk_LatchReadInitialInput(
788  Ntk_Node_t * node)
789{
790  Ntk_Node_t *initial;
791 
792  assert(node != NIL(Ntk_Node_t));
793  assert(node->type == NtkLatch_c);
794  initial = array_fetch(Ntk_Node_t *, node->fanins, LATCH_INITIAL);
795 
796  return (initial);
797}
798
799
800/**Function********************************************************************
801
802  Synopsis    [Returns the number of fanins of a node.]
803
804  SideEffects []
805
806  SeeAlso     [Ntk_NodeReadNumFanouts]
807
808******************************************************************************/
809int
810Ntk_NodeReadNumFanins(
811  Ntk_Node_t * node)
812{
813  assert(node != NIL(Ntk_Node_t));
814  return (array_n(node->fanins));
815}
816
817
818/**Function********************************************************************
819
820  Synopsis    [Returns the number of fanouts of a node.]
821
822  SideEffects []
823
824  SeeAlso     [Ntk_NodeReadNumFanins]
825
826******************************************************************************/
827int
828Ntk_NodeReadNumFanouts(
829  Ntk_Node_t * node)
830{
831  assert(node != NIL(Ntk_Node_t));
832  return (array_n(node->fanouts));
833}
834
835
836/**Function********************************************************************
837
838  Synopsis    [Returns the fanin of node corresponding to faninIndex.]
839
840  Description [Returns the fanin of node corresponding to faninIndex.  Fanins are
841  numbered starting from 0.]
842
843  SideEffects []
844
845  SeeAlso     [Ntk_NodeReadFaninIndex]
846
847******************************************************************************/
848Ntk_Node_t *
849Ntk_NodeReadFaninNode(
850  Ntk_Node_t * node,
851  int  faninIndex)
852{
853  Ntk_Node_t *faninNode;
854 
855  assert(node != NIL(Ntk_Node_t));
856  assert((faninIndex >= 0) && (faninIndex < Ntk_NodeReadNumFanins(node)));
857  faninNode = array_fetch(Ntk_Node_t *, node->fanins, faninIndex);
858  return (faninNode);
859}
860
861 
862/**Function********************************************************************
863
864  Synopsis    [Returns the fanin index of node corresponding to faninNode.]
865
866  Description [Returns the fanin index of node corresponding to faninNode. If
867  faninNode is not a fanin of node, then returns NTK_UNDEFINED_FANIN_INDEX.]
868
869  SideEffects []
870
871  SeeAlso     [Ntk_NodeReadFaninNode]
872
873******************************************************************************/
874int
875Ntk_NodeReadFaninIndex(
876  Ntk_Node_t * node,
877  Ntk_Node_t * faninNode)
878{
879  int         i;
880  Ntk_Node_t *tempNode;
881 
882  assert(node != NIL(Ntk_Node_t));
883  Ntk_NodeForEachFanin(node, i, tempNode) {
884    if (tempNode == faninNode) {
885      return (i);
886    }
887  }
888
889  return (NTK_UNDEFINED_FANIN_INDEX);
890}
891
892
893/**Function********************************************************************
894
895  Synopsis    [Returns the array of fanins of a node.]
896
897  Description [Returns the array of fanins of a node.  The user must not free or
898  modify this array in any way.]
899 
900  SideEffects []
901
902  SeeAlso     [Ntk_NodeReadNumFanins]
903
904******************************************************************************/
905array_t *
906Ntk_NodeReadFanins(
907  Ntk_Node_t * node)
908{
909  assert(node != NIL(Ntk_Node_t));
910  return (node->fanins);
911}
912
913
914/**Function********************************************************************
915
916  Synopsis    [Returns the array of fanouts of a node.]
917
918  Description [Returns the array of fanouts of a node.  The user must not free or
919  modify this array in any way.]
920 
921  SideEffects []
922
923  SeeAlso     [Ntk_NodeReadNumFanouts]
924
925******************************************************************************/
926array_t *
927Ntk_NodeReadFanouts(
928  Ntk_Node_t * node)
929{
930  assert(node != NIL(Ntk_Node_t));
931  return (node->fanouts);
932}
933
934
935/**Function********************************************************************
936
937  Synopsis    [Sets the array of fanins of a node.]
938
939  Description [Sets the array of fanins of a node. This function must be used
940  with UTMOST caution. Use this only when you know EXACTLY what you are doing.]
941 
942  SideEffects [Old fanin array is deleted.]
943
944  SeeAlso     [Ntk_NodeReadNumFanins Ntk_NodeReadFanins]
945
946******************************************************************************/
947void
948Ntk_NodeSetFanins(
949  Ntk_Node_t * node,
950  array_t *faninArray)
951{
952  assert(node != NIL(Ntk_Node_t));
953  if (node->fanins)
954    array_free(node->fanins);
955 
956  node->fanins = faninArray;
957
958  return;
959}
960
961
962/**Function********************************************************************
963
964  Synopsis    [Sets the array of fanouts of a node.]
965
966  Description [Sets the array of fanouts of a node. This function must be used
967  with UTMOST caution. Use this only when you know EXACTLY what you are doing.]
968 
969  SideEffects [Old fanout array is deleted.]
970
971  SeeAlso     [Ntk_NodeReadNumFanouts Ntk_NodeReadFanouts]
972
973******************************************************************************/
974void
975Ntk_NodeSetFanouts(
976  Ntk_Node_t * node,
977  array_t *fanoutArray)
978{
979  assert(node != NIL(Ntk_Node_t));
980  if (node->fanouts)
981    array_free(node->fanouts);
982 
983  node->fanouts = fanoutArray;
984
985  return;
986}
987
988
989/**Function********************************************************************
990
991  Synopsis    [Returns a string giving a node's type.]
992
993  Description [Returns a string giving a node's type.  The return string can
994  be one of the following: "latch", "shadow", "primary-input", "pseudo-input",
995  "combinational", or "unassigned".  It is the user's responsibility to free
996  this string.]
997
998  SideEffects []
999
1000  SeeAlso     [Ntk_NodePrint]
1001
1002******************************************************************************/
1003char *
1004Ntk_NodeObtainTypeAsString(
1005  Ntk_Node_t * node)
1006{
1007  char *typeString;
1008
1009  assert(node != NIL(Ntk_Node_t));
1010  switch(node->type) {
1011      case NtkLatch_c:
1012        typeString = util_strsav("latch");
1013        break;
1014      case NtkShadow_c:
1015        typeString = util_strsav("shadow");
1016        break;
1017      case NtkPrimaryInput_c:
1018        typeString = util_strsav("primary-input");
1019        break;
1020      case NtkPseudoInput_c:
1021        typeString = util_strsav("pseudo-input");
1022        break;
1023      case NtkCombinational_c:
1024        typeString = util_strsav("combinational");
1025        break;
1026      case NtkUnassigned_c:
1027        typeString = util_strsav("unassigned");
1028        break;
1029      default:
1030        fail("Unexpected type");
1031  }
1032  return (typeString);
1033}
1034
1035
1036/**Function********************************************************************
1037
1038  Synopsis    [Prints information about a node.]
1039
1040  Description [Prints the node's name, MDD id, type, and attributes. In
1041  addition, if printIo is TRUE, prints the name of each fanin node and each
1042  fanout node. And if printTableStats is TRUE, print table statistics for
1043  those nodes having a table.]
1044
1045  SideEffects []
1046
1047  SeeAlso     [Ntk_NetworkPrint]
1048
1049******************************************************************************/
1050void
1051Ntk_NodePrint(
1052  FILE * fp,
1053  Ntk_Node_t * node,
1054  boolean printIo,
1055  boolean printTableStats)
1056{
1057  int         i;
1058  Ntk_Node_t *fanin;
1059  Ntk_Node_t *fanout;
1060  char       *typeString = Ntk_NodeObtainTypeAsString(node);
1061 
1062
1063  /*
1064   * Print the node's name, MDD id, type, and attributes.
1065   */
1066  (void) fprintf(fp, "%s: mdd=%d, %s;%s%s%s%s%s%s\n",
1067                 Ntk_NodeReadName(node),
1068                 Ntk_NodeReadMddId(node),
1069                 typeString,
1070                 (Ntk_NodeTestIsPrimaryOutput(node) ? " output" : ""),
1071                 (Ntk_NodeTestIsConstant(node) ? " constant" : ""),
1072                 (Ntk_NodeTestIsLatchDataInput(node) ? " data-input" : ""),
1073                 (Ntk_NodeTestIsLatchInitialInput(node) ? " initial-input" : ""),
1074                 (Ntk_NodeTestIsCombInput(node) ? " comb-input" : ""),
1075                 (Ntk_NodeTestIsCombOutput(node) ? " comb-output" : "")
1076                 );
1077
1078  FREE(typeString);
1079 
1080  if (printIo) {
1081    /*
1082     * Print the name of each fanin.
1083     */
1084    (void) fprintf(fp, "Fanins:  ");
1085    Ntk_NodeForEachFanin(node, i, fanin) {
1086      if (i != 0) (void) fprintf(fp, ",");
1087      (void) fprintf(fp, " %s", Ntk_NodeReadName(fanin));
1088    }
1089    (void) fprintf(fp, "\n");
1090
1091    /*
1092     * Print the name of each fanout.
1093     */
1094    (void) fprintf(fp, "Fanouts: ");
1095    Ntk_NodeForEachFanout(node, i, fanout) {
1096      if (i != 0) (void) fprintf(fp, ",");
1097      (void) fprintf(fp, " %s", Ntk_NodeReadName(fanout));
1098    }
1099    (void) fprintf(fp, "\n");
1100  }
1101
1102  if (printTableStats) {
1103    if (Ntk_NodeTestIsCombinational(node) || Ntk_NodeTestIsPseudoInput(node)) {
1104      Tbl_TablePrintStats(Ntk_NodeReadTable(node), fp);
1105    }
1106  }
1107}
1108
1109
1110/**Function********************************************************************
1111
1112  Synopsis    [Creates a node in a network with a name and a variable.]
1113
1114  Description [Creates a node in a network.  The name, network, and variable
1115  fields are initialized with the supplied values (a copy of name is made
1116  first, a copy of the variable is not made).  The fanins and fanouts fields
1117  are initialized with empty arrays.  All other fields are initialized to NULL
1118  or UNASSIGNED values.  A non-NULL name, non-NULL network, and non-NULL
1119  variable are required. This is the only way to allocate a node; in other
1120  words, a node can only exist with a name and a variable, within the context
1121  of a network.]
1122
1123  SideEffects [The node is added to the network's information.]
1124
1125  SeeAlso     [Ntk_NodeFree]
1126
1127******************************************************************************/
1128Ntk_Node_t *
1129Ntk_NodeCreateInNetwork(
1130  Ntk_Network_t * network,
1131  char * name,
1132  Var_Variable_t *variable)
1133{
1134  Ntk_Node_t *node = ALLOC(Ntk_Node_t, 1);
1135
1136  assert(network != NIL(Ntk_Network_t));
1137  assert(name != NIL(char));
1138  assert(variable != NIL(Var_Variable_t));
1139 
1140  node->name                  = util_strsav(name);
1141  node->network               = network;
1142  node->variable              = variable;
1143  node->type                  = NtkUnassigned_c;
1144  node->fanins                = array_alloc(Ntk_Node_t *, 0);
1145  node->fanouts               = array_alloc(Ntk_Node_t *, 0);
1146  node->table                 = NIL(Tbl_Table_t);
1147  node->outputIndex           = UNASSIGNED_OUTPUT_INDEX;
1148  node->mddId                 = NTK_UNASSIGNED_MDD_ID;
1149  node->mAigId                = -1;
1150  node->shadowInfo.shadow     = NIL(Ntk_Node_t);
1151  node->outputFlag            = 0;
1152  node->constant              = 0;
1153  node->latchDataInput        = 0;
1154  node->latchInitialInput     = 0;
1155  node->undef                 = NIL(void);
1156
1157  /*
1158   * Update the state of the network. Note: it's important to use node->name
1159   * here, rather than just name, because we don't own name.
1160   */
1161  st_insert(network->actualNameToNode, (char *) node->name, (char *) node);
1162  lsNewEnd(network->nodes, (lsGeneric) node, LS_NH);
1163
1164  return (node);
1165}
1166
1167
1168/**Function********************************************************************
1169
1170  Synopsis    [Declares a node as combinational and sets the table.]
1171
1172  Description [Declares a node as combinational using the column of table
1173  corresponding to outputIndex as the function of the node.  This function
1174  does not make a copy of the table; instead, it just sets a pointer to it.
1175  However, it's assumed that the table will own the table, and the table is
1176  freed when the node is freed.  Connections are made to the nodes
1177  corresponding to the inputs in the table.  The node for the ith table input
1178  is found by calling Ntk_NetworkFindNodeByName with the ith entry of
1179  inputNames.  The order of the fanins of node returned by
1180  Ntk_NodeForEachFanin are guaranteed to be the same as the order of the
1181  corresponding input columns in the table.]
1182
1183  SideEffects []
1184
1185  SeeAlso     [Ntk_NodeDeclareAsPrimaryInput Ntk_NodeDeclareAsPrimaryOutput]
1186
1187******************************************************************************/
1188void
1189Ntk_NodeDeclareAsCombinational(
1190  Ntk_Node_t * node,
1191  Tbl_Table_t * table,
1192  array_t * inputNames /* array of char */,
1193  int  outputIndex)
1194{
1195  int            i;
1196  Ntk_Network_t *network = node->network;
1197
1198  assert(node->type == NtkUnassigned_c);
1199 
1200  node->type        = NtkCombinational_c;
1201  node->table       = table;
1202  node->outputIndex = outputIndex;
1203
1204  /*
1205   * If it can be determined that the corresponding output column of table can
1206   * take assume just a single value, then set the constant flag.
1207   */
1208  if (Tbl_TableTestIsConstant(table, outputIndex)) {
1209    node->constant = 1;
1210  }
1211 
1212  /*
1213   * Create a connection to each input of table.
1214   */
1215  for (i = 0; i < array_n(inputNames); i++) {
1216    char        *faninName = array_fetch(char *, inputNames, i);
1217    Ntk_Node_t  *fanin     = Ntk_NetworkFindNodeByName(network, faninName);
1218
1219    assert(fanin != NIL(Ntk_Node_t));
1220
1221    /*
1222     * Make the connections between node and fanin.  Note: it is critical
1223     * that the fanins of node are added to node->fanins in the same order
1224     * they appear in the table.
1225     */
1226    array_insert_last(Ntk_Node_t *, fanin->fanouts, node);
1227    array_insert_last(Ntk_Node_t *, node->fanins, fanin);
1228  }
1229}
1230
1231
1232/**Function********************************************************************
1233
1234  Synopsis    [Declares a node as a latch.]
1235
1236  Description [Declares a node as a latch.  Makes connections to the data and
1237  initial input nodes.  The data node is taken as that one found by calling
1238  Ntk_NetworkFindNodeByName with the name "dataName"; likewise for the initial
1239  node.  Adds the node to the end of the latch list of the node's network, and
1240  the combinational input list.  This function does not automatically create
1241  a shadow node for the latch (i.e. a node to store information about the next
1242  state variable of the latch); to do this, use Ntk_NodeCreateInNetwork and
1243  Ntk_NodeDeclareAsShadow.]
1244
1245  SideEffects []
1246
1247  SeeAlso     [Ntk_LatchReadDataInput Ntk_LatchReadInitialInput]
1248
1249******************************************************************************/
1250void
1251Ntk_NodeDeclareAsLatch(
1252  Ntk_Node_t * latch,
1253  char * dataName,
1254  char * initName)
1255{
1256  Ntk_Node_t    *dataNode;
1257  Ntk_Node_t    *initNode;
1258  Ntk_Network_t *network = latch->network;
1259 
1260  assert(latch->type == NtkUnassigned_c);
1261  latch->type = NtkLatch_c;
1262
1263  /*
1264   * Get the nodes corresponding to dataName and initName.
1265   */
1266  dataNode = Ntk_NetworkFindNodeByName(network, dataName);
1267  initNode = Ntk_NetworkFindNodeByName(network, initName);
1268  assert(dataNode != NIL(Ntk_Node_t));
1269  assert(initNode != NIL(Ntk_Node_t));
1270
1271  /*
1272   * Make the necessary connections. Note the predefined locations of the data
1273   * and initial inputs in the fanin array of latch.
1274   */
1275  array_insert(Ntk_Node_t *, latch->fanins, LATCH_DATA, dataNode);
1276  array_insert(Ntk_Node_t *, latch->fanins, LATCH_INITIAL, initNode);
1277
1278  array_insert_last(Ntk_Node_t *, dataNode->fanouts, latch);
1279  array_insert_last(Ntk_Node_t *, initNode->fanouts, latch);
1280
1281  /*
1282   * Set the special flags in the data and init nodes, and add them to the
1283   * list of combinational outputs.
1284   */
1285  dataNode->latchDataInput = 1;
1286  NetworkAddCombOutput(network, dataNode);
1287
1288  initNode->latchInitialInput = 1;
1289  NetworkAddCombOutput(network, initNode);
1290
1291  /*
1292   * Add the latch to the appropriate lists in network.
1293   */
1294  lsNewEnd(network->latches,    (lsGeneric) latch, LS_NH);
1295  lsNewEnd(network->combInputs, (lsGeneric) latch, LS_NH);
1296}
1297
1298
1299/**Function********************************************************************
1300
1301  Synopsis    [Declares a node as a primary input.]
1302
1303  Description [Declares a node as a primary input.  Adds node to the relevant
1304  node lists maintained by the node's network.]
1305
1306  SideEffects []
1307
1308  SeeAlso     [Ntk_NodeDeclareAsPrimaryOutput]
1309
1310******************************************************************************/
1311void
1312Ntk_NodeDeclareAsPrimaryInput(
1313  Ntk_Node_t * node)
1314{
1315  assert(node->type == NtkUnassigned_c);
1316  node->type = NtkPrimaryInput_c;
1317
1318  lsNewEnd(node->network->primaryInputs, (lsGeneric) node, LS_NH);
1319  lsNewEnd(node->network->inputs,        (lsGeneric) node, LS_NH);
1320  lsNewEnd(node->network->combInputs,    (lsGeneric) node, LS_NH);
1321}
1322
1323
1324/**Function********************************************************************
1325
1326  Synopsis    [Declares a node as a pseudo input.]
1327
1328  Description [Declares a node as a pseudo input.  The function of a pseudo
1329  input is given by the column of table corresponding to outputIndex.  This
1330  function does not make a copy of the table; instead, it just sets a pointer
1331  to it.  However, it's assumed that the table will own the table, and the
1332  table is freed when the node is freed.  Adds node to the relevant node lists
1333  maintained by the node's network.]
1334
1335  SideEffects []
1336
1337  SeeAlso     [Ntk_NodeDeclareAsPrimaryInput]
1338
1339******************************************************************************/
1340void
1341Ntk_NodeDeclareAsPseudoInput(
1342  Ntk_Node_t * node,
1343  Tbl_Table_t * table,
1344  int  outputIndex)
1345{
1346  assert(node->type == NtkUnassigned_c);
1347
1348  node->type        = NtkPseudoInput_c;
1349  node->table       = table;
1350  node->outputIndex = outputIndex;
1351 
1352  if (Tbl_TableTestIsConstant(table, outputIndex)) {
1353    node->constant = 1;
1354  }
1355 
1356  lsNewEnd(node->network->pseudoInputs, (lsGeneric) node, LS_NH);
1357  lsNewEnd(node->network->inputs,       (lsGeneric) node, LS_NH);
1358  lsNewEnd(node->network->combInputs,   (lsGeneric) node, LS_NH);
1359}
1360
1361
1362/**Function********************************************************************
1363
1364  Synopsis    [Declares a node as a primary output.]
1365
1366  Description [Declares a node as a primary output.  Node can be of any type,
1367  except type shadow.]
1368
1369  SideEffects []
1370
1371  SeeAlso     [Ntk_TestIsPrimaryOutput]
1372
1373******************************************************************************/
1374void
1375Ntk_NodeDeclareAsPrimaryOutput(
1376  Ntk_Node_t * node)
1377{
1378  assert(node->type != NtkShadow_c);
1379  node->outputFlag = 1;
1380  lsNewEnd(node->network->primaryOutputs, (lsGeneric) node, LS_NH);
1381  NetworkAddCombOutput(node->network, node);
1382}
1383
1384
1385/**Function********************************************************************
1386
1387  Synopsis    [Declares a node as a shadow node.]
1388
1389  Description [Declares a node as a shadow node. A shadow node is used to
1390  associate extra information with a node, in particular another MDD id.  Any
1391  "origin" node can have a shadow node, except a node which itself is of type
1392  shadow. This function makes the bidirectional link between the shadow and
1393  origin nodes.]
1394
1395  SideEffects []
1396
1397  SeeAlso     [Ntk_NodeTestIsShadow Ntk_ShadowReadOrigin Ntk_NodeReadShadow]
1398
1399******************************************************************************/
1400void
1401Ntk_NodeDeclareAsShadow(
1402  Ntk_Node_t * shadow,
1403  Ntk_Node_t * origin)
1404{
1405  assert(shadow->type == NtkUnassigned_c);
1406  assert(origin->type != NtkShadow_c);
1407 
1408  shadow->type = NtkShadow_c;
1409
1410  shadow->shadowInfo.origin = origin;
1411  origin->shadowInfo.shadow = shadow;
1412}
1413
1414
1415/**Function********************************************************************
1416
1417  Synopsis    [Frees all the memory local to the node.]
1418
1419  Description [Frees all the memory local to the node, including the node
1420  itself. Does not free the nodes in the fanin and fanout of node, nor does it
1421  free the network of node.  Also, this function does not update the lists
1422  maintained by the network to reflect that this node no longer exists, nor
1423  does it update the fanin and fanout lists of neighboring nodes.]
1424
1425  SideEffects []
1426
1427  SeeAlso     [Ntk_NodeCreateInNetwork]
1428
1429******************************************************************************/
1430void
1431Ntk_NodeFree(
1432  Ntk_Node_t * node)
1433{
1434  FREE(node->name);
1435  array_free(node->fanins);
1436  array_free(node->fanouts);
1437  Tbl_TableFree(node->table);
1438 
1439  /*
1440   * Unassign a few key fields for safety's sake.
1441   */
1442  node->name              = NIL(char);
1443  node->network           = NIL(Ntk_Network_t);
1444  node->variable          = NIL(Var_Variable_t);
1445  node->type              = NtkUnassigned_c;
1446  node->fanins            = NIL(array_t);
1447  node->fanouts           = NIL(array_t);
1448  node->table             = NIL(Tbl_Table_t);
1449  node->mddId             = NTK_UNASSIGNED_MDD_ID;
1450
1451  FREE(node);
1452}
1453
1454
1455/*---------------------------------------------------------------------------*/
1456/* Definition of internal functions                                          */
1457/*---------------------------------------------------------------------------*/
1458
1459
1460/*---------------------------------------------------------------------------*/
1461/* Definition of static functions                                            */
1462/*---------------------------------------------------------------------------*/
1463/**Function********************************************************************
1464
1465  Synopsis    [Adds a node to the network's list of combinational outputs.]
1466
1467  Description [Adds a node to the network's list of combinational outputs. If
1468  the list already contains the node, then nothing is done.  List membership
1469  is maintained via a hash table.]
1470
1471  SideEffects []
1472
1473  SeeAlso     [Ntk_NetworkForEachCombOutput]
1474
1475******************************************************************************/
1476static void
1477NetworkAddCombOutput(
1478  Ntk_Network_t *network,
1479  Ntk_Node_t    *node)
1480{
1481  if (!st_is_member(network->combOutputsTable, (char *) node)) {
1482    st_insert(network->combOutputsTable, (char *) node, (char *) 0);
1483    lsNewEnd(network->combOutputs, (lsGeneric) node, LS_NH);
1484  }
1485}
1486
1487   
1488
1489
1490
Note: See TracBrowser for help on using the repository browser.