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 Last edit by hansen on Sat Apr 11 15:53:44 2009
19 ****************************************************************************/
20 #include "tkgate.h"
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <string.h>
25
26 #define SKIPFIELD(C) { \
27 for (;*C && isspace(*C);C++); \
28 for (;*C && !isspace(*C);C++); \
29 }
30
31 int RangeVals[MAXRANGEPOS] = {
32 10,20,50,
33 100,200,500,
34 1000,2000,5000,
35 10000,20000,50000,
36 100000,200000,500000,
37 1000000,2000000,5000000,
38 };
39
40 GScope *Scope = NULL;
41
42 static GTrace *scope_highlightedTrace = 0;
43
44 void idleGateWin(ClientData);
45
46 /*****************************************************************************
47 *
48 * Convert an x screen coordinate to a simulation time value
49 *
50 * Parameters:
51 * S Scope object
52 * x x screen coordinate in scope window
53 *
54 * Returns: Simulation time
55 *
56 *****************************************************************************/
GScope_x2t(GScope * S,int x)57 simtime_t GScope_x2t(GScope *S,int x)
58 {
59 int pmin = ScopeLEFTMARGIN;
60 int pmax = S->Width-ScopeRIGHTMARGIN;
61 double f = ((double)x-pmin)/(double)(pmax-pmin);
62 return (simtime_t)(S->s_leftTime + S->s_range*f);
63 }
64
65 /*****************************************************************************
66 *
67 * Convert a simulation time to an x screen coordinate
68 *
69 * Parameters:
70 * S Scope object
71 * t Simulation time
72 *
73 * Returns: x screen coordinate in scope window
74 *
75 *****************************************************************************/
GScope_t2x(GScope * S,simtime_t t)76 int GScope_t2x(GScope *S,simtime_t t)
77 {
78 int pmin = ScopeLEFTMARGIN;
79 int pmax = S->Width-ScopeRIGHTMARGIN;
80 double f = (double)(t - S->s_leftTime) / (double)S->s_range;
81
82 return (int) (f*(pmax-pmin)+pmin);
83 }
84
85 /*****************************************************************************
86 *
87 * Request a complete redraw of the scope window
88 *
89 *****************************************************************************/
ReqScopeRedisplay()90 void ReqScopeRedisplay()
91 {
92 TkGate.idle_ev.scope_redraw = 1;
93
94 if (!TkGate.idle_ev.pending) {
95 TkGate.idle_ev.pending = 1;
96 Tk_DoWhenIdle(idleGateWin,0);
97 }
98 }
99
100 /*****************************************************************************
101 *
102 * Request a redraw of only the traces and the left origin
103 *
104 *****************************************************************************/
ReqScopeTraceRedisplay(void)105 void ReqScopeTraceRedisplay(void)
106 {
107 TkGate.idle_ev.trace_redraw = 1;
108
109 if (!TkGate.idle_ev.pending) {
110 TkGate.idle_ev.pending = 1;
111 Tk_DoWhenIdle(idleGateWin,0);
112 }
113 }
114
115 /*****************************************************************************
116 *
117 * Return non-zero if value V is a transition
118 *
119 * Parameters:
120 * s Scope object
121 * v Trace value object
122 * n Number of bits of trace
123 *
124 *****************************************************************************/
isTransition(GScope * s,GateValue * v,int n)125 int isTransition(GScope *s,GateValue *v,int n)
126 {
127 if (!v || !v->v_next) return 0;
128
129 if (n == 1) {
130 if (v->v_next->v_time <= s->s_leftTime) return 0;
131 if (v->v_next->v_time > s->s_leftTime + s->s_range) return 0;
132 if (v->v_code == VC_UNRECORDED) return 0;
133 if (v->v_next->v_code == VC_UNRECORDED) return 0;
134 if (v->v_code == v->v_next->v_code) return 0;
135 } else {
136 if (v->v_next->v_time < s->s_leftTime) return 0;
137 if (v->v_next->v_time > s->s_leftTime + s->s_range) return 0;
138 }
139
140 return 1;
141 }
142
143 /*****************************************************************************
144 *
145 * Adjust scope so that T->Current is the first change before LTIme
146 *
147 * Parameters:
148 * T Trace to be adjusted
149 * LTime Time at left side of scope window
150 *
151 *****************************************************************************/
GTrace_adjust(GTrace * T,simtime_t LTime)152 void GTrace_adjust(GTrace *T,simtime_t LTime)
153 {
154 while (T->t_current->v_next && T->t_current->v_next->v_time <= LTime) {
155 T->t_current = T->t_current->v_next;
156 }
157 while (T->t_current->v_prev && T->t_current->v_time > LTime) {
158 T->t_current = T->t_current->v_prev;
159 }
160 }
161
162 /*****************************************************************************
163 *
164 * Get screen x position for a value change
165 *
166 * Parameters:
167 * S Scope object
168 * V Value object
169 * LTime Time at left side of scope window
170 *
171 *****************************************************************************/
GScope_getXPos(GScope * S,GateValue * V,simtime_t LTime)172 int GScope_getXPos(GScope *S,GateValue *V,simtime_t LTime)
173 {
174 simtime_t T;
175
176 if ((!V) || (V->v_time > S->s_leftTime + S->s_range)) {
177 if (S->s_time - S->s_leftTime > S->s_range)
178 T = S->s_leftTime + S->s_range;
179 else
180 T = S->s_time;
181 } else if (V->v_time < LTime)
182 T = LTime;
183 else
184 T = V->v_time;
185
186 if (T < S->s_leftTime) T = S->s_leftTime;
187
188 return ScopeLEFTMARGIN + (T - S->s_leftTime)*S->s_scale;
189 }
190
191 /*****************************************************************************
192 *
193 * Get GC for color to use with value
194 *
195 * Parameters:
196 * V Value object
197 * nbits Number of bits in trace
198 *
199 *****************************************************************************/
GValue_getColor(GateValue * V,int nbits)200 GC GValue_getColor(GateValue *V,int nbits)
201 {
202 switch (V->v_code) {
203 case VC_UNRECORDED :
204 case VC_UNKNOWN :
205 case VC_CONTENTION :
206 case VC_LOW :
207 case VC_HIGH :
208 default :
209 return TkGate.scopeUnknownGC;
210 case VC_FLOAT :
211 return TkGate.scopeFloatGC;
212 case VC_ONE :
213 if (nbits == 1) return TkGate.scopeOneGC;
214 break;
215 case VC_ZERO :
216 if (nbits == 1) return TkGate.scopeZeroGC;
217 break;
218 }
219
220 if (V->v_hexValue) {
221 if (strchr(V->v_hexValue,'x'))
222 return TkGate.scopeUnknownGC;
223 else if (*V->v_hexValue == '0')
224 return TkGate.scopeZeroGC;
225 }
226 return TkGate.scopeOneGC;
227 }
228
GTrace_drawTransValue(GTrace * T,GateValue * V,GScope * S,int y,simtime_t LTime,int isFullUpdate)229 void GTrace_drawTransValue(GTrace *T,GateValue *V,GScope *S,int y,
230 simtime_t LTime,int isFullUpdate)
231 {
232 int x,nextX,width;
233 char *new_dpy = 0;
234 GC gc;
235
236 if (!V) return;
237
238 x = GScope_getXPos(S,V,LTime);
239
240 if (V->v_next)
241 nextX = GScope_getXPos(S,V->v_next,LTime);
242 else
243 nextX = -1;
244
245 if (!V->v_hexValue)
246 new_dpy = "";
247 else {
248 width = GKTextWidth(TkGate.stextXF[1],V->v_hexValue,strlen(V->v_hexValue));
249
250 if (nextX < 0 || width <= nextX-x-3)
251 new_dpy = V->v_hexValue;
252 else if (S->hash_width <= nextX-x-3)
253 new_dpy = "#";
254 else
255 new_dpy = "";
256 }
257
258 if (isFullUpdate && V->v_dpyHexValue) {
259 ob_free(V->v_dpyHexValue);
260 V->v_dpyHexValue = 0;
261 }
262
263 if (V->v_dpyHexValue && (strcmp(V->v_dpyHexValue,new_dpy) != 0)) {
264 char *s = V->v_dpyHexValue;
265 gc = TkGate.scopeClearGC;
266
267 GatePainter_drawString(TkGate.painterScopeW, gc,x+2,y-ScopeLOW-3,s,strlen(s));
268 ob_free(V->v_dpyHexValue);
269 V->v_dpyHexValue = 0;
270 }
271
272 if (*new_dpy) {
273 gc = GValue_getColor(V,T->t_nBits);
274 GatePainter_drawString(TkGate.painterScopeW, gc,x+2,y-ScopeLOW-3,new_dpy,strlen(new_dpy));
275 }
276 V->v_dpyHexValue = ob_strdup(new_dpy);
277 }
278
279 /*
280 Returns a code indicating the proper vertical lines to be drawn
281 on a logic transition. The codes are:
282
283 0 No vertical line
284 1 Bottom half only
285 2 Top half only
286 3 Full vertical line
287 */
transition_type(int from,int to)288 unsigned transition_type(int from,int to)
289 {
290 /*
291 Rows are the 'from' values and columns are the 'to' values.
292 */
293 static unsigned char trans[VC_NUMCASES][VC_NUMCASES] = {
294 /* 0 1 x z H L C */
295 {0, 3, 3, 1, 3, 1, 3}, /* 0 */
296 {3, 0, 3, 2, 2, 3, 3}, /* 1 */
297 {3, 3, 0, 3, 3, 3, 3}, /* x */
298 {1, 2, 3, 0, 2, 1, 3}, /* z */
299 {3, 2, 3, 2, 0, 3, 3}, /* H */
300 {1, 1, 3, 1, 3, 0, 3}, /* L */
301 {3, 3, 3, 3, 3, 3, 0}, /* C */
302 };
303
304 return trans[from][to];
305 }
306
GTrace_updateTransition(GTrace * T,GateValue * V,GScope * S,int y,int x1,int x2,simtime_t LTime,int isFullUpdate)307 void GTrace_updateTransition(GTrace *T,GateValue *V,GScope *S,int y,int x1,int x2,simtime_t LTime,int isFullUpdate)
308 {
309 if (isTransition(S,V,T->t_nBits)) {
310 GC gc;
311
312 gc = GValue_getColor(V->v_next,T->t_nBits);
313
314 if (T->t_nBits > 1) {
315
316 GTrace_drawTransValue(T,V,S,y,LTime,isFullUpdate);
317 GTrace_drawTransValue(T,V->v_next,S,y,LTime,isFullUpdate);
318 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
319 x2,y-ScopeLOW,x2,y-ScopeHIGH+1);
320 } else {
321 unsigned tt;
322
323 if (!V->v_next) return;
324
325 tt = transition_type(V->v_code,V->v_next->v_code);
326 switch (tt) {
327 case 1 : /* Low half */
328 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
329 x2,y-ScopeMEDIUM,
330 x2,y-ScopeLOW);
331 break;
332 case 2 : /* High half */
333 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
334 x2,y-ScopeMEDIUM,
335 x2,y-ScopeHIGH);
336 break;
337 case 3 : /* Full */
338 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
339 x2,y-ScopeLOW,
340 x2,y-ScopeHIGH);
341 break;
342 }
343 }
344 }
345 }
346
GTrace_updateValue(GTrace * T,GateValue * V,int y,int x1,int x2)347 void GTrace_updateValue(GTrace *T,GateValue *V,int y,int x1,int x2)
348 {
349 GC gc = GValue_getColor(V,T->t_nBits);
350
351 switch (V->v_code) {
352 case VC_UNRECORDED :
353 break;
354 case VC_UNKNOWN :
355 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
356 x1,y-ScopeLOW,
357 x2,y-ScopeLOW);
358 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
359 x1,y-ScopeHIGH,
360 x2,y-ScopeHIGH);
361 break;
362 case VC_FLOAT :
363 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
364 x1,y-ScopeMEDIUM,
365 x2,y-ScopeMEDIUM);
366 break;
367 case VC_LOW :
368 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
369 x1,y-ScopeLOW,
370 x2,y-ScopeLOW);
371 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
372 x1,y-ScopeMEDIUM,
373 x2,y-ScopeMEDIUM);
374 break;
375 case VC_HIGH :
376 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
377 x1,y-ScopeHIGH,
378 x2,y-ScopeHIGH);
379 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
380 x1,y-ScopeMEDIUM,
381 x2,y-ScopeMEDIUM);
382 break;
383 case VC_CONTENTION :
384 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
385 x1,y-ScopeLOW,
386 x2,y-ScopeLOW);
387 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
388 x1,y-ScopeHIGH,
389 x2,y-ScopeHIGH);
390 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
391 x1,y-ScopeLOWMED,
392 x2,y-ScopeLOWMED);
393 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
394 x1,y-ScopeHIGHMED,
395 x2,y-ScopeHIGHMED);
396 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
397 x1,y-ScopeMEDIUM,
398 x2,y-ScopeMEDIUM);
399 break;
400 case VC_ONE :
401 if (T->t_nBits == 1) {
402 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
403 x1,y-ScopeHIGH,
404 x2,y-ScopeHIGH);
405 } else {
406 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
407 x1,y-ScopeLOW,
408 x2,y-ScopeLOW);
409 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
410 x1,y-ScopeHIGH,
411 x2,y-ScopeHIGH);
412 }
413 break;
414 case VC_ZERO :
415 if (T->t_nBits == 1) {
416 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
417 x1,y-ScopeLOW,
418 x2,y-ScopeLOW);
419 } else {
420 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
421 x1,y-ScopeLOW,
422 x2,y-ScopeLOW);
423 XDrawLine(TkGate.D,TkGate.ScopeW,gc,
424 x1,y-ScopeHIGH,
425 x2,y-ScopeHIGH);
426 }
427 break;
428 }
429 }
430
431
GTrace_update(GTrace * T,GScope * S,int y,simtime_t LTime,int isFullUpdate)432 void GTrace_update(GTrace *T,GScope *S,int y,simtime_t LTime,int isFullUpdate)
433 {
434 /* int lasttime,value,vcode,*/
435 int x1,x2;
436 GateValue *V;
437
438 GTrace_adjust(T,LTime);
439
440 for (V = T->t_current;V;V = V->v_next) {
441 x1 = GScope_getXPos(S,V,LTime);
442 x2 = GScope_getXPos(S,V->v_next,LTime);
443
444 GTrace_updateValue(T,V,y,x1,x2);
445 GTrace_updateTransition(T,V,S,y,x1,x2,LTime,isFullUpdate);
446 if (V->v_next && V->v_next->v_time > S->s_leftTime + S->s_range) break;
447 }
448 }
449
GScope_getTraceIndex(GScope * S,GTrace * t)450 int GScope_getTraceIndex(GScope *S,GTrace *t)
451 {
452 int i;
453
454 for (i = 0;i < S->NumTraces;i++) {
455 if (S->Traces[i] == t) return i;
456 }
457
458 return -1;
459 }
460
GScope_updateTransition(GScope * S,simtime_t OldTime,int isFullUpdate)461 void GScope_updateTransition(GScope *S,simtime_t OldTime,int isFullUpdate)
462 {
463 int i;
464 int Y = ScopeTRACEHEIGHT;
465 for (i = S->Start;i < S->NumTraces;i++) {
466 int x1,x2;
467 GTrace *T = S->Traces[i];
468
469 if (T->t_last->v_time == OldTime) {
470 GTrace_adjust(T,OldTime);
471 x1 = GScope_getXPos(S,T->t_last,OldTime);
472 x2 = GScope_getXPos(S,0,OldTime);
473 GTrace_updateTransition(T,T->t_last->v_prev,S,Y,x1,x2,0,isFullUpdate);
474 }
475
476 Y += ScopeTRACEHEIGHT;
477 if (Y > S->Height-ScopeBOTTOMHEIGHT) break;
478 }
479 }
480
GScope_hitTrace(GScope * S,int y)481 GTrace *GScope_hitTrace(GScope *S,int y)
482 {
483 int i;
484 int trace_y = ScopeTRACEHEIGHT;
485
486 for (i = S->Start;i < S->NumTraces;i++) {
487 GTrace *T = S->Traces[i];
488
489 if (y < trace_y)
490 return T;
491
492 trace_y += ScopeTRACEHEIGHT;
493 if (trace_y > S->Height-ScopeBOTTOMHEIGHT) break;
494 }
495
496 return 0;
497 }
498
GScope_moveTrace(GScope * S,GTrace * t,int y)499 void GScope_moveTrace(GScope *S,GTrace *t,int y)
500 {
501 int cpos = GScope_getTraceIndex(S,t);
502 int ipos = y/ScopeTRACEHEIGHT; /* Insert position */
503 int imax = (S->Height-ScopeBOTTOMHEIGHT)/ScopeTRACEHEIGHT; /* Last trace position */
504 int i;
505
506 if (ipos < 0) return;
507 if (ipos > imax) return;
508
509 /*
510 * Get target index for insertion
511 */
512 ipos += S->Start;
513 if (ipos >= S->NumTraces) ipos = S->NumTraces-1;
514
515 if (ipos == cpos) return; /* No change */
516
517
518 if (cpos < ipos) {
519 for (i = cpos;i < ipos;i++)
520 S->Traces[i] = S->Traces[i+1];
521 } else {
522 for (i = cpos;i > ipos;i--)
523 S->Traces[i] = S->Traces[i-1];
524 }
525
526 S->Traces[ipos] = t;
527
528 ReqScopeRedisplay();
529 }
530
GScope_deleteSelectedTrace(GScope * S)531 void GScope_deleteSelectedTrace(GScope *S)
532 {
533 int i;
534 const char *name;
535
536 if (!scope_highlightedTrace) return;
537
538 /*
539 * Make sure highlighted trace is still a real trace
540 */
541 for (i = 0;i < S->NumTraces;i++) {
542 if (S->Traces[i] == scope_highlightedTrace)
543 break;
544 }
545 if (i == S->NumTraces) return;
546
547 name = scope_highlightedTrace->t_name;
548 SimInterface_delProbe(&TkGate.circuit->simulator,name);
549 sendSimCmd("$unprobe %s",name);
550
551 scope_highlightedTrace = 0;
552 ReqScopeRedisplay();
553 }
554
555
GScope_clearMark(GScope * S)556 void GScope_clearMark(GScope *S)
557 {
558 S->mark_val[0] = S->mark_val[1] = 0;
559 }
560
GScope_setTraceHighlight(GScope * S,GTrace * t)561 void GScope_setTraceHighlight(GScope *S,GTrace *t)
562 {
563 scope_highlightedTrace = t;
564 if (t)
565 GScope_clearMark(S); /* hide the time selection */
566 ReqScopeRedisplay();
567 }
568
GScope_update(GScope * S,simtime_t OldTime)569 void GScope_update(GScope *S,simtime_t OldTime)
570 {
571 int i;
572
573 if ((OldTime >= S->s_leftTime + S->s_range) && (S->NumTraces > 0)) {
574 return;
575 }
576
577 if (S->s_time >= S->s_leftTime + S->s_range) {
578 S->s_leftTime = ((S->s_time - S->s_range/3)/S->s_interval)*S->s_interval;
579 if (S->s_leftTime < 0) S->s_leftTime = 0;
580
581 ReqScopeRedisplay();
582 } else if (S->Start != -1) {
583 int Y = ScopeTRACEHEIGHT;
584 for (i = S->Start;i < S->NumTraces;i++) {
585 GTrace_update(S->Traces[i],S,Y,OldTime,0);
586 Y += ScopeTRACEHEIGHT;
587 if (Y > S->Height-ScopeBOTTOMHEIGHT) break;
588 }
589 }
590 }
591
GTrace_draw(GTrace * T,GScope * S,int y,int doName)592 void GTrace_draw(GTrace *T,GScope *S,int y,int doName)
593 {
594 int M;
595 GC gc;
596
597 if (T == scope_highlightedTrace) {
598 XFillRectangle(TkGate.D,TkGate.ScopeW,TkGate.scopeSelectGC,0,y-ScopeHIGH-1,
599 S->Width,ScopeHIGH-ScopeLOW+2);
600 } else if (!doName) {
601 XFillRectangle(TkGate.D,TkGate.ScopeW,TkGate.scopeClearGC,ScopeLEFTMARGIN,y-ScopeHIGH-1,
602 S->Width-ScopeLEFTMARGIN,ScopeHIGH-ScopeLOW+2);
603 }
604
605
606 if (T->t_current && !T->t_current->v_next)
607 GTrace_drawTransValue(T,T->t_current,S,y,S->s_leftTime,1);
608
609 if (doName) {
610
611 XSetLineAttributes(TkGate.D,TkGate.scopeGridGC,2,LineSolid,CapButt,JoinBevel);
612 XDrawLine(TkGate.D,TkGate.ScopeW,TkGate.scopeGridGC,ScopeLEFTMARGIN,y,
613 S->Width-ScopeRIGHTMARGIN,y);
614
615 for (M = S->s_leftTime;M <= S->s_leftTime + S->s_range;M += S->s_interval) {
616 int P;
617
618 P = ScopeLEFTMARGIN + (M-S->s_leftTime)*S->s_scale;
619 XDrawLine(TkGate.D,TkGate.ScopeW,TkGate.scopeGridGC,P,y-2,P,y+2);
620 }
621 XSetLineAttributes(TkGate.D,TkGate.scopeGridGC,1,LineSolid,CapButt,JoinBevel);
622
623 if (!T->t_visName) {
624 int w;
625 char *p;
626
627 T->t_visName = T->t_dVisName = ob_strdup(T->t_printName);
628
629 if ((p = strchr(T->t_visName,'.')))
630 T->t_visName = p+1;
631
632 while ((w = GKTextWidth(TkGate.textXF[1],T->t_visName,strlen(T->t_visName))) > ScopeLEFTMARGIN-10) {
633 if ((p = strchr(T->t_visName+1,'.')))
634 T->t_visName = p;
635 else
636 T->t_visName++;
637 }
638 }
639
640
641 XDrawLine(TkGate.D,TkGate.ScopeW,TkGate.scopeGridGC,10,y,
642 ScopeLEFTMARGIN-10,y);
643
644
645 if (T->t_nBits > 1)
646 gc = TkGate.busGC;
647 else
648 gc = TkGate.wireGC;
649
650 XSetFont(TkGate.D,gc,TkGate.textXF[1]->fid);
651 #if 0
652 PosDrawString(TkGate.ScopeW,NULL,gc,10,y-ScopeTEXTPOS,
653 T->t_visName,AtLeft);
654 #endif
655 GatePainter_drawString(TkGate.painterScopeW, gc,10,y-ScopeTEXTPOS,
656 T->t_visName,strlen(T->t_visName));
657 XSetFont(TkGate.D,gc,TkGate.stextXF[1]->fid);
658 }
659
660 GTrace_update(T,S,y,S->s_leftTime,1);
661 }
662
GScope_showCrossLine(GScope * S)663 void GScope_showCrossLine(GScope *S)
664 {
665 if (Scope->show_xhair) return;
666 Scope->show_xhair = 1;
667
668 if (Scope->xhair_x >= ScopeLEFTMARGIN && Scope->xhair_x <= Scope->Width - ScopeRIGHTMARGIN) {
669 if (Scope->enable_xhair)
670 XDrawLine(TkGate.D,TkGate.ScopeW,TkGate.scopeXHairGC,Scope->xhair_x,0,
671 Scope->xhair_x,Scope->Height-ScopeBOTTOMHEIGHT);
672 }
673 }
674
GScope_hideCrossLine(GScope * S)675 void GScope_hideCrossLine(GScope *S)
676 {
677 if (!Scope->show_xhair) return;
678 if (Scope->NumTraces <= 0) return;
679
680 if (Scope->xhair_x >= ScopeLEFTMARGIN && Scope->xhair_x <= Scope->Width - ScopeRIGHTMARGIN) {
681 if (Scope->enable_xhair)
682 XDrawLine(TkGate.D,TkGate.ScopeW,TkGate.scopeXHairGC,Scope->xhair_x,0,
683 Scope->xhair_x,Scope->Height-ScopeBOTTOMHEIGHT);
684 }
685
686 Scope->show_xhair = 0;
687 }
688
GScope_drawCrossLine(GScope * S,int x)689 void GScope_drawCrossLine(GScope *S,int x)
690 {
691 if (Scope->NumTraces <= 0) return;
692 if (!Scope->show_xhair) return;
693
694 if (Scope->xhair_x >= ScopeLEFTMARGIN && Scope->xhair_x <= Scope->Width - ScopeRIGHTMARGIN) {
695 if (Scope->enable_xhair)
696 XDrawLine(TkGate.D,TkGate.ScopeW,TkGate.scopeXHairGC,Scope->xhair_x,0,
697 Scope->xhair_x,Scope->Height-ScopeBOTTOMHEIGHT);
698 }
699
700 Scope->xhair_x = x;
701
702 if (Scope->xhair_x >= ScopeLEFTMARGIN && Scope->xhair_x <= Scope->Width - ScopeRIGHTMARGIN) {
703 if (Scope->enable_xhair)
704 XDrawLine(TkGate.D,TkGate.ScopeW,TkGate.scopeXHairGC,Scope->xhair_x,0,
705 Scope->xhair_x,Scope->Height-ScopeBOTTOMHEIGHT);
706 }
707 }
708
709
GScope_drawSelection(GScope * S)710 void GScope_drawSelection(GScope *S)
711 {
712 int Y,i;
713 int x1,x2;
714 int pmin = ScopeLEFTMARGIN;
715 int pmax = S->Width-ScopeRIGHTMARGIN;
716
717 x1 = GScope_t2x(S,S->mark_val[0]);
718 x2 = GScope_t2x(S,S->mark_val[1]);
719
720 if (x2 < x1) {
721 int t = x1; x1 = x2; x2 = t;
722 }
723 #if 0
724 printf("Scope_drawSelection[%d..%d]\n",x1,x2);
725 #endif
726
727 if (x1 < pmin) x1 = pmin;
728 if (x1 > pmax) x1 = pmax;
729 if (x2 < pmin) x2 = pmin;
730 if (x2 > pmax) x2 = pmax;
731 if (x1 == x2) return;
732
733 if (S->mark_count == 0) return;
734
735 Y = ScopeTRACEHEIGHT;
736 for (i = S->Start;i < S->NumTraces;i++) {
737 XFillRectangle(TkGate.D,TkGate.ScopeW,TkGate.scopeSelectGC,
738 x1,Y-ScopeHIGH-1,
739 x2-x1,ScopeHIGH-ScopeLOW+2);
740
741 Y += ScopeTRACEHEIGHT;
742 if (Y > S->Height-ScopeBOTTOMHEIGHT) break;
743 }
744 }
745
GScope_showSelection(GScope * S)746 void GScope_showSelection(GScope *S)
747 {
748 #if 0
749 printf("GScope_showSelection() show_mark=%d mark_count=%d\n",S->show_mark,S->mark_count);
750 #endif
751
752 if (S->show_mark) return;
753 S->show_mark = 1;
754
755 GScope_drawSelection(S);
756 }
757
GScope_hideSelection(GScope * S)758 void GScope_hideSelection(GScope *S)
759 {
760 #if 0
761 printf("GScope_hideSelection() show_mark=%d\n",S->show_mark);
762 #endif
763
764 if (!S->show_mark) return;
765 S->show_mark = 0;
766
767 GScope_drawSelection(S);
768 }
769
770 /*
771 * Update selected region during a selection drag on the scope.
772 */
GScope_moveSelection(GScope * S)773 void GScope_moveSelection(GScope *S)
774 {
775 int Y,i;
776 int x1,x2;
777 int pmin = ScopeLEFTMARGIN;
778 int pmax = S->Width-ScopeRIGHTMARGIN;
779
780 x1 = GScope_t2x(S,S->mark_val[1]);
781 if (S->mark_count == 1) {
782 S->mark_val[1] = GScope_x2t(S,S->xhair_x);
783 }
784 x2 = GScope_t2x(S,S->mark_val[1]);
785
786 if (x2 < x1) {
787 int t = x1; x1 = x2; x2 = t;
788 }
789
790 if (x1 < pmin) x1 = pmin;
791 if (x1 > pmax) x1 = pmax;
792 if (x2 < pmin) x2 = pmin;
793 if (x2 > pmax) x2 = pmax;
794 if (x1 == x2) return;
795
796 if (S->mark_count == 0) return;
797
798 Y = ScopeTRACEHEIGHT;
799 for (i = S->Start;i < S->NumTraces;i++) {
800 XFillRectangle(TkGate.D,TkGate.ScopeW,TkGate.scopeSelectGC,
801 x1,Y-ScopeHIGH-1,
802 x2-x1,ScopeHIGH-ScopeLOW+2);
803
804 Y += ScopeTRACEHEIGHT;
805 if (Y > S->Height-ScopeBOTTOMHEIGHT) break;
806 }
807 }
808
GScope_setMark(GScope * S,int x,int isDn,unsigned state)809 void GScope_setMark(GScope *S,int x,int isDn,unsigned state)
810 {
811 int val;
812 int is_shift = ((state & ShiftMask) != 0);
813 int pmin = ScopeLEFTMARGIN;
814 int pmax = S->Width-ScopeRIGHTMARGIN;
815 x = imin(x,pmax);
816 x = imax(x,pmin);
817 val = GScope_x2t(S,x);
818
819 switch (S->mark_count) {
820 case 2 :
821 if (!isDn) return; /* Ignore up clicks when no selection */
822 if (is_shift) {
823 int d0 = iabs(S->mark_val[0] - val);
824 int d1 = iabs(S->mark_val[1] - val);
825 if (d0 < d1)
826 S->mark_val[0] = val;
827 else
828 S->mark_val[1] = val;
829 break;
830 } else
831 S->mark_count = 0;
832 /* pass through */
833 case 0 :
834 if (!isDn) return; /* Ignore up clicks when no selection */
835
836 S->mark_x[0] = x;
837 S->mark_x[1] = x;
838 S->mark_val[0] = val;
839 S->mark_val[1] = val;
840 S->mark_count++;
841 break;
842 case 1 :
843 if (!isDn && is_shift) return; /* Ignore up clicks with shift */
844
845 S->mark_x[1] = x;
846 S->mark_val[1] = val;
847 S->mark_count++;
848
849 if (S->mark_val[0] == S->mark_val[1])
850 S->mark_count = 0;
851
852 break;
853 }
854 }
855
856 /*****************************************************************************
857 *
858 * Set flag indicating if cross-hair is visible and update display on screen
859 *
860 * Parameters:
861 * n New cross-hair state (1=visible, 0=invisible)
862 *
863 *****************************************************************************/
GScope_setShowXHairState(int n)864 void GScope_setShowXHairState(int n)
865 {
866 extern int scope_active;
867 if (!scope_active) return;
868
869 if (Scope->enable_xhair == n) return;
870
871 GScope_hideCrossLine(Scope);
872 Scope->enable_xhair = n;
873 Scope->xhair_x = 0;
874 GScope_showCrossLine(Scope);
875 }
876
877 /*****************************************************************************
878 *
879 * Draw the base time value for a scope (i.e., the time on the left edge)
880 *
881 * Parameters:
882 * S Scope object
883 * y y-coordinate at which to draw value
884 *
885 *****************************************************************************/
GScope_drawBaseTime(GScope * S,simtime_t base,int y)886 static void GScope_drawBaseTime(GScope *S,simtime_t base,int y)
887 {
888 SimInterface *si = &TkGate.circuit->simulator;
889 double base_f = (double)base*si->si_tsmult / (double)S->s_precision;
890 int units = si->si_units;
891 char buf[STRMAX];
892 int P = S->s_precision;
893
894 while (base_f > 1000 && units > 0) {
895 base_f /= 1000.0;
896 units--;
897 P *= 1000;
898 }
899 P /= si->si_tsmult;
900
901 switch (P) {
902 case 0:
903 case 1:
904 sprintf(buf,"%0.0f%s",base_f,SimInterface_unitsToStr(units));
905 break;
906 case 10:
907 sprintf(buf,"%0.1f%s",base_f,SimInterface_unitsToStr(units));
908 break;
909 case 100:
910 sprintf(buf,"%0.2f%s",base_f,SimInterface_unitsToStr(units));
911 break;
912 default :
913 sprintf(buf,"%0.3f%s",base_f,SimInterface_unitsToStr(units));
914 break;
915 }
916
917 GatePainter_drawString(TkGate.painterScopeW,TkGate.scopeGridGC,
918 10,y,buf,strlen(buf));
919 }
920
921 /*****************************************************************************
922 *
923 * Choose appropriate parameters for converting epoch values to printable
924 * tick labeled
925 *
926 *****************************************************************************/
GScope_pickTimeLabeling(SimInterface * si,simtime_t range,simtime_t interval,char ** format,double * tickScale,int * units)927 void GScope_pickTimeLabeling(SimInterface *si,simtime_t range,simtime_t interval,
928 char **format,double *tickScale,int *units)
929 {
930 double range_f, interval_f;
931
932 *units = si->si_units;
933 *tickScale = (double)si->si_tsmult/(double)si->si_precision;
934 range_f = *tickScale * (double)range;
935 *units = si->si_units;
936 *format = "%lf";
937
938 while (range_f < 1 && *units < NUM_UNITS) {
939 *tickScale *= 1000;
940 range_f *= 1000;
941 (*units)++;
942 }
943 while (range_f > 1000 && *units > 0) {
944 *tickScale /= 1000;
945 range_f /= 1000;
946 (*units)--;
947 }
948
949 interval_f = interval * *tickScale;
950
951 if (interval_f < 1)
952 *format = "+%0.1lf";
953 else
954 *format = "+%0.0lf";
955 }
956
957 /*****************************************************************************
958 *
959 * Draw the scope window scale
960 *
961 * Parameters:
962 * S Scope object
963 * doTicks Non-zero if scope ticks should also be updated
964 *
965 * If doTicks is zero, only the base time will be updated. If doTicks is
966 * non-zero, it is assumed that the screen has been cleared.
967 *
968 *****************************************************************************/
GScope_drawScale(GScope * S,int doTicks)969 static void GScope_drawScale(GScope *S,int doTicks)
970 {
971 double W = S->Width - ScopeLEFTMARGIN - ScopeRIGHTMARGIN;
972 double UnitSize = W / (double) S->s_range;
973 int y = S->Height - ScopeBOTTOMHEIGHT + 20;
974 simtime_t base = S->s_leftTime;
975 SimInterface *si = &TkGate.circuit->simulator;
976
977 S->s_scale = UnitSize;
978
979 if (!doTicks) {
980 XFillRectangle(TkGate.D,TkGate.ScopeW,TkGate.scopeClearGC,
981 0,S->Height-ScopeBOTTOMHEIGHT,
982 ScopeLEFTMARGIN-10,ScopeBOTTOMHEIGHT);
983 }
984
985 /*
986 * Draw the base value
987 */
988 GScope_drawBaseTime(S,base,y);
989
990
991
992 /*
993 * Draw the tick values.
994 */
995 if (doTicks) {
996 char buf[STRMAX];
997 simtime_t T;
998 char *format;
999 double tickScale;
1000 int units;
1001 const char *units_s;
1002 int text_w;
1003
1004 GScope_pickTimeLabeling(si, S->s_range, S->s_interval, &format, &tickScale, &units);
1005
1006 for (T = base;
1007 T < base + S->s_range + S->s_interval-1;
1008 T += S->s_interval) {
1009 double tick = (T-base)*tickScale;
1010
1011 sprintf(buf,format,tick);
1012
1013 text_w = GKTextWidth(TkGate.textXF[1],buf,strlen(buf))/2;
1014 GatePainter_drawString(TkGate.painterScopeW, TkGate.scopeGridGC,
1015 ScopeLEFTMARGIN+(int)((T-S->s_leftTime)*UnitSize-text_w),
1016 y,buf,strlen(buf));
1017 }
1018
1019
1020 units_s = SimInterface_unitsToStr(units);
1021 text_w = GKTextWidth(TkGate.textXF[1],units_s,strlen(units_s));
1022 XDrawString(TkGate.D,TkGate.ScopeW,TkGate.scopeGridGC,
1023 S->Width - ScopeRIGHTMARGIN - text_w,
1024 y+15,units_s,strlen(units_s));
1025
1026 }
1027 }
1028
1029 /*****************************************************************************
1030 *
1031 * Do a complete update of the scope window.
1032 *
1033 * Parameters:
1034 * S Scope object
1035 *
1036 *****************************************************************************/
GScope_fullUpdate(GScope * S)1037 void GScope_fullUpdate(GScope *S)
1038 {
1039 extern int scope_active;
1040 Window R;
1041 int i, X, Y;
1042 unsigned int W,H,BW,DP;
1043 double vs,ve,hs,he;
1044
1045 if (!scope_active) return;
1046
1047 if (TkGate.idle_ev.scope_redraw) {
1048 XClearWindow(TkGate.D,TkGate.ScopeW);
1049 XGetGeometry(TkGate.D,TkGate.ScopeW,&R,&X,&Y,&W,&H,&BW,&DP);
1050 S->Width = W;
1051 S->Height = H;
1052
1053 S->show_xhair = 0;
1054 S->show_mark = 0;
1055 } else {
1056 W = S->Width;
1057 H = S->Height;
1058
1059 GScope_hideCrossLine(S);
1060 GScope_hideSelection(S);
1061 }
1062
1063 if (S->NumTraces > 0) {
1064 GScope_drawScale(S,TkGate.idle_ev.scope_redraw);
1065
1066 Y = ScopeTRACEHEIGHT;
1067 for (i = S->Start;i < S->NumTraces;i++) {
1068 GTrace_draw(Scope->Traces[i],S,Y,TkGate.idle_ev.scope_redraw);
1069 Y += ScopeTRACEHEIGHT;
1070 if (Y > H-ScopeBOTTOMHEIGHT) break;
1071 }
1072
1073 vs = (double)S->Start/(double)S->NumTraces;
1074 ve = (double)(i+1)/(double)S->NumTraces;
1075
1076 if (S->s_time > 0) {
1077 hs = (double)S->s_leftTime/(double)S->s_time;
1078 he = (double)(S->s_leftTime+S->s_range)/(double)S->s_time;
1079 if (he > 1.0) he = 1.0;
1080 } else {
1081 hs = 0.0;
1082 he = 1.0;
1083 }
1084 } else {
1085 static char *msg;
1086 char buf[STRMAX];
1087
1088 msg = msgLookup("scope.emptymsg");
1089 recodeText(Circuit_getDisplayEncoder(TkGate.circuit), buf, STRMAX, msg);
1090
1091 vs = 0.0;
1092 ve = 1.0;
1093 hs = 0.0;
1094 he = 1.0;
1095 GatePainter_drawString(TkGate.painterScopeW,TkGate.scopeGridGC,
1096 20,H/2,buf,strlen(buf));
1097 }
1098
1099 GScope_showCrossLine(S);
1100 GScope_showSelection(S);
1101
1102 DoTcl(".scope.main.vert set %f %f",vs,ve);
1103 DoTcl(".scope.main.horz set %f %f",hs,he);
1104 }
1105
Scope_stepTo(simtime_t t)1106 void Scope_stepTo(simtime_t t)
1107 {
1108 int OldTime = Scope->s_time;
1109 Scope->s_time = t;
1110 GScope_update(Scope,OldTime);
1111 }
1112
Scope_setOneBitValue(GTrace * T,simtime_t Time,int c)1113 void Scope_setOneBitValue(GTrace *T,simtime_t Time,int c)
1114 {
1115 switch (c) {
1116 case '1' :
1117 trace_observe(T,Time,VC_ONE,0);
1118 break;
1119 case '0' :
1120 trace_observe(T,Time,VC_ZERO,0);
1121 break;
1122 case 'x' :
1123 case 'X' :
1124 trace_observe(T,Time,VC_UNKNOWN,0);
1125 break;
1126 case 'z' :
1127 case 'Z' :
1128 trace_observe(T,Time,VC_FLOAT,0);
1129 break;
1130 case 'l' :
1131 case 'L' :
1132 trace_observe(T,Time,VC_LOW,0);
1133 break;
1134 case 'h' :
1135 case 'H' :
1136 trace_observe(T,Time,VC_HIGH,0);
1137 break;
1138 }
1139 }
1140
Scope_setValue(const char * name,const char * val)1141 void Scope_setValue(const char *name,const char *val)
1142 {
1143 int nbits;
1144 char c,*p,*q;
1145 GTrace *T = GScope_findTrace(Scope,name);
1146
1147 if (!T) return; /* Not an observed value */
1148
1149 if (sscanf(val,"%d'%c",&nbits,&c) != 2) {
1150 trace_observe(T,Scope->s_time,VC_FLOAT,0);
1151 return;
1152 }
1153 p = strchr(val,'\'') + 2;
1154
1155 /*
1156 * Handle single bit values here.
1157 */
1158 if (nbits == 1) {
1159 Scope_setOneBitValue(T,Scope->s_time,*p);
1160 GScope_updateTransition(Scope,Scope->s_time,0);
1161 return;
1162 }
1163
1164 /*
1165 * If multi-bit signal and all bits are floating, treat as
1166 * a single-bit floating signal.
1167 */
1168 for (q = p;*q;q++)
1169 if (*q != 'z') break;
1170 if (!*q) {
1171 Scope_setOneBitValue(T,Scope->s_time,'z');
1172 GScope_updateTransition(Scope,Scope->s_time,0);
1173 return;
1174 }
1175
1176 trace_observe(T,Scope->s_time,VC_ZERO,p);
1177
1178 if (Scope->s_time <= Scope->s_leftTime + Scope->s_range)
1179 GScope_updateTransition(Scope,Scope->s_time,0);
1180 }
1181
1182 /*
1183 Report observations on repName to traceName as well.
1184 */
Scope_rename(const char * oldName,const char * newName)1185 void Scope_rename(const char *oldName,const char *newName)
1186 {
1187 GTrace *T = GScope_findTrace(Scope,oldName);
1188 if (T) {
1189 ob_free(T->t_name);
1190 T->t_name = ob_strdup(newName);
1191 }
1192 }
1193
1194 /*
1195 Observe the value of a trace at a particular time. The value
1196 may be specified with a vcode (for 1-bit traces), or a value string
1197 (for n-bit traces). If the value of the trace changes the change
1198 will be recorded.
1199 */
trace_observe(GTrace * T,simtime_t time,int vcode,const char * value)1200 void trace_observe(GTrace *T,simtime_t time,int vcode,const char *value)
1201 {
1202 if (T->t_last->v_time == time) {
1203 char *old_str = T->t_last->v_hexValue;
1204 const char *new_str = value;
1205
1206 if (new_str)
1207 while (*new_str == '0' && new_str[1]) new_str++;
1208
1209 if (new_str) {
1210 T->t_last->v_hexValue = ob_strdup(new_str);
1211 } else
1212 T->t_last->v_hexValue = 0;
1213
1214 if (old_str) ob_free(old_str);
1215
1216 T->t_last->v_code = vcode;
1217 } else if (T->t_last->v_time < time) {
1218 if (T->t_last->v_code != vcode ||
1219 (value && !T->t_last->v_hexValue) ||
1220 (value && T->t_last->v_hexValue && strcmp(value,T->t_last->v_hexValue) != 0)) {
1221 T->t_last->v_next = new_Value(time,vcode,value,T->t_last);
1222 T->t_last = T->t_last->v_next;
1223 }
1224 } else {
1225 logError(ERL_WARN,"Time travel not allowed.");
1226 return;
1227 }
1228 }
1229
new_GScope(simtime_t precision)1230 GScope *new_GScope(simtime_t precision)
1231 {
1232 GScope *S;
1233
1234 S = (GScope *) ob_malloc(sizeof(GScope),"GScope");
1235 S->Width = S->Height = 0;
1236 S->Start = 0;
1237 S->NumTraces = 0;
1238 S->s_time = S->s_leftTime = 0;
1239 S->s_baseRangePos = DEFAULTRANGEPOS;
1240 S->s_rangePos = S->s_baseRangePos;
1241 S->s_precision = precision;
1242 S->s_range = RangeVals[S->s_rangePos];
1243 GScope_pickInterval(&S->s_range,&S->s_interval,S->s_precision);
1244 S->s_scale = 0.0;
1245
1246 S->hash_width = GKTextWidth(TkGate.stextXF[1],"#",1);
1247
1248 S->enable_xhair = 1;
1249 S->show_xhair = 1;
1250 S->show_mark = 0;
1251 S->xhair_x = 0;
1252 S->mark_count = 0;
1253
1254 memset(S->mark_val,0,sizeof(S->mark_val));
1255 memset(S->mark_x,0,sizeof(S->mark_x));
1256
1257 return S;
1258 }
1259
delete_GScope(GScope * S)1260 void delete_GScope(GScope *S)
1261 {
1262 int i;
1263
1264 for (i = 0;i < S->NumTraces;i++) {
1265 GTrace *T = S->Traces[i];
1266 delete_GTrace(T);
1267 }
1268 S->NumTraces = 0;
1269 }
1270
GScope_deleteTrace(GScope * S,const char * name)1271 void GScope_deleteTrace(GScope *S,const char *name)
1272 {
1273 int i;
1274
1275 for (i = 0;i < S->NumTraces;i++) {
1276 GTrace *T = S->Traces[i];
1277 if (strcmp(T->t_printName,name) == 0) {
1278 delete_GTrace(T);
1279 break;
1280 }
1281 }
1282
1283 S->NumTraces--;
1284 for (;i < S->NumTraces;i++)
1285 S->Traces[i] = S->Traces[i+1];
1286
1287 if (S->NumTraces == 0)
1288 DoTcl("Scope::makeHidden");
1289
1290
1291
1292 if (S->NumTraces == 0)
1293 S->Start = 0;
1294 else if (S->Start >= S->NumTraces)
1295 S->Start = S->NumTraces-1;
1296
1297 ReqScopeRedisplay();
1298 }
1299
GScope_addTrace(GScope * S,const char * Name,const char * PrintName,int Bits,int doSort)1300 void GScope_addTrace(GScope *S,const char *Name,const char *PrintName,int Bits,int doSort)
1301 {
1302 GTrace *T;
1303 int i,j;
1304
1305 if (!(T = GScope_findTrace(S,Name))) {
1306 T = new_GTrace(Name,PrintName,Bits,S->s_time);
1307 } else {
1308 if (T->t_printName) ob_free(T->t_printName);
1309 T->t_printName = (char*) ob_strdup(PrintName);
1310 return;
1311 }
1312
1313 if (doSort) {
1314 for (i = 0;i < S->NumTraces;i++) {
1315 GTrace *sT = S->Traces[i];
1316 if (strcasecmp(T->t_printName,sT->t_printName) <= 0)
1317 break;
1318 }
1319 } else
1320 i = S->NumTraces;
1321
1322 for (j = S->NumTraces;j > i;j--)
1323 S->Traces[j] = S->Traces[j-1];
1324 S->NumTraces++;
1325 S->Traces[i] = T;
1326
1327 if (S->NumTraces == 1)
1328 DoTcl("Scope::makeVisible");
1329
1330 ReqScopeRedisplay();
1331 }
1332
new_GTrace(const char * name,const char * printName,int nBits,simtime_t curTime)1333 GTrace *new_GTrace(const char *name,const char *printName,int nBits,simtime_t curTime)
1334 {
1335 GTrace *T;
1336
1337 T = (GTrace*) ob_malloc(sizeof(GTrace),"GTrace");
1338 T->t_name = (char*) ob_strdup(name);
1339 T->t_printName = (char*) ob_strdup(printName);
1340 T->t_visName = 0;
1341 T->t_dVisName = 0;
1342 T->t_nBits = nBits;
1343
1344 T->t_first = T->t_last = T->t_current = new_Value(0,VC_UNRECORDED,0,NULL);
1345 trace_observe(T,curTime,VC_UNRECORDED,0);
1346
1347 return T;
1348 }
1349
delete_GTrace(GTrace * T)1350 void delete_GTrace(GTrace *T)
1351 {
1352 GateValue *V;
1353
1354 ob_free(T->t_name);
1355 ob_free(T->t_printName);
1356 if (T->t_dVisName) ob_free(T->t_dVisName);
1357
1358 for (V = T->t_first;V;V = V->v_next) {
1359 if (V->v_dpyHexValue) ob_free(V->v_dpyHexValue);
1360 if (V->v_hexValue) ob_free(V->v_hexValue);
1361 }
1362
1363 ob_free(T);
1364 }
1365
GScope_findTrace(GScope * S,const char * Name)1366 GTrace *GScope_findTrace(GScope *S,const char *Name)
1367 {
1368 int i;
1369
1370 for (i = 0;i < S->NumTraces;i++) {
1371 GTrace *T = S->Traces[i];
1372 if (!strcmp(T->t_name,Name))
1373 return T;
1374 }
1375
1376 return NULL;
1377 }
1378
1379
new_Value(simtime_t CurTime,int Code,const char * value,GateValue * Prev)1380 GateValue *new_Value(simtime_t CurTime,int Code,const char *value,GateValue *Prev)
1381 {
1382 GateValue *V;
1383
1384 V = (GateValue *) ob_malloc(sizeof(GateValue),"GValue");
1385 V->v_time = CurTime;
1386 V->v_code = Code;
1387 if (value) {
1388 while (*value == '0' && value[1]) value++;
1389 V->v_hexValue = ob_strdup(value);
1390 } else
1391 V->v_hexValue = 0;
1392 V->v_dpyHexValue = 0;
1393 V->v_prev = Prev;
1394 V->v_next = NULL;
1395
1396 return V;
1397 }
1398
GScope_pickInterval(simtime_t * R,simtime_t * I,simtime_t precision)1399 void GScope_pickInterval(simtime_t *R,simtime_t *I,simtime_t precision)
1400 {
1401 int p,k,d;
1402
1403 k = *R/10;
1404 d = 1;
1405 for (p = 0;k > 10;p++) {
1406 d *= 10;
1407 k /= 10;
1408 }
1409 *I = k * d;
1410
1411 *R *= precision;
1412 *I *= precision;
1413 }
1414
GScope_saveProbes(GScope * S)1415 void GScope_saveProbes(GScope *S)
1416 {
1417 Circuit *c = TkGate.circuit;
1418 int i;
1419
1420 if (!S) return;
1421
1422 Circuit_clearSavedProbes(c);
1423
1424 for (i = 0;i < S->NumTraces;i++) {
1425 GTrace *T = S->Traces[i];
1426 Circuit_addProbeName(c,T->t_name,0);
1427 }
1428 }
1429
GScope_removeProbesOnNet(Circuit * c,GNet * net)1430 void GScope_removeProbesOnNet(Circuit *c,GNet *net)
1431 {
1432 /*STUB*/
1433 }
1434
GScope_postFullName(GTrace * t)1435 void GScope_postFullName(GTrace *t)
1436 {
1437 if (t) {
1438 DoTcl("Scope::showTraceName %s",t->t_name);
1439 } else
1440 DoTcl("Scope::hideTraceName");
1441 }
1442
1443 /*
1444 ScopeExposePred(D,E,arg)
1445 Display *D;
1446 XEvent *E;
1447 char *arg;
1448 {
1449 return E->type == Expose && E->xany.window == TkGate.ScopeW;
1450 }
1451 */
1452
1453