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