1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 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., 59 Temple Place, Suite 330, Boston, MA 02111 USA
28 #include "libgeda_priv.h"
30 #ifdef HAVE_LIBDMALLOC
35 * \brief The connection system
37 * The connection system stores and tracks the connections between
38 * connected <b>OBJECTS</b>. The connected OBJECTS are either
39 * <b>pins</b>, <b>nets</b> and <b>busses</b>.
41 * Each connection object with the type <b>st_conn</b> represents a
42 * single unidirectional relation to another object.
44 * The following figure with two nets and a pin shows the relations
45 * between connections and OBJECTS:
47 * \image html s_conn_overview.png
48 * \image latex s_conn_overview.pdf "Connection overview" width=14cm
52 /*! \brief create a new connection object
53 * \par Function Description
54 * create a single st_conn object and initialize it with the
57 * \return The new connection object
59 CONN
*s_conn_return_new(OBJECT
* other_object
, int type
, int x
, int y
,
60 int whichone
, int other_whichone
)
64 new_conn
= (CONN
*) g_malloc(sizeof(CONN
));
67 printf("** creating: %s %d %d\n", other_object
->name
, x
, y
);
70 new_conn
->other_object
= other_object
;
71 new_conn
->type
= type
;
74 new_conn
->whichone
= whichone
;
75 new_conn
->other_whichone
= other_whichone
;
80 /*! \brief check if a connection is uniq in a list
81 * \par Function Description
82 * This function checks if there's no identical connection
83 * in the list of connections.
84 * \param conn_list list of connection objects
85 * \param input_conn single connection object.
86 * \return TRUE if the CONN structure is unique, FALSE otherwise.
88 int s_conn_uniq(GList
* conn_list
, CONN
* input_conn
)
93 c_current
= conn_list
;
94 while (c_current
!= NULL
) {
95 conn
= (CONN
*) c_current
->data
;
97 if (conn
->other_object
== input_conn
->other_object
&&
98 conn
->x
== input_conn
->x
&& conn
->y
== input_conn
->y
&&
99 conn
->type
== input_conn
->type
) {
103 c_current
= g_list_next(c_current
);
109 /*! \brief remove a object from the connection list of another object
110 * \par Function Description
111 * This function removes the OBJECT <b>to_remove</b> from the connection
112 * list of the OBJECT <b>other_object</b>.
113 * \param toplevel (currently not used)
114 * \param other_object OBJECT from that the to_remove OBJECT needs to be removed
115 * \param to_remove OBJECT to remove
116 * \return TRUE if a connection has been deleted, FALSE otherwise
118 int s_conn_remove_other (TOPLEVEL
*toplevel
, OBJECT
*other_object
,
121 GList
*c_current
= NULL
;
124 c_current
= other_object
->conn_list
;
125 while (c_current
!= NULL
) {
126 conn
= (CONN
*) c_current
->data
;
128 if (conn
->other_object
== to_remove
) {
129 other_object
->conn_list
=
130 g_list_remove(other_object
->conn_list
, conn
);
133 printf("Found other_object in remove_other\n");
134 printf("Freeing other: %s %d %d\n", conn
->other_object
->name
,
138 /* Do not write modify c_current like this, since this will cause */
139 /* very nasty data corruption and upset glib's memory slice */
141 /* c_current->data = NULL; Do not comment in */
145 #if 0 /* this does not work right */
146 if (other_object
->type
== OBJ_BUS
&&
147 other_object
->conn_list
== NULL
) {
148 other_object
->bus_ripper_direction
= 0;
155 c_current
= g_list_next(c_current
);
161 /*! \brief removes a GList of OBJECTs from the connection system
163 * \par Function Description
164 * This function removes all connections from and to the OBJECTS
165 * of the given GList.
167 * \param toplevel (currently not used)
168 * \param obj_list GList of OBJECTs to unconnected from all other objects
170 static void s_conn_remove_glist (TOPLEVEL
*toplevel
, GList
*obj_list
)
175 for (iter
= obj_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
176 o_current
= iter
->data
;
177 s_conn_remove_object (toplevel
, o_current
);
181 /*! \brief remove an OBJECT from the connection system
182 * \par Function Description
183 * This function removes all connections from and to the OBJECT
185 * \param toplevel (currently not used)
186 * \param to_remove OBJECT to unconnected from all other objects
188 void s_conn_remove_object (TOPLEVEL
*toplevel
, OBJECT
*to_remove
)
193 switch (to_remove
->type
) {
197 for (c_iter
= to_remove
->conn_list
;
199 c_iter
= g_list_next (c_iter
)) {
202 /* keep calling this till it returns false (all refs removed) */
203 /* there is NO body to this while loop */
204 while (s_conn_remove_other (toplevel
, conn
->other_object
, to_remove
));
210 g_list_free (to_remove
->conn_list
);
211 to_remove
->conn_list
= NULL
;
215 case OBJ_PLACEHOLDER
:
216 s_conn_remove_glist (toplevel
, to_remove
->complex->prim_objs
);
221 /*! \brief Checks if a point is a midpoint of an OBJECT
222 * \par Function Description
223 * Checks if the point (<b>x</b>,<b>y</b>) is on the OBJECT
224 * and between it's endpoints.
225 * \return TRUE if the point is a midpoint of the OBJECT. FALSE
226 * if the point is not a midpoinit or if the OBJECT is not a
227 * NET a PIN or a BUS or if the OBJECT
228 * has neither horizontal nor vertical orientation.
230 OBJECT
*s_conn_check_midpoint(OBJECT
*o_current
, int x
, int y
)
232 int min_x
, min_y
, max_x
, max_y
;
234 switch(o_current
->type
) {
238 min_y
= min(o_current
->line
->y
[0],
239 o_current
->line
->y
[1]);
240 max_y
= max(o_current
->line
->y
[0],
241 o_current
->line
->y
[1]);
244 if ( (o_current
->line
->x
[0] == x
) &&
245 (y
> min_y
) && (y
< max_y
) &&
246 (o_current
->line
->x
[0] ==
247 o_current
->line
->x
[1]) ) {
249 printf("Found vertical point\n");
254 min_x
= min(o_current
->line
->x
[0],
255 o_current
->line
->x
[1]);
256 max_x
= max(o_current
->line
->x
[0],
257 o_current
->line
->x
[1]);
260 if ( (o_current
->line
->y
[0] == y
) &&
261 (x
> min_x
) && (x
< max_x
) &&
262 (o_current
->line
->y
[0] ==
263 o_current
->line
->y
[1]) ) {
265 printf("Found horizontal point\n");
275 /*! \brief adds a GList of OBJECTs to the connection system
277 * \par Function Description
278 * This function adds all connections from and to the OBJECTS
279 * of the given GList.
281 * \param toplevel (currently not used)
282 * \param obj_list GList of OBJECTs to add into the connection system
284 void s_conn_update_glist (TOPLEVEL
*toplevel
, GList
*obj_list
)
289 for (iter
= obj_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
290 o_current
= iter
->data
;
291 s_conn_update_object (toplevel
, o_current
);
296 /*! \brief Checks if an object is bus, or a bus pin
298 * \par Function Description
299 * Checks if an object is a bus or a bus pin
301 * \param object The OBJECT to test
302 * \return TRUE if the objects is a bis, or bus pin
304 static int is_bus_related (OBJECT
*object
)
306 return (object
->type
== OBJ_BUS
||
307 (object
->type
== OBJ_PIN
&& object
->pin_type
== PIN_TYPE_BUS
));
311 /*! \brief Checks if two objects are of compatible types to be connected
313 * \par Function Description
314 * Checks if two objects are legal to be connected together
316 * \param object1 First OBJECT
317 * \param object2 Second OBJECT
318 * \return TRUE if the objects are compatible, FALSE if not
320 static int check_direct_compat (OBJECT
*object1
, OBJECT
*object2
)
322 return (is_bus_related (object1
) == is_bus_related (object2
));
326 static void add_connection (OBJECT
*object
, OBJECT
*other_object
,
327 int type
, int x
, int y
,
328 int whichone
, int other_whichone
)
330 /* Describe the connection */
331 CONN
*new_conn
= s_conn_return_new (other_object
, type
, x
, y
,
332 whichone
, other_whichone
);
333 /* Do uniqness check */
334 if (s_conn_uniq (object
->conn_list
, new_conn
)) {
335 object
->conn_list
= g_list_append (object
->conn_list
, new_conn
);
341 /*! \brief add a line OBJECT to the connection system
342 * \par Function Description
343 * This function searches for all geometrical conections of the OBJECT
344 * <b>object</b> to all other connectable objects. It adds connections
345 * to the object and from all other
346 * objects to this one.
347 * \param toplevel (currently not used)
348 * \param object OBJECT to add into the connection system
350 static void s_conn_update_line_object (TOPLEVEL
*toplevel
, OBJECT
*object
)
355 OBJECT
*other_object
;
359 /* loop over all tiles which object appears in */
360 for (tl_current
= object
->tiles
;
362 tl_current
= g_list_next (tl_current
)) {
363 t_current
= tl_current
->data
;
365 for (object_list
= t_current
->objects
;
367 object_list
= g_list_next (object_list
)) {
368 other_object
= object_list
->data
;
370 if (object
== other_object
)
373 /* Here is where you check the end points */
374 /* Check both end points of the other object */
375 for (k
= 0; k
< 2; k
++) {
377 /* If the other object is a pin, only check the correct end */
378 if (other_object
->type
== OBJ_PIN
&& other_object
->whichend
!= k
)
381 /* Check both end points of the object */
382 for (j
= 0; j
< 2; j
++) {
384 /* If the object is a pin, only check the correct end */
385 if (object
->type
== OBJ_PIN
&& object
->whichend
!= j
)
388 /* Check for coincidence and compatability between
389 the objects being tested. */
390 if (object
->line
->x
[j
] == other_object
->line
->x
[k
] &&
391 object
->line
->y
[j
] == other_object
->line
->y
[k
] &&
392 check_direct_compat (object
, other_object
)) {
394 add_connection (object
, other_object
, CONN_ENDPOINT
,
395 other_object
->line
->x
[k
],
396 other_object
->line
->y
[k
], j
, k
);
398 add_connection (other_object
, object
, CONN_ENDPOINT
,
400 object
->line
->y
[j
], k
, j
);
405 /* Check both end points of the object against midpoints of the other */
406 for (k
= 0; k
< 2; k
++) {
408 /* If the object is a pin, only check the correct end */
409 if (object
->type
== OBJ_PIN
&& object
->whichend
!= k
)
412 /* check for midpoint of other object, k endpoint of current obj*/
413 found
= s_conn_check_midpoint (other_object
, object
->line
->x
[k
],
416 /* Pins are not allowed midpoint connections onto them. */
417 /* Allow nets to connect to the middle of buses. */
418 /* Allow compatible objects to connect. */
419 if (found
&& other_object
->type
!= OBJ_PIN
&&
420 ((object
->type
== OBJ_NET
&& other_object
->type
== OBJ_BUS
) ||
421 check_direct_compat (object
, other_object
))) {
423 add_connection (object
, other_object
, CONN_MIDPOINT
,
425 object
->line
->y
[k
], k
, -1);
427 add_connection (other_object
, object
, CONN_MIDPOINT
,
429 object
->line
->y
[k
], -1, k
);
433 /* Check both end points of the other object against midpoints of the first */
434 for (k
= 0; k
< 2; k
++) {
436 /* If the other object is a pin, only check the correct end */
437 if (other_object
->type
== OBJ_PIN
&& other_object
->whichend
!= k
)
440 /* do object's endpoints cross the middle of other_object? */
441 /* check for midpoint of other object, k endpoint of current obj*/
442 found
= s_conn_check_midpoint (object
, other_object
->line
->x
[k
],
443 other_object
->line
->y
[k
]);
445 /* Pins are not allowed midpoint connections onto them. */
446 /* Allow nets to connect to the middle of buses. */
447 /* Allow compatible objects to connect. */
448 if (found
&& object
->type
!= OBJ_PIN
&&
449 ((object
->type
== OBJ_BUS
&& other_object
->type
== OBJ_NET
) ||
450 check_direct_compat (object
, other_object
))) {
452 add_connection (object
, other_object
, CONN_MIDPOINT
,
453 other_object
->line
->x
[k
],
454 other_object
->line
->y
[k
], -1, k
);
456 add_connection (other_object
, object
, CONN_MIDPOINT
,
457 other_object
->line
->x
[k
],
458 other_object
->line
->y
[k
], k
, -1);
466 s_conn_print(object
->conn_list
);
470 /*! \brief add an OBJECT to the connection system
472 * \par Function Description
473 * This function searches for all geometrical conections of the OBJECT
474 * <b>object</b> to all other connectable objects. It adds connections
475 * to the object and from all other objects to this one.
477 * \param toplevel (currently not used)
478 * \param object OBJECT to add into the connection system
480 void s_conn_update_object (TOPLEVEL
*toplevel
, OBJECT
*object
)
482 switch (object
->type
) {
486 s_conn_update_line_object (toplevel
, object
);
490 case OBJ_PLACEHOLDER
:
491 s_conn_update_glist (toplevel
, object
->complex->prim_objs
);
496 /*! \brief print all connections of a connection list
497 * \par Function Description
498 * This is a debugging function to print a List of connections.
499 * \param conn_list GList of connection objects
501 void s_conn_print(GList
* conn_list
)
506 printf("\nStarting s_conn_print\n");
507 cl_current
= conn_list
;
508 while (cl_current
!= NULL
) {
510 conn
= (CONN
*) cl_current
->data
;
511 printf("-----------------------------------\n");
512 printf("other object: %s\n", conn
->other_object
->name
);
513 printf("type: %d\n", conn
->type
);
514 printf("x: %d y: %d\n", conn
->x
, conn
->y
);
515 printf("whichone: %d\n", conn
->whichone
);
516 printf("other_whichone: %d\n", conn
->other_whichone
);
517 printf("-----------------------------------\n");
519 cl_current
= g_list_next(cl_current
);
524 /*! \brief Search for net in existing connections.
525 * \par Function Description
526 * This method searches the connection list for the first matching
527 * connection with the given x, y, and whichone endpoint.
529 * \param [in] new_net Net OBJECT to compare to.
530 * \param [in] whichone The connection number to check.
531 * \param [in] conn_list List of existing connections to compare
533 * \return TRUE if a matching connection is found, FALSE otherwise.
535 int s_conn_net_search(OBJECT
* new_net
, int whichone
, GList
* conn_list
)
540 cl_current
= conn_list
;
541 while (cl_current
!= NULL
) {
543 conn
= (CONN
*) cl_current
->data
;
544 if (conn
!= NULL
&& conn
->whichone
== whichone
&&
545 conn
->x
== new_net
->line
->x
[whichone
] &&
546 conn
->y
== new_net
->line
->y
[whichone
])
551 cl_current
= g_list_next(cl_current
);
557 /*! \brief get a list of all objects connected to a list of OBJECTs.
559 * \par Function Description
560 * This function gets all other_object from the connection
561 * list of the OBJECTs in the pased list.
563 * \param [in] input_list GList of OBJECT's or NULL
564 * \param [in] obj_list The GList of OBJECT to get connections from
565 * \return A GList of objects
568 * Caller must g_list_free returned GList pointer.
569 * Do not free individual data items in list.
571 static GList
*s_conn_return_glist_others (GList
*input_list
, GList
*obj_list
)
577 return_list
= input_list
;
579 for (iter
= obj_list
; iter
!= NULL
; iter
= g_list_next (iter
)) {
580 o_current
= iter
->data
;
581 return_list
= s_conn_return_others (return_list
, o_current
);
587 /*! \brief get a list of all objects connected to this one
589 * \par Function Description
590 * This function gets all other_object from the connection list of the current object.
591 * COMPLEX objects are entered, and their prim_objs processed. If an <b>input_list</b>
592 * is given, the other objects are appended to that list.
594 * \param [in] input_list GList of OBJECT's
595 * \param [in] object OBJECT to get other OBJECTs from
596 * \return A GList of OBJECTs
599 * Caller must g_list_free returned GList pointer.
600 * Do not free individual data items in list.
602 GList
*s_conn_return_others(GList
*input_list
, OBJECT
*object
)
607 return_list
= input_list
;
609 switch (object
->type
) {
613 for (c_iter
= object
->conn_list
;
614 c_iter
!= NULL
; c_iter
= g_list_next (c_iter
)) {
615 CONN
*conn
= c_iter
->data
;
617 if (conn
->other_object
&& conn
->other_object
!= object
) {
618 return_list
= g_list_append(return_list
, conn
->other_object
);
624 case OBJ_PLACEHOLDER
:
625 return_list
= s_conn_return_glist_others (return_list
,
626 object
->complex->prim_objs
);