gnetlist
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gnetlist - gEDA Netlist 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 00021 #include <config.h> 00022 #include <missing.h> 00023 00024 #include <stdio.h> 00025 #ifdef HAVE_STRING_H 00026 #include <string.h> 00027 #endif 00028 #include <math.h> 00029 00030 #include <libgeda/libgeda.h> 00031 00032 #include "../include/globals.h" 00033 #include "../include/prototype.h" 00034 00035 #ifdef HAVE_LIBDMALLOC 00036 #include <dmalloc.h> 00037 #endif 00038 00044 static GHashTable *visit_table = NULL; 00045 00047 static gboolean 00048 returns_true (gpointer key, gpointer value, gpointer user_data) 00049 { 00050 return TRUE; 00051 } 00052 00054 static inline gint 00055 is_visited(OBJECT *obj) 00056 { 00057 gpointer val; 00058 gpointer orig_key; 00059 gboolean exist = g_hash_table_lookup_extended (visit_table, 00060 obj, 00061 &orig_key, 00062 &val); 00063 return exist ? GPOINTER_TO_INT(val) : 0; 00064 } 00065 00067 static inline gint 00068 visit(OBJECT *obj) 00069 { 00070 gpointer val = GINT_TO_POINTER(is_visited (obj) + 1); 00071 g_hash_table_replace (visit_table, obj, val); 00072 return GPOINTER_TO_INT (val); 00073 } 00074 00076 static inline void 00077 s_traverse_clear_all_visited (const GList *obj_list) 00078 { 00079 g_hash_table_foreach_remove (visit_table, 00080 (GHRFunc) returns_true, 00081 NULL); 00082 } 00083 00084 void s_traverse_init(void) 00085 { 00086 netlist_head = s_netlist_add(NULL); 00087 netlist_head->nlid = -1; /* head node */ 00088 00089 graphical_netlist_head = s_netlist_add(NULL); 00090 graphical_netlist_head->nlid = -1; /* head node */ 00091 00092 if (verbose_mode) { 00093 printf 00094 ("\n\n------------------------------------------------------\n"); 00095 printf("Verbose mode legend\n\n"); 00096 printf("n : Found net\n"); 00097 printf("C : Found component (staring to traverse component)\n"); 00098 printf 00099 ("p : Found pin (starting to traverse pin / or examining pin)\n"); 00100 printf("P : Found end pin connection (end of this net)\n"); 00101 printf("R : Starting to rename a net\n"); 00102 printf("v : Found source attribute, traversing down\n"); 00103 printf("^ : Finished underlying source, going back up\n"); 00104 printf("u : Found a refdes which needs to be demangle\n"); 00105 printf 00106 ("U : Found a connected_to refdes which needs to be demangle\n"); 00107 printf 00108 ("------------------------------------------------------\n\n"); 00109 00110 } 00111 00112 /* Initialise the hashtable which contains the visit 00113 count. N.b. no free functions are required. */ 00114 visit_table = g_hash_table_new (g_direct_hash, 00115 g_direct_equal); 00116 } 00117 00118 void s_traverse_start(TOPLEVEL * pr_current) 00119 { 00120 GList *iter; 00121 PAGE *p_current; 00122 00123 for ( iter = geda_list_get_glist( pr_current->pages ); 00124 iter != NULL; 00125 iter = g_list_next( iter ) ) { 00126 00127 p_current = (PAGE *)iter->data; 00128 00129 /* only traverse pages which are toplevel, ie not underneath */ 00130 if (p_current->page_control == 0) { 00131 pr_current->page_current = p_current; 00132 s_traverse_sheet (pr_current, s_page_objects (p_current), NULL); 00133 } 00134 } 00135 00136 /* now that all the sheets have been read, go through and do the */ 00137 /* post processing work */ 00138 s_netlist_post_process(pr_current, netlist_head); 00139 00140 /* Now match the graphical netlist with the net names already assigned */ 00141 s_netlist_name_named_nets(pr_current, netlist_head, 00142 graphical_netlist_head); 00143 00144 if (verbose_mode) { 00145 printf("\nInternal netlist representation:\n\n"); 00146 s_netlist_print(netlist_head); 00147 } 00148 } 00149 00150 00151 void 00152 s_traverse_sheet (TOPLEVEL * pr_current, const GList *obj_list, char *hierarchy_tag) 00153 { 00154 NETLIST *netlist; 00155 char *temp; 00156 SCM scm_uref; 00157 char *temp_uref; 00158 gboolean is_graphical=FALSE; 00159 const GList *iter; 00160 00161 if (verbose_mode) { 00162 printf("- Starting internal netlist creation\n"); 00163 } 00164 00165 for (iter = obj_list; iter != NULL; iter = g_list_next (iter)) { 00166 OBJECT *o_current = iter->data; 00167 00168 netlist = s_netlist_return_tail(netlist_head); 00169 00170 if (o_current->type == OBJ_PLACEHOLDER) { 00171 printf("WARNING: Found a placeholder/missing component, are you missing a symbol file? [%s]\n", o_current->complex_basename); 00172 } 00173 00174 if (o_current->type == OBJ_COMPLEX) { 00175 00176 #if DEBUG 00177 printf("starting NEW component\n\n"); 00178 #endif 00179 00180 verbose_print(" C"); 00181 00182 /* look for special tag */ 00183 temp = o_attrib_search_object_attribs_by_name (o_current, "graphical", 0); 00184 if (temp) { 00185 /* traverse graphical elements, but adding them to the 00186 graphical netlist */ 00187 g_free(temp); 00188 00189 netlist = s_netlist_return_tail(graphical_netlist_head); 00190 is_graphical = TRUE; 00191 00192 00193 } 00194 netlist = s_netlist_add(netlist); 00195 netlist->nlid = o_current->sid; 00196 00197 scm_uref = g_scm_c_get_uref(pr_current, o_current); 00198 00199 if (scm_is_string( scm_uref )) { 00200 temp_uref = scm_to_utf8_string (scm_uref); 00201 netlist->component_uref = 00202 s_hierarchy_create_uref(pr_current, temp_uref, hierarchy_tag); 00203 g_free(temp_uref); 00204 } else { 00205 if (hierarchy_tag) { 00206 netlist->component_uref = g_strdup (hierarchy_tag); 00207 } else { 00208 netlist->component_uref = NULL; 00209 } 00210 } 00211 00212 if (hierarchy_tag) { 00213 netlist->hierarchy_tag = g_strdup (hierarchy_tag); 00214 } 00215 00216 netlist->object_ptr = o_current; 00217 00218 if (!netlist->component_uref) { 00219 00220 /* search of net attribute */ 00221 /* maybe symbol is not a component */ 00222 /* but a power / gnd symbol */ 00223 temp = o_attrib_search_object_attribs_by_name (o_current, "net", 0); 00224 00225 /* nope net attribute not found */ 00226 if ( (!temp) && (!is_graphical) ) { 00227 00228 fprintf(stderr, 00229 "Could not find refdes on component and could not find any special attributes!\n"); 00230 00231 netlist->component_uref = g_strdup("U?"); 00232 } else { 00233 00234 #if DEBUG 00235 printf("yeah... found a power symbol\n"); 00236 #endif 00237 /* it's a power or some other special symbol */ 00238 netlist->component_uref = NULL; 00239 g_free(temp); 00240 } 00241 00242 } 00243 00244 netlist->cpins = 00245 s_traverse_component(pr_current, o_current, 00246 hierarchy_tag); 00247 00248 /* here is where you deal with the */ 00249 /* net attribute */ 00250 s_netattrib_handle(pr_current, o_current, netlist, 00251 hierarchy_tag); 00252 00253 /* now you need to traverse any underlying schematics */ 00254 if (pr_current->hierarchy_traversal == TRUE) { 00255 s_hierarchy_traverse(pr_current, o_current, netlist); 00256 } 00257 } 00258 } 00259 00260 verbose_done(); 00261 } 00262 00263 CPINLIST *s_traverse_component(TOPLEVEL * pr_current, OBJECT * component, 00264 char *hierarchy_tag) 00265 { 00266 CPINLIST *cpinlist_head = NULL; 00267 CPINLIST *cpins = NULL; 00268 NET *nets_head = NULL; 00269 NET *nets = NULL; 00270 GList *iter; 00271 00272 cpinlist_head = cpins = s_cpinlist_add(NULL); 00273 cpins->plid = -1; 00274 00275 for (iter = component->complex->prim_objs; 00276 iter != NULL; 00277 iter = g_list_next (iter)) { 00278 OBJECT *o_current = iter->data; 00279 00280 /* Ignore objects which aren't net pins */ 00281 if (o_current->type != OBJ_PIN || 00282 o_current->pin_type != PIN_TYPE_NET) 00283 continue; 00284 00285 /* add cpin node */ 00286 cpins = s_cpinlist_add(cpins); 00287 cpins->plid = o_current->sid; 00288 cpins->type = o_current->pin_type; 00289 00290 cpins->pin_number = 00291 o_attrib_search_object_attribs_by_name (o_current, "pinnumber", 0); 00292 00293 cpins->pin_label = 00294 o_attrib_search_object_attribs_by_name (o_current, "pinlabel", 0); 00295 00296 /* head nets node */ 00297 /* is this really need */ 00298 nets_head = nets = s_net_add(NULL); 00299 nets->nid = -1; 00300 00301 /* This avoids us adding an unnamed net for an unconnected pin */ 00302 if (o_current->conn_list != NULL) { 00303 (void) s_traverse_net (pr_current, nets, TRUE, 00304 o_current, hierarchy_tag, cpins->type); 00305 s_traverse_clear_all_visited (s_page_objects (pr_current->page_current)); 00306 } 00307 00308 cpins->nets = nets_head; 00309 /* s_net_print(nets); */ 00310 } 00311 00312 00313 return (cpinlist_head); 00314 } 00315 00316 00317 static int connection_type (OBJECT *object) 00318 { 00319 switch (object->type) { 00320 case OBJ_PIN: return object->pin_type; 00321 case OBJ_NET: return PIN_TYPE_NET; 00322 case OBJ_BUS: return PIN_TYPE_BUS; 00323 default: 00324 g_critical ("Non-connectable object being queried for connection type\n"); 00325 return PIN_TYPE_NET; 00326 } 00327 } 00328 00329 00330 NET *s_traverse_net (TOPLEVEL *pr_current, NET *nets, int starting, 00331 OBJECT *object, char *hierarchy_tag, int type) 00332 { 00333 NET *new_net; 00334 CONN *c_current; 00335 GList *cl_current; 00336 char *temp = NULL; 00337 00338 visit (object); 00339 00340 if (connection_type (object) != type) 00341 return nets; 00342 00343 new_net = nets = s_net_add(nets); 00344 new_net->nid = object->sid; 00345 00346 /* pins are not allowed to have the netname attribute attached to them */ 00347 if (object->type != OBJ_PIN) { 00348 /* Ignore netname attributes on buses */ 00349 if (object->type == OBJ_NET) 00350 temp = o_attrib_search_object_attribs_by_name (object, "netname", 0); 00351 00352 if (temp) { 00353 new_net->net_name = 00354 s_hierarchy_create_netname(pr_current, temp, 00355 hierarchy_tag); 00356 g_free(temp); 00357 } else if (object->type == OBJ_NET) { 00358 /* search for the old label= attribute on nets */ 00359 temp = o_attrib_search_object_attribs_by_name (object, "label", 0); 00360 if (temp) { 00361 printf("WARNING: Found label=%s. label= is deprecated, please use netname=\n", temp); 00362 new_net->net_name = 00363 s_hierarchy_create_netname(pr_current, temp, 00364 hierarchy_tag); 00365 g_free(temp); 00366 } 00367 } 00368 } 00369 #if DEBUG 00370 printf("inside traverse: %s\n", object->name); 00371 #endif 00372 00373 if (object->type == OBJ_PIN) { 00374 00375 verbose_print (starting ? "p" : "P"); 00376 00377 new_net->connected_to = 00378 s_net_return_connected_string (pr_current, object, hierarchy_tag); 00379 00380 temp = o_attrib_search_object_attribs_by_name (object, "pinlabel", 0); 00381 00382 if (temp) { 00383 new_net->pin_label = temp; 00384 } 00385 00386 /* net= new */ 00387 if (strstr(nets->connected_to, "POWER") && 00388 type == PIN_TYPE_NET) { 00389 00390 #if DEBUG 00391 printf("going to find netname %s \n", nets->connected_to); 00392 #endif 00393 nets->net_name = 00394 s_netattrib_return_netname (pr_current, object, 00395 nets->connected_to, 00396 hierarchy_tag); 00397 nets->net_name_has_priority = TRUE; 00398 g_free(nets->connected_to); 00399 nets->connected_to = NULL; 00400 } 00401 #if DEBUG 00402 printf("traverse connected_to: %s\n", new_net->connected_to); 00403 #endif 00404 00405 /* Terminate if we hit a pin which isn't the one we started with */ 00406 if (!starting) 00407 return nets; 00408 } 00409 00410 /*printf("Found net %s\n", object->name); */ 00411 verbose_print("n"); 00412 00413 /* this is not perfect yet and won't detect a loop... */ 00414 if (is_visited(object) > 100) { 00415 fprintf(stderr, "Found a possible net/pin infinite connection\n"); 00416 exit(-1); 00417 } 00418 00419 cl_current = object->conn_list; 00420 while (cl_current != NULL) { 00421 00422 c_current = (CONN *) cl_current->data; 00423 00424 if (c_current->other_object != NULL) { 00425 00426 if (!is_visited(c_current->other_object) && 00427 c_current->other_object != object) { 00428 nets = s_traverse_net (pr_current, nets, FALSE, 00429 c_current->other_object, hierarchy_tag, type); 00430 } 00431 00432 } 00433 cl_current = g_list_next(cl_current); 00434 } 00435 00436 return (nets); 00437 }