1 /************************************************************
3 ** COPYRIGHT (C) 1993 UNIVERSITY OF PITTSBURGH
4 ** COPYRIGHT (C) 1996 GANNON UNIVERSITY
7 ** This software is distributed on an as-is basis
8 ** with no warranty implied or intended. No author
9 ** or distributor takes responsibility to anyone
10 ** regarding its use of or suitability.
12 ** The software may be distributed and modified
13 ** freely for academic and other non-commercial
14 ** use but may NOT be utilized or included in whole
15 ** or part within any commercial product.
17 ** This copyright notice must remain on all copies
18 ** and modified versions of this software.
20 ************************************************************/
24 /* ------------------------------------------------------------------------
25 * Helper / Utility routines for place and route spl 7/89
27 * ------------------------------------------------------------------------
31 #include "system_defs.h"
36 #include "asg_module.h"
38 /*---------------------------------------------------------------
40 *---------------------------------------------------------------
48 /*---------------------------------------------------------------
49 * my_calloc: replacement for C utility "calloc", using the Tcl
50 * routine Tcl_Alloc followed by bzero to initialize memory.
51 *---------------------------------------------------------------
55 my_calloc(size_t nmemb
, size_t size
)
58 size_t memsiz
= nmemb
* size
;
60 memloc
= (void *)Tcl_Alloc(memsiz
);
61 if (memloc
) bzero(memloc
, memsiz
);
65 #endif /* TCL_WRAPPER */
67 /*---------------------------------------------------------------
68 * error: generic error reporting, should have more on line numbers etc.
70 * Warning: This routine name conflicts with a C utility, so
71 * it is necessary to order the libraries correctly when linking
72 * to avoid an incorrect link.
73 *---------------------------------------------------------------
79 Fprintf(stderr
, "ERROR, line %d: %s\n\t%s\n", lcount
, s1
, s2
);
84 /*---------------------------------------------------------------
85 * side_of: return the module side for the terminal t (module is unique)
86 *---------------------------------------------------------------
93 error("side_of passed NULL terminal","");
95 else if (t
->mod
== NULL
)
97 error("side_of passed terminal with no module","");
105 /*---------------------------------------------------------------
107 * find, and mark the terminals which connect the output of
108 * one module to the input of the next, in a string.
109 *---------------------------------------------------------------
111 mark_connection (m1
, m2
)
117 for (l
= m1
->terms
; l
!= NULL
; l
= l
->next
)
119 if (l
->this->type
== OUT
) /* ignore (l->this->type == INOUT) */
121 for(ll
= l
->this->nt
->terms
; ll
!= NULL
; ll
= ll
->next
)
123 if((ll
->this->mod
->index
== m2
->index
)
125 (ll
->this->type
== IN
) /* ignore (ll->this->type == INOUT) */
128 m1
->primary_out
= l
->this;
129 m2
->primary_in
= ll
->this;
137 error("mark_connection: two modules were not connected", m1
->name
);
141 /* ------------------------------------------------------------------------
142 * insert_index_list insert (by index) an element to a 2d list structure
144 * ------------------------------------------------------------------------
146 llist
*insert_index_list(element
, indx
, lst
)
153 if((lst
== NULL
)||(lst
->index
> indx
))
155 tl
= (llist
*)calloc(1, sizeof(llist
));
159 tl
->values
= concat_list(element
, tl
->values
);
164 for(l
= lst
; ; l
= l
->next
)
168 /* we already have a list at this index */
169 l
->values
= concat_list(element
, l
->values
);
172 if ( (l
->next
== NULL
) || (l
->next
->index
> indx
))
173 {/* note we are counting on order of above exp */
175 /* we hit the end or fall between two existing lists */
176 tl
= (llist
*)calloc(1, sizeof(llist
));
181 tl
->values
= concat_list(element
, tl
->values
);
188 /* ------------------------------------------------------------------------
189 * get_net: do a lookup on all the nets, by name.
190 * could be done with a hash table a-la rsim.
191 * ------------------------------------------------------------------------
199 for (n
= nets
; n
!= NULL
; n
= n
->next
)
200 if (!strcmp(n
->this->name
, name
))
203 /* error ("get_net, net used before it is declared ", name); */
207 /*---------------------------------------------------------------
209 *---------------------------------------------------------------
211 char *str_end_dup(new, old
, n
)
215 /* Copy the last <n> characters from <old> to <new>. */
216 int i
, len
= strlen(old
);
218 new = (char *)calloc(NET_NAME_SIZE
+ 1, sizeof(char));
221 strncpy(new, old
, n
);
224 new[i
] = old
[len
-n
+i
];
228 else strcpy(new, old
);
233 /* ------------------------------------------------------------------------
234 * newnode: add a new net to the global list of nets
235 * ------------------------------------------------------------------------
244 node
= (net
*)calloc(1, sizeof(net
));
245 node
->rflag
= 0; /* Added 11-3-90 stf; Used in Global Router */
248 node
->name
= strdup(name
);
250 /* initialize -- spl 9/30/89 */
253 /* check to see if this is a global input/output node
254 * this is a hack, it would not have to be done execpt that
255 * the current ivf format does not list the i/o nodes in the
256 * flattened discription so we have to pull that out of the
257 * hierarchy first, and leave them on this ext_terms list
258 * here is where we tie the info together.
261 for(t
= ext_terms
; t
!= NULL
; t
= t
->next
)
263 if (!strcmp(t
->this->name
, node
->name
))
265 node
->terms
= (tlist
*)concat_list(t
->this, node
->terms
);
267 node
->type
= (t
->this->type
== IN
) ?
268 OUT
: (t
->this->type
== OUT
) ? IN
: INOUT
;
270 nets
= (nlist
*)concat_list(node
, nets
);
272 t
->this->nt
= node
; /* have the term point to it's parent node */
274 node_count
++; /* for statistics */
280 /* otherwise we have to do it all */
282 node
->type
= NONE
; /* not global in/out */
284 nets
= (nlist
*)concat_list(node
, nets
);
286 node_count
++; /* for statistics */
290 /* ------------------------------------------------------------------------
291 * set_default_object_size
292 * match the object type to some defualt sizes, based on the expected
293 * sizes of the icons.
294 * NOTE: This function interacts with the ps_print functions in "psfigs.c"
295 * ------------------------------------------------------------------------
297 set_default_object_size(type
, x
, y
)
301 switch(validate(type
))
305 case NOT_
: *x
= GATE_HEIGHT
;
313 case XNOR
: *x
= GATE_LENGTH
;
317 case OUTPUT_SYM
: *x
= SYSTERM_SIZE
;
328 /* ------------------------------------------------------------------------
330 * create a new object/module and install it in the global list
331 * ------------------------------------------------------------------------
333 module
*newobject(gate_name
, gate_type
)
334 char *gate_name
, *gate_type
;
338 if(module_count
>= MAX_MOD
)
340 error("newobject: too many modules, change MAX_MOD and recompile",
346 object
= (module
*)calloc(1, sizeof(module
));
347 object
->index
= module_count
++;
348 object
->name
= strdup(gate_name
);
349 object
->type
= strdup(gate_type
);
352 object
->flag
= UNSEEN
;
353 object
->placed
= UNPLACED
;
354 object
->rot
= LEFT
; /* assme no rotation */
355 object
->primary_in
= NULL
;
356 object
->primary_out
= NULL
;
357 object
->terms
= NULL
;
358 object
->fx
= create_var_struct(ADD
, NULL
, NULL
);
359 object
->fy
= create_var_struct(ADD
, NULL
, NULL
);
360 set_default_object_size(object
->type
, &object
->x_size
, &object
->y_size
);
362 modules
= (mlist
*)concat_list(object
, modules
);
366 /* ------------------------------------------------------------------------
367 * addin: add a signal to the list of terminals for a module
368 * ------------------------------------------------------------------------
370 void addin(name
, index
, noOfTerms
)
375 /* MODIFICATION 6-11-90 Skip "_DUMMY_SIGNAL_", "guard","$1" and $0" strings... */
376 if ((!strcmp(name
, STR_DUMMY_SIGNAL
)) ||
377 (!strcmp(name
, SIG_ZERO
)) ||
378 (!strcmp(name
, SIG_ONE
)) ||
379 (!strcmp(name
, STR_GUARD_SIGNAL
))) /* See "system_defs.h" */
381 add_special(name
, index
, noOfTerms
, IN
);
384 else add_in_out(name
, index
, noOfTerms
, IN
);
386 /* ------------------------------------------------------------------------
387 * addout: add a signal to the list of terminals for a module
388 * ------------------------------------------------------------------------
390 void addout(name
, index
, noOfTerms
)
395 /* MODIFICATION 6-11-90 Skip "_DUMMY_SIGNAL_", "$1" and $0" strings... */
396 if ((!strcmp(name
, STR_DUMMY_SIGNAL
)) ||
397 (!strcmp(name
, SIG_ZERO
)) ||
398 (!strcmp(name
, SIG_ONE
)) ||
399 (!strcmp(name
, STR_GUARD_SIGNAL
))) /* See "system_defs.h" */
401 add_special(name
, index
, noOfTerms
, OUT
);
404 else add_in_out(name
, index
, noOfTerms
, OUT
);
406 /* ------------------------------------------------------------------------
407 * addinout: add a signal to the list of terminals for a module
408 * ------------------------------------------------------------------------
410 void addinout(name
, index
, noOfTerms
)
415 /* MODIFICATION 6-11-90 Skip "_DUMMY_SIGNAL_", "$1" and $0" strings... */
416 if ((!strcmp(name
, STR_DUMMY_SIGNAL
)) ||
417 (!strcmp(name
, SIG_ZERO
)) ||
418 (!strcmp(name
, SIG_ONE
)) ||
419 (!strcmp(name
, STR_GUARD_SIGNAL
))) /* See "system_defs.h" */
421 add_special(name
, index
, noOfTerms
, INOUT
);
424 else add_in_out(name
, index
, noOfTerms
, INOUT
);
427 void addoutin(name
, index
, noOfTerms
)
432 /* MODIFICATION 6-11-90 Skip "_DUMMY_SIGNAL_", "$1" and $0" strings... */
433 if ((!strcmp(name
, STR_DUMMY_SIGNAL
)) ||
434 (!strcmp(name
, SIG_ZERO
)) ||
435 (!strcmp(name
, SIG_ONE
)) ||
436 (!strcmp(name
, STR_GUARD_SIGNAL
))) /* See "system_defs.h" */
438 add_special(name
, index
, noOfTerms
,OUTIN
);
441 else add_in_out(name
, index
, noOfTerms
,OUTIN
);
445 /* ------------------------------------------------------------------------
446 * relative_term_location: determine where a signal should be located on the module:
447 * ------------------------------------------------------------------------
449 int relative_term_location(termNo
, termsOnEdge
, edgeLength
, spacesPerPin
)
450 int termNo
, termsOnEdge
, edgeLength
, spacesPerPin
;
452 int offset
, space
= edgeLength
/ (termsOnEdge
+ 1);
454 if (termsOnEdge
> edgeLength
) return(termNo
);
455 else if (termsOnEdge
== edgeLength
) return(termNo
+ 1);
456 else if (termNo
> termsOnEdge
) return(termNo
); /* Problem !! */
457 else if (termsOnEdge
<= 3)
461 case 1 : return(edgeLength
/2);
462 case 2 : if (termNo
== 0) return(space
);
463 else return(edgeLength
- space
);
464 case 3 : switch (termNo
)
466 case 0 : return(edgeLength
- space
);
467 case 1 : return(edgeLength
/2);
468 case 2 : return(space
);
472 else /* Space things out evenly via spacesPerPin (used to set <edgeLength>)*/
474 space
= edgeLength
/ termsOnEdge
;
475 offset
= (edgeLength
- (termsOnEdge
* space
) + space
)/2;
477 if (offset
< 0) offset
= 0;
479 if ((termsOnEdge
> edgeLength
/spacesPerPin
) &&
480 (termNo
> termsOnEdge
/spacesPerPin
))
482 /* This should never be an important result - see "addpositions" */
483 return((termNo
- termsOnEdge
/spacesPerPin
) * space
);
485 else return((termNo
* space
) + offset
);
489 if space == 0, the progression is 1, 2, 3, 4 ...
490 if space == 1, the progression is 1, 3, 5, 7 ...
491 if space == 2, the progression is 1, 4, 7, 10 ...
494 /* ------------------------------------------------------------------------
495 * add_in_out: add a signal to the list of terminals for a module
496 * ------------------------------------------------------------------------
498 void add_in_out(name
, index
, noOfTerms
, dir
)
500 int index
, noOfTerms
, dir
;
506 tt
= (term
*)calloc(1, sizeof(term
));
508 /* find this net in the global database */
511 tt
->mod
= curobj_module
;
512 tt
->name
= (char *)calloc(1, TERM_NAME_SIZE
);
517 sprintf(tt
->name
, "input_%d", index
);
520 tt
->x_pos
= -1; /* -1 is the old hack to put terms outside of module */
521 /* hack to center inputs on left side. Also see "addpositions" */
522 tt
->y_pos
= relative_term_location(index
, noOfTerms
, tt
->mod
->y_size
, SPACES_PER_PIN
);
525 sprintf(tt
->name
, "output_%d", index
);
528 tt
->x_pos
= tt
->mod
->x_size
+ 1; /* add 1 hack to center outputs on
530 tt
->y_pos
= relative_term_location(index
, noOfTerms
, tt
->mod
->y_size
, SPACES_PER_PIN
);
531 tt
->mod
->primary_out
= tt
; /* hack to see that all mods have a PO */
535 sprintf(tt
->name
, "inout_%d", index
);
536 tt
->side
= UP
; /* MODIFICATION 20-10-89 stf (labels are up) */
537 /* MOD 6-11-90 (SHOULD BE 'UP'- SCED LABELS AREN'T USED */
540 /* MOD 5-2-91 INOUT's are distributed accross the top of the icon */
541 tt
->x_pos
= relative_term_location(index
, noOfTerms
, tt
->mod
->x_size
, SPACES_PER_PIN
);
542 tt
->y_pos
= tt
->mod
->y_size
+ 1; /* Put at top of icon... */
546 sprintf(tt
->name
, "inout_%d", index
);
547 tt
->side
= BOTTOM
; /* MODIFICATION 20-10-89 stf (labels are up) */
548 /* MOD 6-11-90 (SHOULD BE 'UP'- SCED LABELS AREN'T USED */
551 /* MOD 5-2-91 INOUT's are distributed accross the top of the icon */
552 tt
->x_pos
= relative_term_location(index
, noOfTerms
, tt
->mod
->x_size
, SPACES_PER_PIN
);
553 tt
->y_pos
= -1; /* Put at top of icon... */
555 default: error("add_in_out: terminal with bad direction", name
);
558 curobj_module
->terms
= (tlist
*)concat_list(tt
, curobj_module
->terms
);
560 /* tie the term back into the list of terms on this net */
562 tn
->terms
= (tlist
*)concat_list(tt
, tn
->terms
);
565 /* ------------------------------------------------------------------------
566 * add_xc_term: add a signal to the list of terminals for a module
567 * based on the XCircuit object for gate "name".
569 * If "pinName" is non-NULL, it points to a string containing the
570 * pin name. If "pinName" is NULL, then the target symbol is
571 * searched for a SPICE info label, and the pin name is pulled
573 * ------------------------------------------------------------------------
576 void add_xc_term(type
, pinName
, netName
, index
, numpins
)
587 int result
, x
, y
, a
, b
, c
;
590 /* Get the xcircuit object name corresponding to the module */
591 if (NameToObject(type
, &xc_inst
, FALSE
) == NULL
) return;
593 /* If the pinName is NULL, try go get the pin name from the object */
594 if (pinName
== NULL
) {
595 locPin
= parsepininfo(xc_inst
, "spice", index
);
596 if (locPin
== NULL
) locPin
= defaultpininfo(xc_inst
, index
);
597 if (locPin
== NULL
) return; /* No pins; can't do much! */
599 else locPin
= pinName
;
601 /* Find the location of the pin named "pinName" relative to the object position */
602 result
= NameToPinLocation(xc_inst
, locPin
, &x
, &y
);
605 /* Temporary hack---shift all coordinates relative to the bounding box corner */
606 /* x -= xc_inst->bbox.lowerleft.x; */
607 /* y -= xc_inst->bbox.lowerleft.y; */
610 if (locPin
!= pinName
) free(locPin
);
611 add_in_out(netName
, index
, numpins
, INOUT
); /* backup behavior */
612 return; /* if pin name not found */
615 tt
= (term
*)calloc(1, sizeof(term
));
617 /* find this net in the global database */
618 tn
= get_net(netName
);
621 tt
->mod
= curobj_module
;
622 if (locPin
!= pinName
)
625 tt
->name
= (char *)calloc(1, TERM_NAME_SIZE
);
626 sprintf(tt
->name
, pinName
);
629 /* Treat all (analog) signals as "inout", but determine which side */
630 /* is closest to the pin position. */
631 /* sprintf(tt->name, "inout_%d", index); */ /* former behavior */
636 /* Check for position of label relative to the object center and */
637 /* set value as IN/LEFT, OUT/RIGHT, etc. */
638 /* Divide the object's bounding box into quadrants based on */
639 /* diagonals through the center, and give the pin a placement LEFT */
640 /* (IN), RIGHT (OUT) accordingly. */
642 a
= (x
- xc_inst
->bbox
.lowerleft
.x
) * xc_inst
->bbox
.height
;
643 b
= (y
- xc_inst
->bbox
.lowerleft
.y
) * xc_inst
->bbox
.width
;
644 c
= a
- (xc_inst
->bbox
.width
* xc_inst
->bbox
.height
);
646 if ((a
< b
) && (c
< -b
)) {
663 curobj_module
->terms
= (tlist
*)concat_list(tt
, curobj_module
->terms
);
665 /* tie the term back into the list of terms on this net */
667 tn
->terms
= (tlist
*)concat_list(tt
, tn
->terms
);
670 /* ------------------------------------------------------------------------
671 * add_special: add a special terminal to a module
672 * ------------------------------------------------------------------------
674 void add_special(name
, index
, noOfTerms
, dir
)
676 int index
, noOfTerms
, dir
;
682 tt
= (term
*)calloc(1, sizeof(term
));
683 tt
->nt
= NULL
; /* Special terminals have no nets */
685 tt
->mod
= curobj_module
;
686 tt
->name
= (char *)calloc(1, TERM_NAME_SIZE
);
691 sprintf(tt
->name
, "%s_input_%d", name
, index
);
693 tt
->x_pos
= -1; /* -1 is the old hack to put terms outside of module */
694 /* hack to center inputs on left side. Also see "addpositions" */
695 tt
->y_pos
= relative_term_location(index
, noOfTerms
, tt
->mod
->y_size
, SPACES_PER_PIN
);
698 sprintf(tt
->name
, "%s_output_%d", name
, index
);
700 tt
->x_pos
= tt
->mod
->x_size
+ 1; /* add 1 hack to center outputs on
702 tt
->y_pos
= relative_term_location(index
, noOfTerms
, tt
->mod
->y_size
, SPACES_PER_PIN
);
703 tt
->mod
->primary_out
= tt
; /* hack to see that all mods have a PO */
706 sprintf(tt
->name
, "%s_inout_%d", name
, index
);
707 tt
->side
= UP
; /* MODIFICATION 20-10-89 stf (labels are up) */
708 /* MOD 6-11-90 (SHOULD BE 'UP'- SCED LABELS AREN'T USED */
710 /* MOD 5-2-91 INOUT's are distributed accross the top of the icon */
711 tt
->x_pos
= relative_term_location(index
, noOfTerms
, tt
->mod
->x_size
, SPACES_PER_PIN
);
712 tt
->y_pos
= tt
->mod
->y_size
+ 1; /* Put at top of icon... */
716 sprintf(tt
->name
, "inout_%d", index
);
717 tt
->side
= BOTTOM
; /* MODIFICATION 20-10-89 stf (labels are up) */
718 /* MOD 6-11-90 (SHOULD BE 'UP'- SCED LABELS AREN'T USED */
721 /* MOD 5-2-91 INOUT's are distributed accross the top of the icon */
722 tt
->x_pos
= relative_term_location(index
, noOfTerms
, tt
->mod
->x_size
, SPACES_PER_PIN
);
723 tt
->y_pos
= -1; /* Put at top of icon... */
725 default: error("add_special: terminal with bad direction", name
);
727 /* The TYPE is based on the signal name: */
728 if (!strcmp(name
, SIG_ZERO
)) tt
->type
= GND
;
729 else if (!strcmp(name
, SIG_ONE
)) tt
->type
= VDD
;
730 else tt
->type
= DUMMY
;
732 /* Add the terminal to the growing list of terminals for this module: */
733 curobj_module
->terms
= (tlist
*)concat_list(tt
, curobj_module
->terms
);
736 /* ------------------------------------------------------------------------
737 * named_net_p - Return TRUE if the net name matches the given string.
738 *-------------------------------------------------------------------------
740 int named_net_p(nName
, t
)
744 if (!strcmp(nName
, t
->nt
->name
)) return(TRUE
);
748 /* ------------------------------------------------------------------------
749 * classify_terminal - return the type (IN, OUT, INOUT, OUTIN) for the term
750 * based on it's relative position on the module.
751 *-------------------------------------------------------------------------
753 int classify_terminal(m
, t
)
757 if (t
->x_pos
>= m
->x_size
)
759 if (t
->y_pos
>= m
->y_size
)
764 else if (t
->y_pos
<= 0)
775 else if (t
->x_pos
<= 0)
777 if (t
->y_pos
>= m
->y_size
)
782 else if (t
->y_pos
<= 0)
793 else if (t
->y_pos
>= m
->y_size
)
805 /* ------------------------------------------------------------------------
806 * fix_pin_position - for a given named net, part of the given module,
807 * fix the pin position to the (x,y) coordinates given:
808 *-------------------------------------------------------------------------
810 int fix_pin_position(m
, nn
, x
, y
)
812 char *nn
; /* The name of the net being fixed */
815 tlist
*tl
= (tlist
*)member(nn
, m
->terms
, named_net_p
);
819 /* Adjust the pin position to be just outside the icon, rather than on
821 if (Xcanvas_scaling
== FALSE
)
823 if (x
== 0) adjX
= -1;
824 else if (x
== m
->x_size
) adjX
= x
+1;
827 if (y
== 0) adjY
= -1;
828 else if (y
== m
->y_size
) adjY
= y
+1;
831 else /* Treat for XCanvas conventions - note that the origin of the
832 module is at the top left corner, not lower left corner: */
834 if (x
== 0)adjX
= -1;
835 else if (x
/XCANVAS_SCALE_FACTOR
== m
->x_size
) adjX
= (x
/XCANVAS_SCALE_FACTOR
)+1;
836 else adjX
= x
/XCANVAS_SCALE_FACTOR
;
838 if (y
== 0) adjY
= m
->y_size
+ 1;
839 else if (y
/XCANVAS_SCALE_FACTOR
== m
->y_size
) adjY
= -1;
840 else adjY
= m
->y_size
- (y
/XCANVAS_SCALE_FACTOR
);
845 /* put tl->this at the end of the terminal list, and hopefully enable
846 other terminals on the same net <nn> to be found: */
847 rem_item(tl
->this, &m
->terms
);
848 queue(tl
->this, &m
->terms
);
850 /* Assign the new position to the terminal: */
851 tl
->this->x_pos
= adjX
;
852 tl
->this->y_pos
= adjY
;
854 /* NOW - reclassify the terminal: */
855 tl
->this->type
= classify_terminal(m
, tl
->this);
859 Fprintf(stderr
, "Bad netname %s trying to be fixed for module %s\n",
864 /* ------------------------------------------------------------------------
865 * reset_default_icon_size - use the x,y dimensions added 3-92 (stf)
866 *-------------------------------------------------------------------------
868 int reset_default_icon_size(m
, x
, y
)
872 m
->x_size
= (Xcanvas_scaling
== FALSE
) ? x
: x
/XCANVAS_SCALE_FACTOR
;
873 m
->y_size
= (Xcanvas_scaling
== FALSE
) ? y
: y
/XCANVAS_SCALE_FACTOR
;
875 /* ------------------------------------------------------------------------
876 * adjust_icon_size - make the x-y ratio nice (1-4)
877 *-------------------------------------------------------------------------
879 int adjust_icon_size(m
, vTerminals
, hTerminals
)
880 /* Adjust the x side of tall blocks, etc.. Return TRUE if something was modified */
883 int mType
= validate(m
->type
), mX
= m
->x_size
, mY
= m
->y_size
;
884 if ((mType
== BLOCK
) || (mType
== DONT_KNOW
))
886 if (m
->x_size
/ m
->y_size
< 3)
888 if ((m
->x_size
>= 2 * ICON_SIZE
) && (m
->y_size
/3 >= vTerminals
* 2))
889 m
->x_size
= m
->y_size
/3;
890 else if (m
->y_size
/2 >= vTerminals
* 2)
891 m
->x_size
= m
->y_size
/2;
893 else if (m
->y_size
/ m
->x_size
< 3)
895 if ((m
->y_size
>= 2 * ICON_SIZE
) && (m
->x_size
/3 >= hTerminals
* 2))
896 m
->y_size
= m
->x_size
/3;
897 else if (m
->x_size
/2 >= hTerminals
* 2)m
->y_size
= m
->x_size
/2;
900 if ((m
->x_size
!= mX
) || (m
->y_size
!= mY
)) return(TRUE
);
905 /* ------------------------------------------------------------------------
906 * addpositions: add the real postions for the terminals, as set by the
907 * icon file, if we can find it. Otherwise use the defaults that were
908 * done above in add_in_out.
909 * Note we do open and read each icon file for each occurance, which might
910 * be slow. If this turns out to be the case, we have started to keep
911 * track of things: we can re-use the range-list (rlist) we use for the
912 * terminal positions, we just have to keep it somewhere. See the
913 * hack note in sced.c
914 * ------------------------------------------------------------------------
916 void addpositions(cur_module
, incount
, inoutcount
, outcount
)
918 int incount
, inoutcount
, outcount
;
921 int adjustTerminals
= FALSE
;
922 int type
= validate(cur_module
->type
);
923 int spacesPerPin
= ((type
== BLOCK
) || (type
== DONT_KNOW
)) ?
924 BLOCK_SPACES_PER_PIN
: SPACES_PER_PIN
;
926 if (compute_aspect_ratios
== TRUE
)
928 /* Might need to resize the bloody icon if its too bloody small. */
929 if (inoutcount
> cur_module
->x_size
/spacesPerPin
)
931 /* the default iconsize won't cut it. This will fail in screwey sits. */
932 cur_module
->x_size
= SPACES_PER_PIN
* inoutcount
;
933 adjustTerminals
= TRUE
;
936 if ((incount
> cur_module
->y_size
/ spacesPerPin
) ||
937 (outcount
> cur_module
->y_size
/ spacesPerPin
))
939 /* the default iconsize won't cut it */
940 cur_module
->y_size
= spacesPerPin
* MAX(incount
, outcount
);
941 adjustTerminals
= TRUE
;
944 /* Check to see if there is wasted terminal space: (Icon is too big) */
945 if ( ((cur_module
->y_size
/ spacesPerPin
) > MAX(incount
+ 1, outcount
+ 1)) ||
946 ((cur_module
->x_size
/ SPACES_PER_PIN
) > inoutcount
+ 1))
948 adjustTerminals
= TRUE
;
951 if ((adjust_icon_size(cur_module
, MAX(incount
, outcount
), inoutcount
) == TRUE
)
953 (adjustTerminals
== TRUE
))
955 /* now reset all terminal positions to reflect this: */
956 reposition_all_terminals(cur_module
, incount
, inoutcount
,
957 outcount
, spacesPerPin
);
962 /* ------------------------------------------------------------------------ */
963 int get_terminal_counts(m
, ins
, inouts
, outs
)
965 int *ins
, *inouts
, *outs
;
968 for (tl
= m
->terms
; tl
!= NULL
; tl
= tl
->next
)
970 switch(tl
->this->type
)
974 case INOUT
: *inouts
+= 1;
976 case OUT
: *outs
+= 1;
982 /* ------------------------------------------------------------------------ */
986 /* Get the expected pin spacing for the given module type: */
987 int type
= validate(m
->type
);
988 int spacesPerPin
= ((type
== BLOCK
) || (type
== DONT_KNOW
)) ?
989 BLOCK_SPACES_PER_PIN
: SPACES_PER_PIN
;
990 return(spacesPerPin
);
993 /* ------------------------------------------------------------------------ */
994 int reposition_all_terminals(m
, incount
, inoutcount
, outcount
, spacesPerPin
)
996 int incount
, inoutcount
, outcount
, spacesPerPin
;
998 /* Reset the positions of all terminals, based on the counts and spacings
1002 int INindex
= 0, INOUTindex
= 0, OUTindex
= 0;
1004 for (tl
= m
->terms
; tl
!= NULL
; tl
= tl
->next
)
1006 switch(tl
->this->type
)
1009 tl
->this->y_pos
= relative_term_location(INindex
++, incount
,
1010 m
->y_size
, spacesPerPin
);
1011 tl
->this->x_pos
= -1;
1015 tl
->this->x_pos
= relative_term_location(INOUTindex
++, inoutcount
,
1016 m
->x_size
, spacesPerPin
);
1017 tl
->this->y_pos
= m
->y_size
+ 1;
1021 tl
->this->y_pos
= relative_term_location(OUTindex
++, outcount
,
1022 m
->y_size
, spacesPerPin
);
1023 tl
->this->x_pos
= m
->x_size
+ 1;
1030 /* ------------------------------------------------------------------------
1031 * add_port: add a terminal to the list of system terminals
1032 * this list is different from the other terminal lists:
1033 * the names are realy net-names, and there is no module
1034 * or net associated with them. We add the net (which
1035 * has the same name) later, when we find it.
1036 * ------------------------------------------------------------------------
1037 * MODIFICATION (stf 9-89) additions made to create a module, and maintain
1038 * a list of external modules.
1040 void add_port(name
, dir
)
1048 tt
= (term
*)calloc(1, sizeof(term
));
1050 tt
->nt
= NULL
; /* will be filled in in newnode */
1052 tt
->name
= (char *)calloc(1, TERM_NAME_SIZE
);
1053 sprintf(tt
->name
, name
);
1055 tmod
= newobject(name
, dir
);
1057 if (!strcmp(dir
, "IN"))
1061 tt
->x_pos
= tmod
->x_size
+1;
1062 tt
->y_pos
= tmod
->y_size
/2;
1065 else if (!strcmp(dir
, "OUT"))
1069 tt
->x_pos
= -1; /* (mod 9/90 stf) */
1070 tt
->y_pos
= tmod
->y_size
/2;
1073 else if (!strcmp(dir
, "INOUT"))
1075 tt
->side
= UP
; /* Modification 6-11-90 (inouts should be on top. */
1077 tt
->x_pos
= tmod
->x_size
/2;
1078 tt
->y_pos
= tmod
->y_size
+ 1;
1081 else error("add_port: terminal with bad direction", name
);
1083 /* tie the terminal to the module, and vise-versa */
1085 tmod
->terms
= (tlist
*)concat_list(tt
, tmod
->terms
);
1088 /* that gave the default postions, but if we can find it in the
1089 * icon file, we should use those instead. NOTE for real modules,
1090 * this call is made in parse.c since only it knows,
1091 * by the order of the ivf file, when all i/o's for the current
1092 * module are finished. -- spl 9/30/89
1094 if (tt
->type
== OUT
) /* its an input port, it has one output */
1096 addpositions(tmod
, 0, 0, 1);
1098 else if (tt
->type
== IN
) /* its an output port, it has one input */
1100 addpositions(tmod
, 1, 0, 0);
1102 /* for inouts just use the defaults above */
1104 /* add it to the external connection lists: */
1106 ext_terms
= (tlist
*)concat_list(tt
, ext_terms
);
1108 ext_mods
= (mlist
*)concat_list(tmod
, ext_mods
);
1112 /* ------------------------------------------------------------------------
1113 * get_module: do a lookup on all the modules, by index.
1114 * could be done with a hash table a-la rsim.
1115 * ------------------------------------------------------------------------
1118 module
*get_module(index
)
1123 for (m
= modules
; m
!= NULL
; m
= m
->next
)
1125 if (m
->this->index
== index
)
1130 error ("get_module, module of this index not found ", index
);
1134 /* ------------------------------------------------------------------------
1136 * manhattan rotate y coordinates of terminal positions of an icon.
1137 * Rotation is done such that the resulting box still has its lower
1138 * left corner at the (relative) 0, 0 postion.
1139 * ------------------------------------------------------------------------
1142 int rot_x_y(rot
, x_size
, y_size
, t
)
1143 int rot
, x_size
, y_size
;
1146 int x_old
= t
->x_pos
;
1147 int y_old
= t
->y_pos
;
1153 error("rot_x_y called with no needed rotation","");
1159 t
->y_pos
= (x_size
- x_old
);
1164 t
->x_pos
= (x_size
- x_old
);
1165 t
->y_pos
= (y_size
- y_old
);
1170 t
->x_pos
= (y_size
- y_old
);
1174 default: error("rot_x_y: called with bad rotation","");
1177 /* ------------------------------------------------------------------------
1179 * manhattan rotate terminal side info
1180 * ------------------------------------------------------------------------
1182 int rot_side(rot
, side
)
1185 /* Im a sucker for a hack */
1187 return((rot
+ side
) % 4);
1190 /* ------------------------------------------------------------------------
1192 * Count all of the terms on the module that exit on a given side:
1193 * ------------------------------------------------------------------------
1195 int count_terms(m
, s
)
1202 for(t
= m
->terms
; t
!= NULL
; t
= t
->next
)
1204 if (t
->this->side
== s
) count
++;
1208 /* ------------------------------------------------------------------------
1210 * Count all the unique terms in the partition that point in the given direction...
1211 * ------------------------------------------------------------------------
1213 int count_terms_part(part
, s
)
1222 for(ml
= partitions
[part
]; ml
!= NULL
; ml
= ml
->next
)
1224 for (tl
= ml
->this->terms
; tl
!= NULL
; tl
= tl
->next
)
1226 if (tl
->this->side
== s
) pushnew(tl
->this->nt
, &nets
, identity
);
1229 count
= list_length(nets
);
1233 /*----------------------------------------------------------------------------
1234 * count_terms_between_modules(sourceM, destM)
1235 * similar to "count_terms_part" only it counts the nets between the two mods.
1236 *----------------------------------------------------------------------------
1238 int count_terms_between_mods(sourceM
, destM
)
1239 module
*sourceM
, *destM
;
1245 for (tl
= sourceM
->terms
; tl
!= NULL
; tl
= tl
->next
)
1247 if ((tl
->this->type
== OUT
) || (tl
->this->type
== INOUT
))
1248 pushnew(tl
->this->nt
, &nets
, identity
);
1250 for (tl
= destM
->terms
; tl
!= NULL
; tl
= tl
->next
)
1252 if (tl
->this->type
== IN
)
1253 pushnew(tl
->this->nt
, &nets
, identity
);
1255 count
= list_length(nets
);
1260 /* file util - 9/89 stf */
1261 /* more support functions on basic data types: (llist and tnode) */
1263 /*---------------------------------------------------------------
1264 * collection of node manipulation functions for use on binary trees of the
1267 * struct tnode_struct
1270 * tnode *left, *right;
1273 * where node is defined as:
1275 * typedef struct tnode_struct tnode;
1279 tnode
*build_leaf(e
)
1281 /* used to build nodes, given a pointer to the info to hang there. The pointers are
1284 tnode
*temp
= (tnode
*)calloc(1, sizeof(tnode
));
1291 tnode
*build_node(l
, r
, e
)
1295 /* used to build internal nodes */
1297 tnode
*temp
= (tnode
*)calloc(1, sizeof(tnode
));
1303 /*===================================================================================*/
1304 int pull_terms_from_nets(m
)
1307 /* This removes the given module from all of the nets in which it's terminals are
1308 listed; This is only a one-way removal; The information in the module structure
1309 and within the terminal structures remains unchanged.
1314 for (tl
= m
->terms
; tl
!= NULL
; tl
= tl
->next
)
1316 /* pull this term from it's net */
1318 rem_item(tl
->this, &n
->terms
);
1321 /*===================================================================================*/
1322 int add_terms_to_nets(m
)
1325 /* This adds the given module to all of the nets in which it's terminals are
1326 listed; This is the converse operation to "pull_terms_from_nets".
1331 for (tl
= m
->terms
; tl
!= NULL
; tl
= tl
->next
)
1333 /* Add this term to it's net */
1335 pushnew(tl
->this, &n
->terms
);
1339 /*===================================================================================*/
1340 void clip_null_gates()
1342 /* This procedure walks through all of the modules being placed, and
1343 folds all NL_GATE entries, removing them from the completed diagram. */
1345 int part
, termCount
= 0, i
;
1348 term
*nullInpuTerm
, *nullOutpuTerm
, *inpuTerm
;
1351 for (ml
= modules
; ml
!= NULL
; ml
= ml
->next
)
1354 termCount
= list_length(m
->terms
);
1355 if ((termCount
<= 2) && (!strcmp(m
->type
, GATE_NULL_STR
)))
1359 nullOutpuTerm
= m
->primary_out
;
1360 rem_item(nullOutpuTerm
, &m
->terms
);
1361 nullInpuTerm
= m
->terms
->this;
1363 /* Fix the net reference in the inputs to bypass the null gate: */
1364 if ((nullInpuTerm
->type
!= GND
) &&
1365 (nullInpuTerm
->type
!= VDD
) &&
1366 (nullInpuTerm
->type
!= DUMMY
))
1368 for (tl
=nullInpuTerm
->nt
->terms
; tl
!= NULL
; tl
= tl
->next
)
1370 if (tl
->this != nullInpuTerm
)
1372 tl
->this->nt
= nullOutpuTerm
->nt
;
1373 inpuTerm
= tl
->this;
1377 /* Fix the net reference in the output to bypass the null gate: */
1378 for (tl
=nullOutpuTerm
->nt
->terms
; tl
!= NULL
; tl
= tl
->next
)
1380 if (tl
->this == nullOutpuTerm
)
1382 tl
->this = inpuTerm
;
1385 rem_item(nullInpuTerm
->nt
, nets
);
1387 else /* Hang the special term at all connected terminals */
1389 inpuTerm
= nullInpuTerm
;
1390 /* Fix the net reference in the output to bypass the null gate: */
1391 for (tl
=nullOutpuTerm
->nt
->terms
; tl
!= NULL
; tl
= tl
->next
)
1393 if (tl
->this != nullOutpuTerm
)
1395 tl
->this = inpuTerm
;
1398 tll
= nullOutpuTerm
->nt
->terms
;
1399 rem_item(nullOutpuTerm
, &tll
);
1402 /* The next two lines are needed if deletion occurs after partitioning */
1403 part
= module_info
[m
->index
].used
;
1404 rem_item(m
, &partitions
[part
]);
1406 rem_item(m
, &modules
);
1411 /* Now go through the modules and renumber them... */
1412 /* The module index should */
1413 temp
= (mlist
*)rcopy_list(modules
);
1414 for (ml
= temp
, i
=0; ml
!= NULL
; ml
= ml
->next
, i
++)
1417 module_info
[i
] = module_info
[m
->index
];
1423 /*---------------------------------------------------------------
1425 *---------------------------------------------------------------
1428 char *str_end_copy(new, old
, n
)
1432 /* Copy the last <n> characters from <old> to <new>. */
1433 int i
, len
= strlen(old
);
1436 strncpy(new, old
, n
);
1439 new[i
] = old
[len
-n
+i
];
1443 else strcpy(new, old
);
1448 /* ------------------------------------------------------------------------
1450 * ------------------------------------------------------------------------