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