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     One of four main modules pertaining to wires.  COntaines functions for moving
20     and drawing wires.  Basic routines to maintain horizontal and vertical wires
21     being moved are defined here.
22 
23 
24 */
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include "tkgate.h"
28 
29 /*****************************************************************************
30  *
31  * Tweek point to compensate for X11 server differences.
32  *
33  * Parameters:
34  *      p		Coordinate to be adjusted
35  *      q		Next point in line segment
36  *
37  * Tweek end point p (where q is the adjacent point) to compensate for
38  * X server differences.  It is assumed that p and q are non-heap
39  * objects and do not require being saved with ob_touch()
40  *
41  *****************************************************************************/
tweekPoint(XPoint * p,XPoint * q)42 static void tweekPoint(XPoint *p,XPoint *q)
43 {
44   if (p->x == q->x) {
45     if (p->y > q->y) {
46       p->y += TKGATE_WIRETWEEK_BOTTOM;
47     } else if (p->y < q->y) {
48       p->y += TKGATE_WIRETWEEK_TOP;
49     }
50   } else if (p->y == q->y) {
51     if (p->x > q->x) {
52       p->x += TKGATE_WIRETWEEK_RIGHT;
53     } else if (p->x < q->x) {
54       p->x += TKGATE_WIRETWEEK_LEFT;
55     }
56   }
57 }
58 
59 /*****************************************************************************
60  *
61  * Get the position of the net node label
62  *
63  * Parameters:
64  *      n		Node on which to get label position.
65  *      net		Net of the node.
66  *      *x,*y		Return coordinates for node.
67  *      *p		Positioning
68  *
69  *****************************************************************************/
GWireNode_getLabelPos(GWireNode * n,GNet * net,int * x,int * y,int * p)70 void GWireNode_getLabelPos(GWireNode *n,GNet *net,int *x,int *y,int *p)
71 {
72   //  n->showSide
73   if (n->out) {
74     if (n->y != n->out->y) {
75       /* Vertical segment */
76       if (n->labelSide) {
77 	*x = n->x - 3;
78 	*y = n->y + (n->out->y - n->y)*n->offset/100;
79 	*p = AtRight|AtBottom;
80       } else {
81 	*x = n->x + 3;
82 	*y = n->y + (n->out->y - n->y)*n->offset/100;
83 	*p = AtLeft|AtBottom;
84       }
85     } else if (n->x != n->out->x) {
86       /* Horizontal segment */
87       if (n->labelSide) {
88 	*y = n->y;
89 	*x = n->x + (n->out->x - n->x)*n->offset/100;
90 	*p = AtLeft|AtTop;
91       } else {
92 	*y = n->y;
93 	*x = n->x + (n->out->x - n->x)*n->offset/100;
94 	*p = AtLeft|AtBottom;
95       }
96     } else {
97       /* Zero-length segment */
98       *x = n->x;
99       *y = n->y;
100       *p = AtLeft|AtBottom;
101     }
102   } else {
103     /* Shouldn't be possible, but just in case */
104     *x = n->x;
105     *y = n->y;
106     *p = AtLeft|AtBottom;
107   }
108 }
109 
110 /*****************************************************************************
111  *
112  * Display the label at a node.
113  *
114  * Parameters:
115  *      n		Node on which to display label
116  *      net		Net of the node.
117  *
118  *****************************************************************************/
GWireNode_displayLabel(GWireNode * n,GNet * net)119 static void GWireNode_displayLabel(GWireNode *n,GNet *net)
120 {
121   char label[STRMAX];
122   GC gc;
123 
124   if (net == TkGate.circuit->nsel) {
125     if (net->n_nbits > 1)
126       gc = TkGate.selBusGC;
127     else
128       gc = TkGate.selWireGC;
129   } else {
130     if (net->n_nbits > 1)
131       gc = TkGate.busGC;
132     else
133       gc = TkGate.wireGC;
134   }
135 
136 
137   if (GNet_getDisplayLabel(net, label, STRMAX, DLM_GET_VISIBLE) > 0) {
138     int x,y,p;
139 
140     GWireNode_getLabelPos(n,net,&x,&y,&p);
141     dce_DrawString(gc,x,y,p,label);
142   }
143 }
144 
145 
146 /*****************************************************************************
147  *
148  * Display the size of a wire with a slant and a number of bits
149  *
150  * Parameters:
151  *      n		Wirenode at which to display wire size
152  *      net		Net for this wirenode (or NULL to search for the net)
153  *
154  *
155  *****************************************************************************/
GWireNode_displaySize(GWireNode * n,GNet * net)156 void GWireNode_displaySize(GWireNode *n,GNet *net)
157 {
158   GWireNode *n2 = n->out;
159 
160   //
161   // No implied next node.
162   //
163   if (!n2) return;
164 
165   //
166   // If no net was given, search for the net.
167   //
168   if (!net) {
169     GWire *w = wirenode_driver(n);
170     net = w->net;
171   }
172 
173   if (net->n_nbits > 1) {
174     int x1 = n->x;
175     int y1 = n->y;
176     int x2 = n2->x;
177     int y2 = n2->y;
178     char ns[30];
179     int dx,dy,x,y;
180 
181     dx = (x2 - x1);
182     dy = (y2 - y1);
183 
184     if (dx*dx+dy*dy < (15*15))
185       return;
186 
187 
188     x = x1 + dx/2;
189     y = y1 + dy/2;
190 
191     sprintf(ns,"%d",net->n_nbits);
192 
193     if (x1 == x2) {
194       Icon_draw(TkGate.D,TkGate.W,TkGate.busGC,ctow_x(x+TKGATE_BUSW_VERT-1),ctow_y(y),SIZEHASH);
195       dce_DrawString(TkGate.busGC,x+8+TKGATE_BUSW_VERT,y,AtLeft|BetweenTopAndBottom,ns);
196     } else {
197       Icon_draw(TkGate.D,TkGate.W,TkGate.busGC,ctow_x(x),ctow_y(y+TKGATE_BUSW_HORZ-1),SIZEHASH);
198       dce_DrawString(TkGate.busGC,x,y-3+TKGATE_BUSW_HORZ,BetweenLeftAndRight|AtBottom,ns);
199     }
200 
201   }
202 }
203 
204 /*
205     Draw end of wire
206 */
wire_drawend(GWireNode * n,GWireNode * n2,int s,short * x,short * y)207 void wire_drawend(GWireNode *n,GWireNode *n2,int s,short *x,short *y)
208 {
209   static int xval[] = {0,0,-1,1};
210   static int yval[] = {-1,1,0,0};
211   int d,inv;
212 
213   d = (n->x == n2->x) ? (n->y <= n2->y) : 2 + (n->x <= n2->x);
214   inv = n->end->invert != 0;
215 
216   if (inv)
217     Icon_draw(TkGate.D,TkGate.W,TkGate.instGC,
218 	      ctow_x(n->x + 2*xval[d]),ctow_y(n->y + 2*yval[d]),
219 	      INVERTER);
220 
221   if (n->end && n->end->gate && n->end->gate->cpath_cut) {
222     int x1,y1,x2,y2;
223     int r;
224 
225     x1 = x2 = ctow_x(n->x + xval[d]*5);
226     y1 = y2 = ctow_y(n->y + yval[d]*5);
227 
228     r = (d + 2) % 4;
229 
230     x1 += xval[r]*5;
231     x2 -= xval[r]*5;
232     y1 += yval[r]*5;
233     y2 -= yval[r]*5;
234 
235     ZDrawLine(TkGate.D, TkGate.W, TkGate.instGC, x1,y1, x2,y2);
236   }
237 
238   *x += 5*xval[d]*inv;
239   *y += 5*yval[d]*inv;
240 }
241 
242 /*****************************************************************************
243  *
244  * Draw all wires driving a gate
245  *
246  *****************************************************************************/
wire_drawlist(GWire * w,GCElement * g)247 void wire_drawlist(GWire *w,GCElement *g)
248 {
249   GCElement *dg;
250 
251   for (;w;w = w->next) {
252     dg = wire_drivinggate(w);
253     if ((!g) || (!dg) || g == dg)
254       GWire_draw(w->driver);
255   }
256 }
257 
258 /*****************************************************************************
259  *
260  * Draw a single wire
261  *
262  * Parameters:
263  *      w		Wire to draw
264  *
265  * A wire is a single sequence of verticies between to connection points.  A
266  * connection point can be either a gate or a joint.
267  *
268  *****************************************************************************/
GWire_draw(GWire * w)269 void GWire_draw(GWire *w)
270 {
271   GWire *w1,*w2;
272   GWireNode *n;
273   XPoint p[1024];
274   int k;
275 
276   w1 = wire_driver(w);
277   w2 = wire_other(w1);
278 
279   for (k = 0, n = w1->nodes;n;k++, n = n->out) {
280     p[k].x = ctow_x(n->x);
281     p[k].y = ctow_y(n->y);
282 
283     if (n->showSize)
284       GWireNode_displaySize(n,w1->net);
285 
286     if (n->isLabeled)
287       GWireNode_displayLabel(n,w1->net);
288   }
289 
290   wire_drawend(w1->nodes,w1->nodes->out,0,&p[0].x,&p[0].y);
291   wire_drawend(w2->nodes,w2->nodes->in,0,&p[k-1].x,&p[k-1].y);
292 
293   if (w1->net->n_nbits > 1) {
294     GC gc = (w1->net == TkGate.circuit->nsel) ? TkGate.selBusGC : TkGate.busGC;
295 
296     tweekPoint(&p[0],&p[1]);
297     tweekPoint(&p[k-1],&p[k-2]);
298 
299     ZDrawLines(TkGate.D,TkGate.W,gc,p,k,CoordModeOrigin);
300   } else {
301     GC gc = (w1->net == TkGate.circuit->nsel) ? TkGate.selWireGC : TkGate.wireGC;
302 
303     if (w1->net == TkGate.circuit->nsel) {
304       tweekPoint(&p[0],&p[1]);
305       tweekPoint(&p[k-1],&p[k-2]);
306     }
307     ZDrawLines(TkGate.D,TkGate.W,gc,p,k,CoordModeOrigin);
308   }
309 
310   if (w1->cpath && TkGate.cpath_flashState) {
311     int i;
312 
313     for (i = 1;i < k;i++)
314       cpath_draw(p[i-1].x,p[i-1].y,p[i].x,p[i].y);
315   }
316 }
317 
wire_drawnet_aux(GWire * w,int isFirst)318 static void wire_drawnet_aux(GWire *w,int isFirst)
319 {
320   int i;
321 
322   w = wire_other(w);
323 
324   if (!isFirst) {
325     GWire_draw(w);
326     if (w->gate && w->gate->typeinfo->Flags.WireProps) gate_draw(w->gate,GD_NOWIRE);
327   }
328 
329   if (w->gate) {
330     switch (w->gate->typeinfo->code) {
331     case GC_JOINT :
332       gate_draw(w->gate,GD_NOWIRE);
333       for (i=0;i<4;i++)
334 	if (w->gate->wires[i] && (w->gate->wires[i] != w))
335 	  wire_drawnet_aux(w->gate->wires[i],0);
336       break;
337     case GC_TAP :
338       if (w == w->gate->wires[TAP_OUT])
339 	wire_drawnet_aux(w->gate->wires[TAP_IN],0);
340       else if (w == w->gate->wires[TAP_IN])
341 	wire_drawnet_aux(w->gate->wires[TAP_OUT],0);
342       break;
343     case GC_LED :
344       gate_draw(w->gate,GD_NOWIRE);
345       break;
346     }
347   }
348 }
349 
350 /*****************************************************************************
351  *
352  * Draw all wires associate with a net
353  *
354  * Parameters:
355  *      w		Representative wire on the net
356  *
357  *****************************************************************************/
wire_drawnet(GWire * w)358 void wire_drawnet(GWire *w)
359 {
360   GWire *o_w;
361 
362   if (!w) return;
363 
364   o_w = wire_other(w);
365 
366   wire_drawnet_aux(w,0);
367   wire_drawnet_aux(o_w,1);
368 
369   if (w->gate && w->gate->typeinfo->Flags.WireProps) gate_draw(w->gate,GD_NOWIRE);
370 }
371