1 /* gEDA - GPL Electronic Design Automation
2 * gnetlist - gEDA Netlist
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <libgeda/libgeda.h>
31 #include "../include/globals.h"
32 #include "../include/prototype.h"
33 #include "../include/gettext.h"
35 /*! Tracks which OBJECTs have been visited so far, and how many times.
37 * The keys of the table are the OBJECT pointers, and the visit count
38 * is stored directly in the value pointers.
40 static GHashTable
*visit_table
= NULL
;
42 /*! Trivial function used when clearing #visit_table. */
44 returns_true (gpointer key
, gpointer value
, gpointer user_data
)
49 /*! Retrieve the current visit count for a particular OBJECT. */
51 is_visited(OBJECT
*obj
)
55 gboolean exist
= g_hash_table_lookup_extended (visit_table
,
59 return exist
? GPOINTER_TO_INT(val
) : 0;
62 /*! Increment the current visit count for a particular OBJECT. */
66 gpointer val
= GINT_TO_POINTER(is_visited (obj
) + 1);
67 g_hash_table_replace (visit_table
, obj
, val
);
68 return GPOINTER_TO_INT (val
);
71 /*! Reset all visit counts. Simply clears the hashtable completely. */
73 s_traverse_clear_all_visited (const GList
*obj_list
)
75 g_hash_table_foreach_remove (visit_table
,
76 (GHRFunc
) returns_true
,
80 void s_traverse_init(void)
82 netlist_head
= s_netlist_add(NULL
);
83 netlist_head
->nlid
= -1; /* head node */
85 graphical_netlist_head
= s_netlist_add(NULL
);
86 graphical_netlist_head
->nlid
= -1; /* head node */
90 ("\n\n------------------------------------------------------\n");
91 printf("Verbose mode legend\n\n");
92 printf("n : Found net\n");
93 printf("C : Found component (staring to traverse component)\n");
95 ("p : Found pin (starting to traverse pin / or examining pin)\n");
96 printf("P : Found end pin connection (end of this net)\n");
97 printf("R : Starting to rename a net\n");
98 printf("v : Found source attribute, traversing down\n");
99 printf("^ : Finished underlying source, going back up\n");
100 printf("u : Found a refdes which needs to be demangle\n");
102 ("U : Found a connected_to refdes which needs to be demangle\n");
104 ("------------------------------------------------------\n\n");
108 /* Initialise the hashtable which contains the visit
109 count. N.b. no free functions are required. */
110 visit_table
= g_hash_table_new (g_direct_hash
,
114 void s_traverse_start(TOPLEVEL
* pr_current
)
119 for ( iter
= geda_list_get_glist( pr_current
->pages
);
121 iter
= g_list_next( iter
) ) {
123 p_current
= (PAGE
*)iter
->data
;
125 /* only traverse pages which are toplevel, ie not underneath */
126 if (p_current
->page_control
== 0) {
127 pr_current
->page_current
= p_current
;
128 s_traverse_sheet (pr_current
, s_page_objects (p_current
), NULL
);
132 /* now that all the sheets have been read, go through and do the */
133 /* post processing work */
134 s_netlist_post_process(pr_current
, netlist_head
);
136 /* Now match the graphical netlist with the net names already assigned */
137 s_netlist_name_named_nets(pr_current
, netlist_head
,
138 graphical_netlist_head
);
141 printf("\nInternal netlist representation:\n\n");
142 s_netlist_print(netlist_head
);
148 s_traverse_sheet (TOPLEVEL
* pr_current
, const GList
*obj_list
, char *hierarchy_tag
)
157 printf("- Starting internal netlist creation\n");
160 for (iter
= obj_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
161 OBJECT
*o_current
= iter
->data
;
163 netlist
= s_netlist_return_tail(netlist_head
);
165 if (o_current
->type
== OBJ_PLACEHOLDER
) {
166 printf(_("WARNING: Found a placeholder/missing component, are you missing a symbol file? [%s]\n"), o_current
->complex_basename
);
169 if (o_current
->type
== OBJ_COMPLEX
) {
170 gboolean is_graphical
= FALSE
;
173 printf("starting NEW component\n\n");
178 /* look for special tag */
179 temp
= o_attrib_search_object_attribs_by_name (o_current
, "graphical", 0);
180 if (g_strcmp0 (temp
, "1") == 0) {
181 /* traverse graphical elements, but adding them to the
184 netlist
= s_netlist_return_tail(graphical_netlist_head
);
190 netlist
= s_netlist_add(netlist
);
191 netlist
->nlid
= o_current
->sid
;
193 scm_uref
= g_scm_c_get_uref (o_current
);
195 if (scm_is_string( scm_uref
)) {
196 temp_uref
= scm_to_utf8_string (scm_uref
);
197 netlist
->component_uref
=
198 s_hierarchy_create_uref(pr_current
, temp_uref
, hierarchy_tag
);
202 netlist
->component_uref
= g_strdup (hierarchy_tag
);
204 netlist
->component_uref
= NULL
;
209 netlist
->hierarchy_tag
= g_strdup (hierarchy_tag
);
212 netlist
->object_ptr
= o_current
;
214 if (!netlist
->component_uref
) {
216 /* search of net attribute */
217 /* maybe symbol is not a component */
218 /* but a power / gnd symbol */
219 temp
= o_attrib_search_object_attribs_by_name (o_current
, "net", 0);
221 /* nope net attribute not found */
222 if ( (!temp
) && (!is_graphical
) ) {
225 _("Could not find refdes on component and could not find any special attributes!\n"));
227 netlist
->component_uref
= g_strdup("U?");
231 printf("yeah... found a power symbol\n");
233 /* it's a power or some other special symbol */
234 netlist
->component_uref
= NULL
;
241 s_traverse_component(pr_current
, o_current
,
244 /* here is where you deal with the */
246 s_netattrib_handle(pr_current
, o_current
, netlist
,
249 /* now you need to traverse any underlying schematics */
250 if (pr_current
->hierarchy_traversal
== TRUE
) {
251 s_hierarchy_traverse(pr_current
, o_current
, netlist
);
259 CPINLIST
*s_traverse_component(TOPLEVEL
* pr_current
, OBJECT
* component
,
262 CPINLIST
*cpinlist_head
= NULL
;
263 CPINLIST
*cpins
= NULL
;
264 NET
*nets_head
= NULL
;
268 cpinlist_head
= cpins
= s_cpinlist_add(NULL
);
271 for (iter
= component
->complex->prim_objs
;
273 iter
= g_list_next (iter
)) {
274 OBJECT
*o_current
= iter
->data
;
276 /* Ignore objects which aren't net pins */
277 if (o_current
->type
!= OBJ_PIN
||
278 o_current
->pin_type
!= PIN_TYPE_NET
)
282 cpins
= s_cpinlist_add(cpins
);
283 cpins
->plid
= o_current
->sid
;
284 cpins
->type
= o_current
->pin_type
;
287 o_attrib_search_object_attribs_by_name (o_current
, "pinnumber", 0);
290 o_attrib_search_object_attribs_by_name (o_current
, "pinlabel", 0);
293 /* is this really need */
294 nets_head
= nets
= s_net_add(NULL
);
297 /* This avoids us adding an unnamed net for an unconnected pin */
298 if (o_current
->conn_list
!= NULL
) {
299 s_traverse_net (pr_current
, nets
, TRUE
,
300 o_current
, hierarchy_tag
, cpins
->type
);
301 s_traverse_clear_all_visited (s_page_objects (pr_current
->page_current
));
304 cpins
->nets
= nets_head
;
305 /* s_net_print(nets); */
309 return (cpinlist_head
);
313 static int connection_type (OBJECT
*object
)
315 switch (object
->type
) {
316 case OBJ_PIN
: return object
->pin_type
;
317 case OBJ_NET
: return PIN_TYPE_NET
;
318 case OBJ_BUS
: return PIN_TYPE_BUS
;
320 g_critical (_("Non-connectable object being queried for connection type\n"));
326 NET
*s_traverse_net (TOPLEVEL
*pr_current
, NET
*nets
, int starting
,
327 OBJECT
*object
, char *hierarchy_tag
, int type
)
333 const gchar
*netattrib_pinnum
= NULL
;
337 if (connection_type (object
) != type
)
340 new_net
= nets
= s_net_add(nets
);
341 new_net
->nid
= object
->sid
;
343 /* pins are not allowed to have the netname attribute attached to them */
344 if (object
->type
!= OBJ_PIN
) {
345 /* Ignore netname attributes on buses */
346 if (object
->type
== OBJ_NET
)
347 temp
= o_attrib_search_object_attribs_by_name (object
, "netname", 0);
351 s_hierarchy_create_netname(pr_current
, temp
,
354 } else if (object
->type
== OBJ_NET
) {
355 /* search for the old label= attribute on nets */
356 temp
= o_attrib_search_object_attribs_by_name (object
, "label", 0);
358 printf(_("WARNING: Found label=%s. label= is deprecated, please use netname=\n"), temp
);
360 s_hierarchy_create_netname(pr_current
, temp
,
367 printf("inside traverse: %s\n", object
->name
);
370 if (object
->type
== OBJ_PIN
) {
372 verbose_print (starting
? "p" : "P");
374 new_net
->connected_to
=
375 s_net_return_connected_string (pr_current
, object
, hierarchy_tag
);
377 temp
= o_attrib_search_object_attribs_by_name (object
, "pinlabel", 0);
380 new_net
->pin_label
= temp
;
384 netattrib_pinnum
= s_netattrib_connected_string_get_pinnum (nets
->connected_to
);
385 if (netattrib_pinnum
!= NULL
&& type
== PIN_TYPE_NET
) {
388 printf("going to find netname %s \n", nets
->connected_to
);
391 s_netattrib_return_netname (pr_current
, object
,
394 nets
->net_name_has_priority
= TRUE
;
395 g_free(nets
->connected_to
);
396 nets
->connected_to
= NULL
;
399 printf("traverse connected_to: %s\n", new_net
->connected_to
);
402 /* Terminate if we hit a pin which isn't the one we started with */
407 /*printf("Found net %s\n", object->name); */
410 /* this is not perfect yet and won't detect a loop... */
411 if (is_visited(object
) > 100) {
412 fprintf(stderr
, _("Found a possible net/pin infinite connection\n"));
416 cl_current
= object
->conn_list
;
417 while (cl_current
!= NULL
) {
419 c_current
= (CONN
*) cl_current
->data
;
421 if (c_current
->other_object
!= NULL
) {
423 if (!is_visited(c_current
->other_object
) &&
424 c_current
->other_object
!= object
) {
425 nets
= s_traverse_net (pr_current
, nets
, FALSE
,
426 c_current
->other_object
, hierarchy_tag
, type
);
430 cl_current
= g_list_next(cl_current
);