1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 ****************************************************************************/
18 /*###########################################################################*
19  *
20  * Functions for creating wires and adding wires to circuit elements are
21  * defined in this source module.
22  *
23  *###########################################################################*/
24 
25 #include <stdlib.h>
26 
27 #include "tkgate.h"
28 
29 /*****************************************************************************
30  *
31  * Counts the number of wires on a terminal
32  *
33  * Parameters:
34  *    w			Head of wire list.
35  *
36  * Returns:		Number of wires in wire list.
37  *
38  *****************************************************************************/
wire_count(GWire * w)39 int wire_count(GWire *w)
40 {
41   if (!w)
42     return 0;
43   else
44     return 1 + wire_count(w->next);
45 }
46 
47 /*****************************************************************************
48  *
49  * Links a wire into the wire list
50  *
51  * Parameters:
52  *    wl		Wire list
53  *    w			Wire to be linked
54  *
55  * Returns:		Modified wire list.
56  *
57  *****************************************************************************/
wire_link(GWireList * wl,GWire * w)58 GWireList *wire_link(GWireList *wl,GWire *w)
59 {
60   GWireList *new_wl;
61 
62   new_wl = (GWireList *) ob_malloc(sizeof(GWireList),"GWireList");
63   ob_touch(new_wl);
64   new_wl->wl_next = wl;
65   new_wl->wl_wire = w;
66   return new_wl;
67 }
68 
69 /*****************************************************************************
70  *
71  * Unlinks a wire from the wire list
72  *
73  * Parameters:
74  *    wl		Wire list
75  *    w			Wire to be unlinked
76  *
77  * Returns:		Modified wire list.
78  *
79  *****************************************************************************/
wire_unlink(GWireList * wl,GWire * w)80 GWireList *wire_unlink(GWireList *wl,GWire *w)
81 {
82   GWireList *rest;
83 
84   if (wl == NULL)
85     return NULL;
86 
87   if (wl->wl_wire != w) {
88     ob_touch(wl);
89     wl->wl_next = wire_unlink(wl->wl_next,w);
90     return wl;
91   } else {
92     rest = wl->wl_next;
93     ob_free(wl);
94 
95     return rest;
96   }
97 }
98 
99 /*****************************************************************************
100  *
101  * Creates a new endpoint of a wire
102  *
103  * Parameters:
104  *    M			Module in which to create new wire end.
105  *    net		Net to which new wire end will belong
106  *    doNodes		Non-zero if wire nodes should also be created.
107  *
108  * Returns:		New wire object.
109  *
110  *****************************************************************************/
wire_newend(GModuleDef * M,GNet * net,int doNodes)111 GWire *wire_newend(GModuleDef *M,GNet *net,int doNodes)
112 {
113   GWire *w;
114 
115   w = (GWire *) ob_malloc(sizeof(GWire),"GWire");
116   ob_touch(w);
117 
118   w->net = 0;
119   w->name = NULL;
120   w->xanchor = 0;
121   w->yanchor = 0;
122   w->orient = 0;
123   w->wtype = 0;
124   w->PadNum = 0;
125   w->WireDir = 0;
126   w->invert = 0;
127   w->gate = NULL;
128   w->nodes = NULL;
129   w->driver = NULL;
130   w->next = NULL;
131   w->nidx = 0;
132   w->cpath = 0;
133   w->offset.num = w->offset.den = 0;
134 
135   if (net)
136     wire_setNet(w,net);
137 
138   if (doNodes) {
139     w->nodes = new_GWireNode();
140     ob_touch(w->nodes);
141     w->nodes->end = w;
142   }
143 
144   if (M) {
145     ob_touch(M);
146     M->m_wires = wire_link(M->m_wires,w);
147   }
148 
149   return w;
150 }
151 
152 /*****************************************************************************
153  *
154  * Creates a new wire node (Should be in nodes)
155  *
156  * Returns:		New wire node object.
157  *
158  *****************************************************************************/
new_GWireNode()159 GWireNode *new_GWireNode()
160 {
161   GWireNode *n;
162 
163   n = (GWireNode *) ob_malloc(sizeof(GWireNode),"GWireNode");
164 
165   n->x = 0;
166   n->y = 0;
167   n->out = NULL;
168   n->in = NULL;
169   n->end = NULL;
170   n->stype = UNSELECTED;
171   n->mark = 0;
172   n->showSize = 0;
173   n->isLabeled = 0;
174   n->labelSide = 0;
175   n->offset = 50;
176 
177   return n;
178 }
179 
180 /*****************************************************************************
181  *
182  *   Set/reset the net of a wire.  Update reference counts,
183  *   and free net if this is the last reference to the old
184  *   net of w.
185  *
186  * Parameters:
187  *    w			Wire on which to set the net.
188  *    net		Net to be assigned to the wire w.
189  *
190  *****************************************************************************/
wire_setNet(GWire * w,GNet * net)191 void wire_setNet(GWire *w,GNet *net)
192 {
193   ob_touch(w);				/* JPH 121603 */
194   if (net) {
195     ob_touch(net);			/* JPH 121603 */
196     net->n_refs++;
197   }
198   if (w->net) {
199     ob_touch(w->net);			/* JPH 121603 */
200     if (--w->net->n_refs <= 0)
201       delete_GNet(w->net);
202   }
203   w->net = net;
204 }
205 
206 /*****************************************************************************
207  *
208  * Create a new wire segment on an existing net.
209  *
210  * Parameters
211  *    M			Module in which to create wires.
212  *    net		Net on which to create segment.
213  *    *e1		Return for End 1 of new segment
214  *    *e2		Return for End 2 of new segment
215  *
216  * Returns:		Non-zero on error.
217  *
218  *****************************************************************************/
wire_newNetSegment(GModuleDef * M,GNet * net,GWire ** e1,GWire ** e2)219 int wire_newNetSegment(GModuleDef *M,GNet *net,GWire **e1,GWire **e2)
220 {
221   GWire *end1,*end2;			/* end1 is output end, end2 is input end */
222 
223   end1 = wire_newend(M,net,1);
224   end2 = wire_newend(M,net,1);
225 
226   ob_touch(end1);
227   ob_touch(end2);
228   ob_touch(end1->nodes);
229   ob_touch(end2->nodes);
230   end1->nodes->out = end2->nodes;
231   end2->nodes->in = end1->nodes;
232 
233   end1->driver = end1;
234   end1->wtype = DRIVER;
235   end2->driver = end1;
236   end2->wtype = DRIVEE;
237 
238   if (e1) *e1 = end1;
239   if (e2) *e2 = end2;
240 
241   return 0;
242 }
243 
244 /*****************************************************************************
245  *
246  * Create a new wire segment on a new net.
247  *
248  * Parameters:
249  *    M			Module in which to create new wires/net
250  *    *e1		Return for End 1 of wire
251  *    *e2		Return for End 2 of wire
252  *
253  *****************************************************************************/
wire_new(GModuleDef * M,GWire ** e1,GWire ** e2)254 int wire_new(GModuleDef *M,GWire **e1,GWire **e2)
255 {
256   GNet *net;
257 
258   net = new_GNet(0,M);				/* Create a whole new net */
259   wire_newNetSegment(M,net,e1,e2);		/* Create wire segments on net */
260   if (e1)
261     (*e1)->nodes->showSize = 1;
262 
263 
264   return 0;
265 }
266 
267 /*****************************************************************************
268  *
269  * Free a wire and decrement reference count on its net
270  *
271  * Parameters:
272  *    w			Wire to be freed.
273  *
274  *****************************************************************************/
wire_free(GWire * w)275 void wire_free(GWire *w)
276 {
277   if (w->net) net_decref(w->net);
278   ob_free(w);
279 }
280 
281 /*****************************************************************************
282  *
283  * Free a wire node.
284  *
285  * Parameters:
286  *    n			Wire node to be freed.
287  *
288  *****************************************************************************/
delete_GWireNode(GWireNode * n)289 void delete_GWireNode(GWireNode *n)
290 {
291   ob_free(n);
292 }
293 
294 /*****************************************************************************
295  *
296  * Evenly space wires on a pad of a gate along that pad.
297  *
298  * Parameters:
299  *    g			Gate on which to space wires
300  *    p			Pad # on gate.
301  *
302  *****************************************************************************/
wire_setPadSpacing(GCElement * g,int p)303 void wire_setPadSpacing(GCElement *g,int p)
304 {
305   int n,i,dy,dx;
306   GWire *q;
307   GWire *w = g->wires[p];
308   int x1 = g->xpos + g->typeinfo->Pad[p].Loc[g->orient].x1;
309   int y1 = g->ypos + g->typeinfo->Pad[p].Loc[g->orient].y1;
310   int x2 = g->xpos + g->typeinfo->Pad[p].Loc[g->orient].x2;
311   int y2 = g->ypos + g->typeinfo->Pad[p].Loc[g->orient].y2;
312 
313   n = wire_count(w) + 1;
314   dx = (1000*(x2 - x1)) / n;
315   dy = (1000*(y2 - y1)) / n;
316   for (i = 1, q = w;q;i++, q = q->next) {
317     int x = x1 + (dx * i)/1000;
318     int y = y1 + (dy * i)/1000;
319     wire_move(q->nodes,x-q->nodes->x,y-q->nodes->y,FULL);
320   }
321 }
322 
323 /*****************************************************************************
324  *
325  * Place a wires in the appropriate positions relative to the gates's position.
326  *
327  * Parameters:
328  *    p		Pad # on gate
329  *    g		Gate on which wire is attached.
330  *    w		Wire to be placed.
331  *    inout	I/O direction of wire
332  *
333  *****************************************************************************/
wire_placement(int p,GCElement * g,GWire * w,int inout)334 void wire_placement(int p,GCElement *g,GWire *w,int inout)
335 {
336   ob_touch(w);
337   w->orient = g->typeinfo->Pad[p].Loc[g->orient].dir;
338   if (inout == IN) {
339     ob_touch(w->nodes->in);
340     w->nodes->in->x = w->nodes->x;
341     w->nodes->in->y = w->nodes->y;
342     switch (w->orient) { /* Danger */
343     case D_RIGHT :
344       w->nodes->in->x += TKGATE_STUBLEN;
345       break;
346     case D_UP :
347       w->nodes->in->y -= TKGATE_STUBLEN;
348       break;
349     case D_LEFT :
350       w->nodes->in->x -= TKGATE_STUBLEN;
351       break;
352     case D_DOWN :
353       w->nodes->in->y += TKGATE_STUBLEN;
354       break;
355     }
356   } else {
357     ob_touch(w->nodes->out);
358     w->nodes->out->x = w->nodes->x;
359     w->nodes->out->y = w->nodes->y;
360     switch (w->orient) {
361     case D_RIGHT :
362       w->nodes->out->x += TKGATE_STUBLEN;
363       break;
364     case D_UP :
365       w->nodes->out->y -= TKGATE_STUBLEN;
366       break;
367     case D_LEFT :
368       w->nodes->out->x -= TKGATE_STUBLEN;
369       break;
370     case D_DOWN :
371       w->nodes->out->y += TKGATE_STUBLEN;
372       break;
373     }
374   }
375 #ifdef DEBUGADD
376   printf("end place\n");
377 #endif
378 }
379 
380 /*****************************************************************************
381  *
382  * Append wire to end of the pad list
383  *
384  * Parameters:
385  *    wl		Wire at head of pad list.
386  *    w			Wire to be appended.
387  *
388  * Returns:		New wire pad list
389  *
390  *****************************************************************************/
wire_append(GWire * wl,GWire * w)391 GWire *wire_append(GWire *wl,GWire *w)
392 {
393   GWire *l;
394 
395   if (!wl) return w;
396 
397   for (l = wl;l->next;l = l->next);
398   ob_touch(l);
399   l->next = w;
400 
401   return wl;
402 }
403 
404 
405 /*****************************************************************************
406  *
407  * Helping function to add a wire to a gate and set initial placement.
408  *
409  * Parameters:
410  *    g			Gate on which to attach wire
411  *    e1		End 1 of wire
412  *    e2		End 2 of wire
413  *    p			Pad # on gate
414  *    dir               I/O direction of wire
415  *    invertp		Non-zero if we should attach an inverter.
416  *
417  *****************************************************************************/
wire_gateadd(GCElement * g,GWire * e1,GWire * e2,int p,int dir,int invertp)418 static void wire_gateadd(GCElement *g,GWire *e1,GWire *e2,int p,int dir,int invertp)
419 {
420   GWire *w;
421 
422 #ifdef DEBUGADD
423   printf("wire_gate_add(%p)\n",p);
424 #endif
425   net_setSize(e1->net,g->typeinfo->Pad[p].size);
426   net_setSize(e2->net,g->typeinfo->Pad[p].size);
427 
428   switch (dir) {
429   case IN :
430     w = e2;
431     ob_touch(w);
432     w->gate = g;
433     ob_touch(g);
434     g->wires[p] = wire_append(g->wires[p],w);
435     wire_placement(p,g,w,IN);
436     wire_setPadSpacing(g,p);
437     break;
438   case TRI :
439   case OUT :
440     w = e1;
441     ob_touch(w);
442     w->gate = g;
443     w->invert = invertp;
444     ob_touch(g);
445     g->wires[p] = wire_append(g->wires[p],w);
446     wire_placement(p,g,w,OUT);
447     wire_setPadSpacing(g,p);
448     break;
449   default :
450     printf("UNKNOWN pin type\n");
451     abort();
452     break;
453   }
454 }
455 
456 /*****************************************************************************
457  *
458  * Adds a wire to a gate
459  *
460  * Parameters:
461  *    g			Gate on which to add wire.
462  *    p			Pad # on which to add wire.
463  *    M			Module in which gate is defined.
464  *    invertp		Non-zero to add inverter to wire.
465  *
466  * Returns:		Non-zero on error.
467  *
468  *****************************************************************************/
wire_addToGate(GCElement * g,int p,GModuleDef * M,int invertp)469 int wire_addToGate(GCElement *g,int p,GModuleDef *M,int invertp)
470 {
471   GWire *e1,*e2;
472 
473   wire_new(M,&e1,&e2);
474   wire_gateadd(g,e1,e2,p,g->typeinfo->Pad[p].iotype,invertp);
475   wire_finalizeNet(e1);
476 
477   return 0;
478 }
479