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