Modified the UGetCursor() routine to return a valid response if the
[xcircuit.git] / asg / utility.c
blobfcac76600d39698746fbc89068c1e529cf8dea16
1 /************************************************************
2 **
3 ** COPYRIGHT (C) 1993 UNIVERSITY OF PITTSBURGH
4 ** COPYRIGHT (C) 1996 GANNON UNIVERSITY
5 ** ALL RIGHTS RESERVED
6 **
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 ************************************************************/
23 /* file utility.c */
24 /* ------------------------------------------------------------------------
25 * Helper / Utility routines for place and route spl 7/89
27 * ------------------------------------------------------------------------
29 #include <stdio.h>
30 #include <string.h>
31 #include "system_defs.h"
32 #include "net.h"
33 #include "network.h"
34 #include "externs.h"
35 #include "psfigs.h"
36 #include "asg_module.h"
38 /*---------------------------------------------------------------
39 * Forward References
40 *---------------------------------------------------------------
43 void add_in_out();
44 void add_special();
46 #ifdef TCL_WRAPPER
48 /*---------------------------------------------------------------
49 * my_calloc: replacement for C utility "calloc", using the Tcl
50 * routine Tcl_Alloc followed by bzero to initialize memory.
51 *---------------------------------------------------------------
54 void *
55 my_calloc(size_t nmemb, size_t size)
57 void *memloc;
58 size_t memsiz = nmemb * size;
60 memloc = (void *)Tcl_Alloc(memsiz);
61 if (memloc) bzero(memloc, memsiz);
62 return memloc;
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 *---------------------------------------------------------------
76 error(s1, s2)
77 char *s1, *s2;
79 Fprintf(stderr, "ERROR, line %d: %s\n\t%s\n", lcount, s1, s2);
80 Flush(stderr);
84 /*---------------------------------------------------------------
85 * side_of: return the module side for the terminal t (module is unique)
86 *---------------------------------------------------------------
88 side_of(t)
89 term *t;
91 if (t == NULL)
93 error("side_of passed NULL terminal","");
95 else if (t->mod == NULL)
97 error("side_of passed terminal with no module","");
99 else
101 return (t->side);
105 /*---------------------------------------------------------------
106 * mark_connection
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)
112 module *m1, *m2;
114 tlist *l, *ll;
115 int found = FALSE;
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;
130 found = TRUE;
135 if (!found)
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)
147 int *element;
148 int indx;
149 llist *lst;
151 llist *tl, *l;
153 if((lst == NULL)||(lst->index > indx))
155 tl = (llist *)calloc(1, sizeof(llist));
156 tl->next = lst;
157 tl->index = indx;
158 tl->values = NULL;
159 tl->values = concat_list(element, tl->values);
160 return (tl);
162 else
164 for(l = lst; ; l = l->next)
166 if(l->index == indx)
168 /* we already have a list at this index */
169 l->values = concat_list(element, l->values);
170 return(lst);
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));
177 tl->next = l->next;
178 l->next = tl;
179 tl->index = indx;
180 tl->values = NULL;
181 tl->values = concat_list(element, tl->values);
182 return(lst);
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 * ------------------------------------------------------------------------
194 net *get_net(name)
195 char *name;
197 nlist *n;
199 for (n = nets; n != NULL ; n = n->next)
200 if (!strcmp(n->this->name, name))
201 return(n->this);
203 /* error ("get_net, net used before it is declared ", name); */
204 return(NULL);
207 /*---------------------------------------------------------------
208 * str_end_dup
209 *---------------------------------------------------------------
211 char *str_end_dup(new, old, n)
212 char *new, *old;
213 int 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));
219 if (len > n)
221 strncpy(new, old, n);
222 for (i=0; i<n; i++)
224 new[i] = old[len-n+i];
226 new[n] = '\0';
228 else strcpy(new, old);
230 return(new);
233 /* ------------------------------------------------------------------------
234 * newnode: add a new net to the global list of nets
235 * ------------------------------------------------------------------------
237 void newnode(name)
238 char *name;
240 net *node;
241 tlist *t;
244 node = (net *)calloc(1, sizeof(net));
245 node->rflag = 0; /* Added 11-3-90 stf; Used in Global Router */
246 node->expns = NULL;
248 node->name = strdup(name);
250 /* initialize -- spl 9/30/89 */
251 node->terms = NULL;
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 */
276 return;
280 /* otherwise we have to do it all */
281 node->terms = NULL;
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)
298 char *type;
299 int *x, *y;
301 switch(validate(type))
303 case BUFFER :
304 case INVNOT_:
305 case NOT_ : *x = GATE_HEIGHT;
306 *y = SYSTERM_SIZE;
307 break;
308 case AND :
309 case NAND :
310 case OR :
311 case NOR :
312 case XOR :
313 case XNOR : *x = GATE_LENGTH;
314 *y = GATE_HEIGHT;
315 break;
316 case INPUT_SYM :
317 case OUTPUT_SYM : *x = SYSTERM_SIZE;
318 *y = SYSTERM_SIZE;
319 break;
320 case BLOCK :
321 default :
322 *x = ICON_SIZE;
323 *y = ICON_SIZE;
324 break;
328 /* ------------------------------------------------------------------------
329 * newobject
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;
336 module *object;
338 if(module_count >= MAX_MOD)
340 error("newobject: too many modules, change MAX_MOD and recompile",
341 gate_name);
342 /* exit(1); */
343 return NULL;
346 object = (module *)calloc(1, sizeof(module));
347 object->index = module_count++;
348 object->name = strdup(gate_name);
349 object->type = strdup(gate_type);
350 object->x_pos = 0;
351 object->y_pos = 0;
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);
363 return(object);
366 /* ------------------------------------------------------------------------
367 * addin: add a signal to the list of terminals for a module
368 * ------------------------------------------------------------------------
370 void addin(name, index, noOfTerms)
371 char *name;
372 int index;
373 int 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)
391 char *name;
392 int index;
393 int 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)
411 char *name;
412 int index;
413 int 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)
428 char *name;
429 int index;
430 int 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)
459 switch (termsOnEdge)
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))
481 { /* Overlap... */
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)
499 char *name;
500 int index, noOfTerms, dir;
502 tlist *tl;
503 term *tt;
504 net *tn;
506 tt = (term *)calloc(1, sizeof(term));
508 /* find this net in the global database */
509 tn = get_net(name);
510 tt->nt = tn;
511 tt->mod = curobj_module;
512 tt->name = (char *)calloc(1, TERM_NAME_SIZE);
514 switch (dir)
516 case IN:
517 sprintf(tt->name, "input_%d", index);
518 tt->side = LEFT;
519 tt->type = IN;
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);
523 break;
524 case OUT:
525 sprintf(tt->name, "output_%d", index);
526 tt->side = RIGHT;
527 tt->type = OUT;
528 tt->x_pos = tt->mod->x_size + 1; /* add 1 hack to center outputs on
529 right side */
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 */
532 break;
533 case INOUT:
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 */
538 tt->type = INOUT;
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... */
543 break;
545 case OUTIN:
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 */
549 tt->type = OUTIN;
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... */
554 break;
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
572 * from that.
573 * ------------------------------------------------------------------------
576 void add_xc_term(type, pinName, netName, index, numpins)
577 char *type;
578 char *pinName;
579 char *netName;
580 int index;
581 int numpins;
583 tlist *tl;
584 term *tt;
585 net *tn;
586 objinstptr xc_inst;
587 int result, x, y, a, b, c;
588 char *locPin;
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; */
609 if (result < 0) {
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);
619 tt->nt = tn;
621 tt->mod = curobj_module;
622 if (locPin != pinName)
623 tt->name = locPin;
624 else {
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 */
633 tt->x_pos = x;
634 tt->y_pos = y;
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)) {
647 tt->type = IN;
648 tt->side = LEFT;
650 else if (a < b) {
651 tt->side = UP;
652 tt->type = INOUT;
654 else if (c < -b) {
655 tt->side = BOTTOM;
656 tt->type = OUTIN;
658 else {
659 tt->side = RIGHT;
660 tt->type = OUT;
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)
675 char *name;
676 int index, noOfTerms, dir;
678 tlist *tl;
679 term *tt;
680 net *tn;
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);
688 switch (dir)
690 case IN:
691 sprintf(tt->name, "%s_input_%d", name, index);
692 tt->side = LEFT;
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);
696 break;
697 case OUT:
698 sprintf(tt->name, "%s_output_%d", name, index);
699 tt->side = RIGHT;
700 tt->x_pos = tt->mod->x_size + 1; /* add 1 hack to center outputs on
701 right side */
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 */
704 break;
705 case INOUT:
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... */
713 break;
715 case OUTIN:
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 */
719 tt->type = OUTIN;
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... */
724 break;
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)
741 char *nName;
742 term *t;
744 if (!strcmp(nName, t->nt->name)) return(TRUE);
745 else return(FALSE);
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)
754 module *m;
755 term *t;
757 if (t->x_pos >= m->x_size)
759 if (t->y_pos >= m->y_size)
761 t->side = UP;
762 return(OUTIN);
764 else if (t->y_pos <= 0)
766 t->side = DOWN;
767 return(INOUT);
769 else
771 t->side = RIGHT;
772 return(OUT);
775 else if (t->x_pos <= 0)
777 if (t->y_pos >= m->y_size)
779 t->side = UP;
780 return(OUTIN);
782 else if (t->y_pos <= 0)
784 t->side = DOWN;
785 return(INOUT);
787 else
789 t->side = LEFT;
790 return(IN);
793 else if (t->y_pos >= m->y_size)
795 t->side = UP;
796 return(OUTIN);
798 else
800 t->side = DOWN;
801 return(INOUT);
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)
811 module *m;
812 char *nn; /* The name of the net being fixed */
813 int x,y;
815 tlist *tl = (tlist *)member(nn, m->terms, named_net_p);
817 int adjX, adjY;
819 /* Adjust the pin position to be just outside the icon, rather than on
820 the edge: */
821 if (Xcanvas_scaling == FALSE)
823 if (x == 0) adjX = -1;
824 else if (x == m->x_size) adjX = x+1;
825 else adjX = x;
827 if (y == 0) adjY = -1;
828 else if (y == m->y_size) adjY = y+1;
829 else adjY = y;
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);
843 if (tl != NULL)
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);
857 else
859 Fprintf(stderr, "Bad netname %s trying to be fixed for module %s\n",
860 nn, m->name);
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)
869 module *m;
870 int 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 */
881 module *m;
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);
902 else return(FALSE);
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)
917 module *cur_module;
918 int incount, inoutcount, outcount;
920 tlist *t;
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)
964 module *m;
965 int *ins, *inouts, *outs;
967 tlist *tl;
968 for (tl = m->terms; tl != NULL; tl = tl->next)
970 switch(tl->this->type)
972 case IN: *ins += 1;
973 break;
974 case INOUT: *inouts += 1;
975 break;
976 case OUT: *outs += 1;
977 break;
982 /* ------------------------------------------------------------------------ */
983 int pin_spacing(m)
984 module *m;
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)
995 module *m;
996 int incount, inoutcount, outcount, spacesPerPin;
998 /* Reset the positions of all terminals, based on the counts and spacings
999 given...*/
1001 tlist *tl;
1002 int INindex = 0, INOUTindex = 0, OUTindex = 0;
1004 for (tl = m->terms; tl != NULL; tl = tl->next)
1006 switch(tl->this->type)
1008 case IN :
1009 tl->this->y_pos = relative_term_location(INindex++, incount,
1010 m->y_size, spacesPerPin);
1011 tl->this->x_pos = -1;
1012 break;
1014 case INOUT :
1015 tl->this->x_pos = relative_term_location(INOUTindex++, inoutcount,
1016 m->x_size, spacesPerPin);
1017 tl->this->y_pos = m->y_size + 1;
1018 break;
1020 case OUT :
1021 tl->this->y_pos = relative_term_location(OUTindex++, outcount,
1022 m->y_size, spacesPerPin);
1023 tl->this->x_pos = m->x_size + 1;
1024 break;
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)
1041 char *name, *dir;
1043 tlist *tl;
1044 term *tt;
1045 net *tn;
1046 module *tmod;
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"))
1059 tt->side = RIGHT;
1060 tt->type = OUT;
1061 tt->x_pos = tmod->x_size+1;
1062 tt->y_pos = tmod->y_size/2;
1065 else if (!strcmp(dir, "OUT"))
1067 tt->side = LEFT;
1068 tt->type = IN;
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. */
1076 tt->type = INOUT;
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);
1086 tt->mod = tmod;
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)
1119 int index;
1121 mlist *m;
1123 for (m = modules; m != NULL ; m = m->next)
1125 if (m->this->index == index)
1127 return(m->this);
1130 error ("get_module, module of this index not found ", index);
1131 return(NULL);
1134 /* ------------------------------------------------------------------------
1135 * rot_x_y
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;
1144 term *t;
1146 int x_old = t->x_pos;
1147 int y_old = t->y_pos;
1149 switch(rot)
1151 case ZERO:
1153 error("rot_x_y called with no needed rotation","");
1155 break;
1156 case NINETY:
1158 t->x_pos = y_old;
1159 t->y_pos = (x_size - x_old);
1161 break;
1162 case ONE_EIGHTY:
1164 t->x_pos = (x_size - x_old);
1165 t->y_pos = (y_size - y_old);
1167 break;
1168 case TWO_SEVENTY:
1170 t->x_pos = (y_size - y_old);
1171 t->y_pos = x_old;
1173 break;
1174 default: error("rot_x_y: called with bad rotation","");
1177 /* ------------------------------------------------------------------------
1178 * rot_side
1179 * manhattan rotate terminal side info
1180 * ------------------------------------------------------------------------
1182 int rot_side(rot, side)
1183 int rot, side;
1185 /* Im a sucker for a hack */
1187 return((rot + side) % 4);
1190 /* ------------------------------------------------------------------------
1191 * count_terms
1192 * Count all of the terms on the module that exit on a given side:
1193 * ------------------------------------------------------------------------
1195 int count_terms(m, s)
1196 module *m;
1197 int s;
1199 tlist *t;
1200 int count = 0;
1202 for(t = m->terms; t != NULL; t = t->next)
1204 if (t->this->side == s) count++;
1206 return(count);
1208 /* ------------------------------------------------------------------------
1209 * count_terms_part
1210 * Count all the unique terms in the partition that point in the given direction...
1211 * ------------------------------------------------------------------------
1213 int count_terms_part(part, s)
1214 int part;
1215 int s;
1217 mlist *ml;
1218 int count = 0;
1219 tlist *tl;
1220 nlist *nets = NULL;
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);
1230 free_list(nets);
1231 return(count);
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;
1241 int count = 0;
1242 tlist *tl;
1243 nlist *nets = NULL;
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);
1256 free_list(nets);
1257 return(count);
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
1265 * type
1267 * struct tnode_struct
1269 * int *this;
1270 * tnode *left, *right;
1273 * where node is defined as:
1275 * typedef struct tnode_struct tnode;
1279 tnode *build_leaf(e)
1280 int *e;
1281 /* used to build nodes, given a pointer to the info to hang there. The pointers are
1282 * set to NULL */
1284 tnode *temp = (tnode *)calloc(1, sizeof(tnode));
1285 temp->left = NULL;
1286 temp->right = NULL;
1287 temp->this = e;
1288 return(temp);
1291 tnode *build_node(l, r, e)
1292 tnode *l, *r;
1293 int *e;
1295 /* used to build internal nodes */
1297 tnode *temp = (tnode *)calloc(1, sizeof(tnode));
1298 temp->left = l;
1299 temp->right = r;
1300 temp->this = e;
1301 return(temp);
1303 /*===================================================================================*/
1304 int pull_terms_from_nets(m)
1305 module *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.
1311 net *n;
1312 tlist *tl;
1314 for (tl = m->terms; tl != NULL; tl = tl->next)
1316 /* pull this term from it's net */
1317 n = tl->this->nt;
1318 rem_item(tl->this, &n->terms);
1321 /*===================================================================================*/
1322 int add_terms_to_nets(m)
1323 module *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".
1328 net *n;
1329 tlist *tl;
1331 for (tl = m->terms; tl != NULL; tl = tl->next)
1333 /* Add this term to it's net */
1334 n = tl->this->nt;
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;
1346 mlist *temp, *ml;
1347 module *m;
1348 term *nullInpuTerm, *nullOutpuTerm, *inpuTerm;
1349 tlist *tl, *tll;
1351 for (ml = modules; ml != NULL; ml = ml->next)
1353 m = ml->this;
1354 termCount = list_length(m->terms);
1355 if ((termCount <= 2) && (!strcmp(m->type, GATE_NULL_STR)))
1357 if (termCount == 2)
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);
1407 module_count -= 1;
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++)
1416 m = ml->this;
1417 module_info[i] = module_info[m->index];
1418 m->index = i;
1420 free_list(temp);
1423 /*---------------------------------------------------------------
1424 * str_end_copy
1425 *---------------------------------------------------------------
1428 char *str_end_copy(new, old, n)
1429 char *new, *old;
1430 int n;
1432 /* Copy the last <n> characters from <old> to <new>. */
1433 int i, len = strlen(old);
1434 if (len > n)
1436 strncpy(new, old, n);
1437 for (i=0; i<n; i++)
1439 new[i] = old[len-n+i];
1441 new[n] = '\0';
1443 else strcpy(new, old);
1445 return(new);
1448 /* ------------------------------------------------------------------------
1449 * END OF FILE
1450 * ------------------------------------------------------------------------