1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: simwindow.c
6  * Simulation tool: signal window control
7  * Written by: Steven M. Rubin, Static Free Software
8  *
9  * Copyright (c) 2000 Static Free Software.
10  *
11  * Electric(tm) is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * Electric(tm) is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Electric(tm); see the file COPYING.  If not, write to
23  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24  * Boston, Mass 02111-1307, USA.
25  *
26  * Static Free Software
27  * 4119 Alpine Road
28  * Portola Valley, California 94028
29  * info@staticfreesoft.com
30  */
31 
32 #include "config.h"
33 #if SIMTOOL
34 
35 #include "global.h"
36 #include "egraphics.h"
37 #include "edialogs.h"
38 #include "efunction.h"
39 #include "network.h"
40 #include "sim.h"
41 #include "simals.h"
42 #include "tecgen.h"
43 #include "tecschem.h"
44 #include "tecart.h"
45 #include "usr.h"
46 #include "usrtrack.h"
47 #include <math.h>
48 #include <float.h>
49 
50 /*
51  *     WINDOW CONTROL:
52  * sim_window_init()                            Initialize simulation window system (do only once)
53  * BOOLEAN sim_window_create(f, np, chw, chs, fmt) Make simulation window with "f" frames, format "fmt"
54  *                                              in cell "np" charhandlers "chw/s" (l=0 to restore)
55  * sim_window_titleinfo(info)                   adds "info" to title of simulation window
56  * void sim_window_stopsimulation()             Stops simulation
57  * INTBIG sim_window_isactive(np)               Returns nonzero if simulating, returns cell if so
58  * sim_window_redraw()                          Redraws simulation window
59  * INTBIG sim_window_getnumframes()             Returns number of frames in sim window
60  * sim_window_setnumframes(count)               Sets number of frames in simulation window
61  * INTBIG sim_window_getnumvisframes()          Returns number of visible frames in sim window
62  * INTBIG sim_window_gettopvisframe()           Returns topmost visible frame in simulation window
63  * sim_window_settopvisframe(count)             Sets topmost visible frame in simulation window
64  * sim_window_savegraph()                       Preserves plot in database
65  * sim_window_writespicecmd()                   Writes vectors as SPICE commands
66  * c = sim_window_getdisplaycolor(s)            Get color of strength/state "s"
67  * sim_window_setdisplaycolor(s, c)             Set color of strength/state "s" to "c"
68  *
69  *     FRAME CONTROL
70  * sim_window_auto_anarange(void)               Zooms all frames to fit their traces (TODO: all->frameno)
71  * sim_window_zoom_frame(INTBIG frameno)        Zooms In frame "frameno" by scale 2
72  * sim_window_zoomout_frame(INTBIG frameno)     Zooms Out frame "frameno" by scale 2
73  * sim_window_shiftup_frame(INTBIG frameno)     Shifts Up frame "frameno" by 1/4 of height
74  * sim_window_shiftdown_frame(INTBIG frameno)   Shifts Dowm frame "frameno" by 1/4 of height
75  * sim_window_renumberlines()                   Renumbers frames so that they have no gaps
76  *
77  *     CONTROL OF TRACES:
78  * INTBIG sim_window_newtrace(frame, name, data) Creates trace in "frame" called "name" with user "data"
79  * BOOLEAN sim_window_buscommand()              Creates a bus from currently selected signals
80  * sim_window_loaddigtrace(tr, num, time, sta)  Loads trace "tr" with "num" digital signals "time/sta"
81  * sim_window_loadanatrace(tr, num, time, val)  Loads trace "tr" with "num" analog signals "time/val"
82  * sim_window_settraceframe(tr, frame)          Sets frame number for trace "tr"
83  * sim_window_killtrace(tr)                     Deletes trace "tr"
84  * sim_window_killalltraces(save)               Deletes all traces
85  * sim_window_supresstraceprefix(prefix)		Ignore this prefix when displaying trace names
86  *
87  *     TRACE INFORMATION:
88  * INTBIG *sim_window_getbustraces(tr)          Returns 0-terminated list of traces in bus "tr"
89  * INTBIG sim_window_gettraceframe(tr)          Returns frame number for trace "tr"
90  * INTBIG sim_window_getcurframe()              Returns current frame number
91  * char *sim_window_gettracename(tr)            Returns name for trace "tr"
92  * INTBIG sim_window_gettracedata(tr)           Returns user data for trace "tr"
93  * float sim_window_getanatracevalue(tr, time)  Returns analog value for trace "tr" at time "time"
94  * sim_window_getdigtracevalue(tr, time, &lev, &str) Returns digital value for trace "tr" at time "time"
95  * CHAR *sim_window_getbustracevalue(tr, time)	Returns bus value for trace "tr" at time "time"
96  * INTBIG *sim_window_findtrace(name, &count)   Locates the traces with this name
97  * sim_window_inittraceloop()                   Begin search of all traces
98  * sim_window_inittraceloop2()                  Begin search of all traces
99  * INTBIG sim_window_nexttraceloop()            Returns next trace (0 when done)
100  * INTBIG sim_window_nexttraceloop2()           Returns next trace (0 when done)
101  *
102  *     TRACE HIGHLIGHTING:
103  * sim_window_cleartracehighlight()             Unhighlights all traces
104  * sim_window_addhighlighttrace(tr)             Adds trace "tr" to highlighting
105  * sim_window_deletehighlighttrace(tr)          Removes trace "tr" from highlighting
106  * INTBIG sim_window_gethighlighttrace()        Returns highlighted trace (0 if none)
107  * INTBIG *sim_window_gethighlighttraces()      Returns 0-terminated list of highlighted traces
108  * sim_window_showhighlightedtraces()           Makes sure highlighted traces are seen
109  *
110  *     TIME AND CURSOR CONTROL:
111  * sim_window_setmaincursor(time)               Sets position of main cursor
112  * double sim_window_getmaincursor()            Returns position of main cursor
113  * sim_window_setextensioncursor(time)          Sets position of extension cursor
114  * double sim_window_getextensioncursor()       Returns position of extension cursor
115  * sim_window_settimerange(tr, min, max)        Sets trace time range from "min" to "max"
116  * sim_window_gettimerange(tr, min, max)        Returns trace time range
117  * sim_window_gettimeextents(min, max)          Returns data time range
118  */
119 
120 #define BUSANGLE          4		/* defines look of busses */
121 
122 #define NOTRACE ((TRACE *)-1)
123 
124 /* the meaning of TRACE->flags */
125 #define TRACESELECTED     01		/* set if this trace is selected */
126 #define TRACEMARK         02		/* for temporarily marking a trace */
127 #define TRACETYPE        014		/* the type of this trace */
128 #define TRACEISDIGITAL     0		/*     this trace is a digital signal */
129 #define TRACEISANALOG     04		/*     this trace is an analog signal */
130 #define TRACEISBUS       010		/*     this trace is a bus */
131 #define TRACEISOPENBUS   014		/*     this trace is an opened bus */
132 #define TRACENOTDRAWN    020		/* set if trace is not to be drawn */
133 #define TRACEHIGHCHANGED 040		/* set if trace highlighting changed */
134 
135 typedef struct Itrace
136 {
137 	CHAR     *name;				/* name of this trace */
138 	CHAR     *origname;			/* original name of this trace */
139 	INTBIG    flags;			/* state bits for this trace (see above) */
140 	INTBIG    nodeptr;			/* "user" data for this trace */
141 	INTBIG    busindex;			/* index of this trace in the bus (when part of a bus) */
142 	INTBIG    color;			/* color of this trace (analog only) */
143 	INTBIG    nameoff;			/* offset of trace name (when many per frame) */
144 	INTBIG    frameno;			/* frame number of this trace in window */
145 	INTBIG    numsteps;			/* number of steps along this trace */
146 	INTBIG    timelimit;		/* maximum times allocated for this trace */
147 	INTBIG    statelimit;		/* maximum states allocated for this trace */
148 	INTBIG    valuelimit;		/* maximum values allocated for this trace */
149 	double   *timearray;		/* time steps along this trace */
150 	INTBIG   *statearray;		/* states along this trace (digital) */
151 	float    *valuearray;		/* values along this trace (analog) */
152 	double    mintime, maxtime;	/* displayed range along horozintal axis */
153 	float     anadislow;		/* low vertical axis for this trace (analog) */
154 	float     anadishigh;		/* high vertical axis for this trace (analog) */
155 	float     anadisrange;		/* vertical range for this trace (analog) */
156 	struct Itrace *buschannel;
157 	struct Itrace *nexttrace;
158 } TRACE;
159 
160 static GRAPHICS sim_window_desc = {LAYERA, ALLOFF, SOLIDC, SOLIDC,
161 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
162 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
163 static GRAPHICS sim_window_udesc = {LAYERA, ALLOFF, PATTERNED, PATTERNED,
164 	{0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,
165 	0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555}, NOVARIABLE, 0};
166 static INTBIG sim_window_anacolor[] = {RED, GREEN, BLUE, CYAN, MAGENTA, YELLOW, ORANGE,
167 									   PURPLE, LGRAY, LRED, LGREEN, LBLUE, 0};
168 
169 #define DEFWAVEXNAMEEND     112		/* default x position where signal names end */
170 #define DEFWAVEXNAMEENDANA  100		/* default X position where signal names end (if analog) */
171 #define DEFWAVEXBAR         113		/* default X position of the bar between names and waveforms */
172 #define DEFWAVEXSIGSTART    114		/* default X position where waveforms start */
173 #define WAVEXSIGEND         767		/* the X position where waveforms end */
174 
175 #define WAVEYTIMETOP      30
176 #define WAVEYSIGBOT       31
177 #define WAVEYSIGTOP      560
178 #define WAVEYSIGRANGE    (WAVEYSIGTOP-WAVEYSIGBOT)		/* was 540 */
179 #define WAVEYSIGGAP       10
180 #define WAVEYCURSTOP     571
181 #define WAVEYTEXTBOT     561
182 #define WAVEYTEXTTOP     600
183 
184 #define TOPBARSIZE        20		/* size of title bar in waveform window */
185 
186 #define MINTHUMB          25		/* minimum horizontal thumb size */
187 
188 /* still need to convert "sim_window_drawcursors()" */
189 
190 /*
191  * In X:
192  *    0 to 112 is signal name
193  *      113    is bar
194  *   114-767 is signal waveform
195  * In Y:
196  *    0 to  30 is axis label
197  *   31 to 560 is signal waveforms
198  *   31 to 571 is the cursors
199  *  561 to 600 is text values (main and extension coordinates)
200  */
201 static INTBIG        sim_window_curx, sim_window_cury;
202 static INTBIG        sim_window_textsize;
203 static INTBIG        sim_window_lines = 0;
204 static INTBIG        sim_window_lines_limit = 0;
205 static INTBIG        sim_window_visframes;		/* frames (or lines) visible in window */
206 static INTBIG        sim_window_topframes;		/* upper visible frame in window */
207 static INTBIG        sim_window_highframe;		/* highlighted frame in window */
208 static INTBIG        sim_window_txthei;
209 static INTBIG        sim_window_curanacolor;
210 static INTBIG        sim_window_offx, sim_window_offy;
211 static INTBIG        sim_window_basex, sim_window_basey;
212        INTBIG        sim_window_statekey;		/* key for "SIM_window_state" */
213        INTBIG        sim_window_state;			/* cached value of "SIM_window_state" */
214        INTBIG        sim_window_format;			/* type of simulation in window */
215        INTBIG        sim_window_signalorder_key;/* key for "SIM_window_signalorder" */
216        INTBIG        sim_window_hierpos_key;	/* key for "SIM_window_hierarchy_pos" */
217 static double        sim_window_maincursor, sim_window_extensioncursor;
218 static float         sim_window_analow, sim_window_anahigh, sim_window_anarange;
219 static float        *sim_window_frame_analow=NULL, *sim_window_frame_anahigh=NULL;
220 static float        *sim_window_frame_topval=NULL, *sim_window_frame_botval=NULL;
221 static INTBIG        sim_window_highlightedtracecount;
222 static INTBIG        sim_window_highlightedtracetotal = 0;
223 static TRACE       **sim_window_highlightedtraces;
224 static INTBIG        sim_window_bustracetotal = 0;
225 static TRACE       **sim_window_bustraces;
226 static TRACE        *sim_window_firstrace;
227 static TRACE        *sim_window_tracefree;
228 static TRACE        *sim_window_loop;
229 static TRACE        *sim_window_loop2;
230        INTBIG        sim_colorstrengthoff;		/* color of off-strength */
231        INTBIG        sim_colorstrengthnode;		/* color of node-strength */
232        INTBIG        sim_colorstrengthgate;		/* color of gate-strength */
233        INTBIG        sim_colorstrengthpower;	/* color of power-strength */
234        INTBIG        sim_colorlevellow;			/* color of low-levels */
235        INTBIG        sim_colorlevelhigh;		/* color of high-levels */
236        INTBIG        sim_colorlevelundef;		/* color of undefined levels */
237        INTBIG        sim_colorlevelzdef;		/* color of Z levels */
238        INTBIG        sim_colorstrengthoff_key;	/* key for "SIM_window_color_str0" */
239        INTBIG        sim_colorstrengthnode_key;	/* key for "SIM_window_color_str1" */
240        INTBIG        sim_colorstrengthgate_key;	/* key for "SIM_window_color_str2" */
241        INTBIG        sim_colorstrengthpower_key;/* key for "SIM_window_color_str3" */
242        INTBIG        sim_colorlevellow_key;		/* key for "SIM_window_color_low" */
243        INTBIG        sim_colorlevelhigh_key;	/* key for "SIM_window_color_high" */
244        INTBIG        sim_colorlevelundef_key;	/* key for "SIM_window_color_X" */
245        INTBIG        sim_colorlevelzdef_key;	/* key for "SIM_window_color_Z" */
246 static WINDOWPART   *sim_waveformwindow;		/* current window when arrows are clicked */
247 static INTBIG        sim_waveformsliderpart;	/* 0:down arrow 1:below thumb 2:thumb 3:above thumb 4:up arrow */
248 static INTBIG        sim_window_tracedragyoff;	/* Y offset when dragging */
249 static INTBIG        sim_window_initialx;		/* initial X coordinate when dragging */
250 static INTBIG        sim_window_initialy;		/* initial Y coordinate when dragging */
251 static INTBIG        sim_window_currentdragy;	/* current Y coordinate when dragging */
252 static INTBIG        sim_window_deltasofar;		/* for dragging thumb button on side */
253 static INTBIG        sim_window_initialthumb;	/* for dragging thumb button on side */
254 static TRACE        *sim_window_tracedragtr;	/* signal being dragged */
255 static INTBIG        sim_window_sigtotal = 0;
256 static INTBIG       *sim_window_sigvalues;
257 static INTBIG        sim_window_zoominix, sim_window_zoominiy;	/* initial zoom coordinate */
258 static INTBIG        sim_window_zoomothx, sim_window_zoomothy;	/* final zoom coordinate */
259 static INTBIG        sim_waveforminiththumbpos;
260 static double        sim_waveformhrange;
261 static float         sim_window_maxtime, sim_window_mintime;
262 static float	     sim_window_max_timetick, sim_window_min_timetick;
263 static float	     sim_window_time_separation;
264 static float         sim_window_percent[] = { 0.1f, 0.5f, 0.9f };
265 #define PERCENTSIZE ((INTBIG)(sizeof(sim_window_percent)/sizeof(sim_window_percent[0])))
266 static float         sim_window_vdd;
267 static CHAR         *sim_window_title = 0;
268 static CHAR         *sim_window_traceprefix = 0;
269 static void         *sim_veroldstringarray = 0;	/* string array that holds a cell's former signal order */
270 static INTBIG        sim_window_wavexnameend;	/* the X position where signal names end */
271 static INTBIG        sim_window_wavexnameendana;/* the X position where signal names end (if analog) */
272        INTBIG        sim_window_wavexbar;		/* the X position of the bar between names and waveforms */
273 static INTBIG        sim_window_wavexsigstart;	/* the X position where waveforms start */
274 static BOOLEAN       sim_window_dragshown;		/* TRUE if dragging divider between names and waveforms */
275 static BOOLEAN       sim_window_draghighoff;	/* TRUE if highlights are off during divider dragging */
276 static INTBIG        sim_window_draglastx;		/* last position of divider between names and waveforms */
277 static INTBIG        sim_window_playing;		/* state of VCR controls */
278 static UINTBIG       sim_window_lastadvance;	/* time the VCR last advanced */
279 static UINTBIG       sim_window_advancespeed;	/* speed of the VCR (in screen pixels) */
280 static INTBIG        sim_window_measureframe;	/* frame in which measurement is being done */
281 static INTBIG        sim_window_firstmeasurex;	/* starting screen X coordinate of measurement */
282 static INTBIG        sim_window_firstmeasurey;	/* starting screen Y coordinate of measurement */
283 static INTBIG        sim_window_lastmeasurex;	/* current screen X coordinate of measurement */
284 static INTBIG        sim_window_lastmeasurey;	/* current screen Y coordinate of measurement */
285 static double        sim_window_firstmeasuretime;	/* current time coordinate of measurement */
286 static double        sim_window_firstmeasureyval;	/* current value coordinate of measurement */
287 static POLYGON      *sim_window_dragpoly = NOPOLYGON;	/* polygon for displaying measurement */
288 
289 /* the meaning of "sim_window_playing" */
290 #define VCRSTOP         0						/* VCR is stopped */
291 #define VCRPLAYFOREWARD 1						/* VCR is playing forward */
292 #define VCRPLAYBACKWARD 2						/* VCR is playing backward */
293 
294 /* prototypes for local routines */
295 static void        sim_window_addsegment(WINDOWPART*, INTBIG*, INTBIG*, INTBIG, INTBIG, INTBIG, INTBIG);
296 static void        sim_window_addtrace(TRACE *tr, TRACE *aftertr);
297 static TRACE      *sim_window_alloctrace(void);
298 static void        sim_window_buttonhandler(WINDOWPART*, INTBIG, INTBIG, INTBIG);
299 static CHAR       *sim_windowconvertengineeringnotation2(double time, INTBIG precpower);
300 static BOOLEAN     sim_window_distancedown(INTBIG x, INTBIG y);
301 static void        sim_window_distanceinit(WINDOWPART *wavewin);
302 static void        sim_window_distanceup(void);
303 static void        sim_window_dividerdone(void);
304 static BOOLEAN     sim_window_dividerdown(INTBIG x, INTBIG y);
305 static void        sim_window_dividerinit(WINDOWPART *w);
306 static void        sim_window_donehighlightchange(WINDOWPART *wavewin);
307 static void        sim_window_draw_timeticks(WINDOWPART *wavewin, INTBIG y1, INTBIG y2, BOOLEAN grid);
308 static void        sim_window_drawdistance(void);
309 static void        sim_window_drawareazoom(WINDOWPART *w, BOOLEAN on, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty);
310 static void        sim_window_drawbox(WINDOWPART*, INTBIG, INTBIG, INTBIG, INTBIG, INTBIG);
311 static void        sim_window_drawcstring(WINDOWPART*, CHAR*);
312 static void        sim_window_drawcursors(WINDOWPART*);
313 static void        sim_window_drawframe(INTBIG frame, WINDOWPART *wavewin);
314 static void        sim_window_drawgraph(WINDOWPART*);
315 static void        sim_window_drawhcstring(WINDOWPART *w, CHAR *s);
316 static void        sim_window_drawtimescale(WINDOWPART*);
317 static void        sim_window_drawto(WINDOWPART*, INTBIG, INTBIG, INTBIG);
318 static void        sim_window_drawtracedrag(WINDOWPART*, BOOLEAN on);
319 static void        sim_window_drawtraceselect(WINDOWPART *wavewin, INTBIG y1, INTBIG y2, BOOLEAN on);
320 static void        sim_window_drawulstring(WINDOWPART *w, CHAR *s);
321 static BOOLEAN     sim_window_eachbdown(INTBIG, INTBIG);
322 static void        sim_window_eachcursordown(INTBIG x, INTBIG y,double *cursor);
323 static BOOLEAN     sim_window_eachdown(INTBIG x, INTBIG y);
324 static BOOLEAN     sim_window_eachwdown(INTBIG, INTBIG);
325 static INTBIG      sim_window_ensurespace(TRACE *tr);
326 static BOOLEAN     sim_window_findcross(TRACE *tr, double val, double *time);
327 static WINDOWPART *sim_window_findschematics(void);
328 static void        sim_window_findthistrace(CHAR *name);
329 static WINDOWPART *sim_window_findwaveform(void);
330 static float       sim_window_get_analow(int traceno);
331 static float       sim_window_get_anahigh(int traceno);
332 static float       sim_window_get_anarange(int traceno);
333 static float       sim_window_get_botval(int frameno);
334 static float       sim_window_get_extanarange(int frameno);
335 static float       sim_window_get_topval(int frameno);
336 static void        sim_window_gethighlightcolor(INTBIG state, INTBIG *texture, INTBIG *color);
337 static void        sim_window_highlightname(WINDOWPART *wavewin, TRACE *tr, BOOLEAN on);
338 static BOOLEAN     sim_window_horizontalslider(INTBIG x, INTBIG y);
339 static void        sim_window_hthumbtrackingcallback(INTBIG delta);
340 static void        sim_window_inithighlightchange(void);
341 static BOOLEAN     sim_window_lineseg(WINDOWPART *wavewin, INTBIG xf, INTBIG yf, INTBIG xt,
342 					INTBIG yt, INTBIG style, INTBIG x, INTBIG y, BOOLEAN thick);
343 static CHAR       *sim_window_makewidevalue(INTBIG count, INTBIG *value);
344 static void        sim_window_mapcoord(WINDOWPART*, INTBIG*, INTBIG*);
345 static void        sim_window_moveto(INTBIG, INTBIG);
346 static CHAR       *sim_window_namesignals(INTBIG count, TRACE **list);
347 static BOOLEAN     sim_window_plottrace(TRACE *tr, WINDOWPART *wavewin, INTBIG style, INTBIG x, INTBIG y);
348 static CHAR       *sim_window_prettyprint(float v, int i1, int i2);
349 static void        sim_window_putvalueontrace(TRACE *tr, NODEPROTO *simnt);
350 static void        sim_window_redisphandler(WINDOWPART*);
351 static void        sim_window_removetrace(TRACE *tr);
352 static void        sim_window_savesignalorder(void);
353 static void        sim_window_scaletowindow(WINDOWPART*, INTBIG*, INTBIG*);
354 static BOOLEAN     sim_window_seleachdown(INTBIG x, INTBIG y);
355 static float       sim_window_sensible_value(float *h, float *l, INTBIG *i1, INTBIG *i2, INTBIG n);
356 static double      sim_window_sensibletimevalue(double time);
357 static void        sim_window_set_anahigh(int frameno, float value);
358 static void        sim_window_set_analow(int frameno, float value);
359 static void        sim_window_set_botval(int frameno, float value);
360 static int         sim_window_set_frames(int n);
361 static void        sim_window_set_topval(int frameno, float value);
362 static void        sim_window_setcolor(INTBIG);
363 static void        sim_window_setmask(INTBIG);
364 static void        sim_window_setviewport(WINDOWPART*);
365 static void        sim_window_showtracebar(WINDOWPART *wavewin, INTBIG frame, INTBIG style);
366 static void        sim_window_termhandler(WINDOWPART *w);
367 static INTBIG      sim_window_timetoxpos(double);
368 static void        sim_window_trace_range(INTBIG tri) ;
369 static INTBIG      sim_window_valtoypos(INTBIG frameno, double val);
370 static BOOLEAN     sim_window_verticalslider(INTBIG x, INTBIG y);
371 static void        sim_window_vthumbtrackingcallback(INTBIG delta);
372 static void        sim_window_writetracename(WINDOWPART*, TRACE*);
373 static double      sim_window_xpostotime(INTBIG);
374 static INTBIG      sim_window_ypostoval(INTBIG ypos, double *val);
375 static BOOLEAN     sim_window_zoomdown(INTBIG, INTBIG);
376 
377 /********************************* WINDOW CONTROL *********************************/
378 
379 /*
380  * routine to initialize the simulation window
381  */
sim_window_init(void)382 void sim_window_init(void)
383 {
384 	sim_window_signalorder_key = makekey(x_("SIM_window_signalorder"));
385 	sim_window_hierpos_key = makekey(x_("SIM_window_hierarchy_pos"));
386 
387 	sim_window_statekey = makekey(x_("SIM_window_state"));
388 #if SIMTOOLIRSIM == 0
389 	sim_window_state = FULLSTATE | SHOWWAVEFORM;
390 #else
391 	sim_window_state = FULLSTATE | SHOWWAVEFORM | SIMENGINEIRSIM;
392 #endif
393 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_window_statekey,
394 		sim_window_state, VINTEGER|VDONTSAVE);
395 
396 	sim_window_maincursor = 0.0000002f;
397 	sim_window_extensioncursor = 0.0000003f;
398 	(void)sim_window_set_frames(0) ;
399 	sim_window_visframes = 0;
400 	sim_window_topframes = 0;
401 	sim_window_highframe = -1;
402 	sim_window_firstrace = NOTRACE;
403 	sim_window_tracefree = NOTRACE;
404 	sim_window_highlightedtracecount = 0;
405 	sim_window_wavexnameend = DEFWAVEXNAMEEND;
406 	sim_window_wavexnameendana = DEFWAVEXNAMEENDANA;
407 	sim_window_wavexbar = DEFWAVEXBAR;
408 	sim_window_wavexsigstart = DEFWAVEXSIGSTART;
409 	sim_window_playing = VCRSTOP;
410 	sim_window_advancespeed = 2;
411 
412 	/* setup simulation window colors */
413 	sim_colorstrengthoff = BLUE;
414 	sim_colorstrengthnode = GREEN;
415 	sim_colorstrengthgate = MAGENTA;
416 	sim_colorstrengthpower = BLACK;
417 	sim_colorlevellow = BLUE;
418 	sim_colorlevelhigh = MAGENTA;
419 	sim_colorlevelundef = BLACK;
420 	sim_colorlevelzdef = LGRAY;
421 	sim_colorstrengthoff_key = makekey(x_("SIM_window_color_str0"));
422 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorstrengthoff_key, sim_colorstrengthoff, VINTEGER|VDONTSAVE);
423 	sim_colorstrengthnode_key = makekey(x_("SIM_window_color_str1"));
424 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorstrengthnode_key, sim_colorstrengthnode, VINTEGER|VDONTSAVE);
425 	sim_colorstrengthgate_key = makekey(x_("SIM_window_color_str2"));
426 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorstrengthgate_key, sim_colorstrengthgate, VINTEGER|VDONTSAVE);
427 	sim_colorstrengthpower_key = makekey(x_("SIM_window_color_str3"));
428 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorstrengthpower_key, sim_colorstrengthpower, VINTEGER|VDONTSAVE);
429 	sim_colorlevellow_key = makekey(x_("SIM_window_color_low"));
430 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorlevellow_key, sim_colorlevellow, VINTEGER|VDONTSAVE);
431 	sim_colorlevelhigh_key = makekey(x_("SIM_window_color_high"));
432 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorlevelhigh_key, sim_colorlevelhigh, VINTEGER|VDONTSAVE);
433 	sim_colorlevelundef_key = makekey(x_("SIM_window_color_X"));
434 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorlevelundef_key, sim_colorlevelundef, VINTEGER|VDONTSAVE);
435 	sim_colorlevelzdef_key = makekey(x_("SIM_window_color_Z"));
436 	(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorlevelzdef_key, sim_colorlevelzdef, VINTEGER|VDONTSAVE);
437 }
438 
439 /*
440  * routine to terminate the simulation window module memory
441  */
sim_freewindowmemory(void)442 void sim_freewindowmemory(void)
443 {
444 	REGISTER TRACE *tr;
445 
446 	sim_window_killalltraces(FALSE);
447 
448 	while (sim_window_tracefree != NOTRACE)
449 	{
450 		tr = sim_window_tracefree;
451 		sim_window_tracefree = sim_window_tracefree->nexttrace;
452 		if (tr->timelimit > 0) efree((CHAR *)tr->timearray);
453 		if (tr->statelimit > 0) efree((CHAR *)tr->statearray);
454 		if (tr->valuelimit > 0) efree((CHAR *)tr->valuearray);
455 		efree((CHAR *)tr);
456 	}
457 	if (sim_window_highlightedtracetotal > 0) efree((CHAR *)sim_window_highlightedtraces);
458 	if (sim_window_bustracetotal > 0) efree((CHAR *)sim_window_bustraces);
459 	if (sim_window_sigtotal > 0)
460 	{
461 		efree((CHAR *)sim_window_sigvalues);
462 		sim_window_sigtotal = 0;
463 	}
464 	if (sim_window_lines_limit > 0)
465 	{
466 		efree((CHAR *)sim_window_frame_analow);
467 		efree((CHAR *)sim_window_frame_anahigh);
468 		efree((CHAR *)sim_window_frame_topval);
469 		efree((CHAR *)sim_window_frame_botval);
470 	}
471 	if (sim_window_title != 0) efree((CHAR *)sim_window_title);
472 	if (sim_window_traceprefix != 0) efree((CHAR *)sim_window_traceprefix);
473 	if (sim_veroldstringarray == 0)
474 		killstringarray(sim_veroldstringarray);
475 }
476 
477 /*
478  * routine to start a simulation window with room for "framecount" traces and associated cell "np".
479  * The character handler to use in the waveform window is in "charhandlerwave", the character
480  * handler to use in the schematic/layout window is in "charhandlerschem".  Returns true on error.
481  */
sim_window_create(INTBIG framecount,NODEPROTO * np,BOOLEAN (* charhandlerwave)(WINDOWPART *,INTSML,INTBIG),BOOLEAN (* charhandlerschem)(WINDOWPART *,INTSML,INTBIG),INTBIG format)482 BOOLEAN sim_window_create(INTBIG framecount, NODEPROTO *np, BOOLEAN (*charhandlerwave)(WINDOWPART*, INTSML, INTBIG),
483 	BOOLEAN (*charhandlerschem)(WINDOWPART*, INTSML, INTBIG), INTBIG format)
484 {
485 	REGISTER WINDOWPART *wavewin, *schemwin;
486 	REGISTER NODEPROTO *simnp;
487 
488 	/* sorry, can't have more than 1 simulation window at a time */
489 	wavewin = sim_window_findwaveform();
490 	schemwin = sim_window_findschematics();
491 	simnp = NONODEPROTO;
492 	if (wavewin != NOWINDOWPART && (wavewin->state&WINDOWSIMMODE) != 0)
493 		simnp = wavewin->curnodeproto;
494 	if (schemwin != NOWINDOWPART) simnp = schemwin->curnodeproto;
495 	if (simnp != NONODEPROTO && simnp != np)
496 	{
497 		ttyputerr(x_("Sorry, already simulating cell %s"), describenodeproto(simnp));
498 		return(TRUE);
499 	}
500 
501 	/* reinitialize waveform display if number of lines is specified */
502 	if (framecount > 0)
503 	{
504 		sim_window_killalltraces(TRUE);
505 		if (sim_window_set_frames(framecount) == 0) return TRUE;
506 		sim_window_topframes = 0;
507 	}
508 
509 	/* save simulation format */
510 	sim_window_format = format;
511 
512 	/* determine the number of visible signals */
513 	sim_window_visframes = sim_window_lines;
514 	sim_window_curanacolor = 0;
515 	sim_window_vdd = 0.0;
516 
517 	/* remove title information */
518 	if (sim_window_title != 0) efree((CHAR *)sim_window_title);
519 	sim_window_title = 0;
520 
521 	/* remove trace prefix information */
522 	if (sim_window_traceprefix != 0) efree((CHAR *)sim_window_traceprefix);
523 	sim_window_traceprefix = 0;
524 
525 	/* create waveform window if requested */
526 	if (charhandlerwave != 0)
527 	{
528 		if (wavewin == NOWINDOWPART)
529 		{
530 			/* get window state information */
531 			switch (sim_window_state&WAVEPLACE)
532 			{
533 				case WAVEPLACECAS:
534 					wavewin = (WINDOWPART *)asktool(us_tool, x_("window-new"));
535 					break;
536 				case WAVEPLACETHOR:
537 					wavewin = (WINDOWPART *)asktool(us_tool, x_("window-horiz-new"));
538 					break;
539 				case WAVEPLACETVER:
540 					wavewin = (WINDOWPART *)asktool(us_tool, x_("window-vert-new"));
541 					break;
542 			}
543 			if (wavewin == NOWINDOWPART) return(TRUE);
544 		}
545 		sim_window_setviewport(wavewin);
546 
547 		startobjectchange((INTBIG)wavewin, VWINDOWPART);
548 		(void)setval((INTBIG)wavewin, VWINDOWPART, x_("state"), (wavewin->state & ~WINDOWTYPE) | WAVEFORMWINDOW |
549 			WINDOWSIMMODE, VINTEGER);
550 		(void)setval((INTBIG)wavewin, VWINDOWPART, x_("curnodeproto"), (INTBIG)np, VNODEPROTO);
551 		(void)setval((INTBIG)wavewin, VWINDOWPART, x_("buttonhandler"), (INTBIG)sim_window_buttonhandler, VADDRESS);
552 		(void)setval((INTBIG)wavewin, VWINDOWPART, x_("charhandler"), (INTBIG)charhandlerwave, VADDRESS);
553 		(void)setval((INTBIG)wavewin, VWINDOWPART, x_("redisphandler"), (INTBIG)sim_window_redisphandler, VADDRESS);
554 		(void)setval((INTBIG)wavewin, VWINDOWPART, x_("termhandler"), (INTBIG)sim_window_termhandler, VADDRESS);
555 		endobjectchange((INTBIG)wavewin, VWINDOWPART);
556 		us_setcellname(wavewin);
557 	}
558 
559 	/* find and setup associated schematics/layout window if requested */
560 	if (charhandlerschem != 0)
561 	{
562 		for(schemwin = el_topwindowpart; schemwin != NOWINDOWPART;
563 			schemwin = schemwin->nextwindowpart)
564 		{
565 			if ((schemwin->state&WINDOWTYPE) != DISPWINDOW &&
566 				(schemwin->state&WINDOWTYPE) != DISP3DWINDOW) continue;
567 			if (schemwin->curnodeproto == np) break;
568 		}
569 		if (schemwin != NOWINDOWPART)
570 		{
571 			startobjectchange((INTBIG)schemwin, VWINDOWPART);
572 			(void)setval((INTBIG)schemwin, VWINDOWPART, x_("state"), schemwin->state |
573 				WINDOWSIMMODE, VINTEGER);
574 			(void)setval((INTBIG)schemwin, VWINDOWPART, x_("charhandler"),
575 				(INTBIG)charhandlerschem, VADDRESS);
576 			endobjectchange((INTBIG)schemwin, VWINDOWPART);
577 		}
578 	}
579 	return(FALSE);
580 }
581 
sim_window_titleinfo(CHAR * title)582 void sim_window_titleinfo(CHAR *title)
583 {
584 	if (sim_window_title != 0) efree((CHAR *)sim_window_title);
585 	allocstring(&sim_window_title, title, sim_tool->cluster);
586 }
587 
588 /*
589  * Routine to stop simulation.
590  */
sim_window_stopsimulation(void)591 void sim_window_stopsimulation(void)
592 {
593 	REGISTER WINDOWPART *schemwin, *wavewin;
594 
595 	/* disable simulation control in schematics/layout window */
596 	schemwin = sim_window_findschematics();
597 	if (schemwin != NOWINDOWPART)
598 	{
599 		startobjectchange((INTBIG)schemwin, VWINDOWPART);
600 		(void)setval((INTBIG)schemwin, VWINDOWPART, x_("state"), schemwin->state &
601 			~WINDOWSIMMODE, VINTEGER);
602 		(void)setval((INTBIG)schemwin, VWINDOWPART, x_("charhandler"),
603 			(INTBIG)DEFAULTCHARHANDLER, VADDRESS);
604 		endobjectchange((INTBIG)schemwin, VWINDOWPART);
605 	}
606 
607 	/* disable waveform window */
608 	wavewin = sim_window_findwaveform();
609 	if (wavewin != NOWINDOWPART)
610 	{
611 		startobjectchange((INTBIG)wavewin, VWINDOWPART);
612 		(void)setval((INTBIG)wavewin, VWINDOWPART, x_("state"), wavewin->state &
613 			~WINDOWSIMMODE, VINTEGER);
614 		endobjectchange((INTBIG)wavewin, VWINDOWPART);
615 	}
616 }
617 
618 /*
619  * Routine to set vdd value used for grid
620  */
sim_window_setvdd(float vdd)621 void sim_window_setvdd(float vdd)
622 {
623 	sim_window_vdd = vdd;
624 }
625 
626 /*
627  * routine that returns:
628  *  0                                    if there is no active simulation
629  *  SIMWINDOWWAVEFORM                    if simulating and have a waveform window
630  *  SIMWINDOWSCHEMATIC                   if simulating and have a schematics window
631  *  SIMWINDOWWAVEFORM|SIMWINDOWSCHEMATIC if simulating and have both windows
632  * If there is active simulation, the cell being simulated is returned in "np"
633  */
sim_window_isactive(NODEPROTO ** np)634 INTBIG sim_window_isactive(NODEPROTO **np)
635 {
636 	REGISTER INTBIG activity;
637 	REGISTER WINDOWPART *wavewin, *schemwin;
638 
639 	*np = NONODEPROTO;
640 	activity = 0;
641 	schemwin = sim_window_findschematics();
642 	if (schemwin != NOWINDOWPART)
643 	{
644 		activity |= SIMWINDOWSCHEMATIC;
645 		*np = schemwin->curnodeproto;
646 	}
647 	wavewin = sim_window_findwaveform();
648 	if (wavewin != NOWINDOWPART && (wavewin->state&WINDOWSIMMODE) != 0)
649 	{
650 		activity |= SIMWINDOWWAVEFORM;
651 		*np = wavewin->curnodeproto;
652 	}
653 	return(activity);
654 }
655 
656 /*
657  * this procedure redraws everything, including the waveforms.
658  */
sim_window_redraw(void)659 void sim_window_redraw(void)
660 {
661 	REGISTER WINDOWPART *wavewin;
662 
663 	/* get the waveform window */
664 	wavewin = sim_window_findwaveform();
665 	if (wavewin == NOWINDOWPART) return;
666 	sim_window_redisphandler(wavewin);
667 }
668 
669 /*
670  * routine that changes the number of trace frames in the simulation window to "count"
671  */
sim_window_setnumframes(INTBIG count)672 void sim_window_setnumframes(INTBIG count)
673 {
674 	(void)sim_window_set_frames(count);
675 	if (sim_window_lines < sim_window_visframes)
676 		sim_window_visframes = sim_window_lines;
677 }
678 
679 /*
680  * routine that returns the number of signals in the simulation window
681  */
sim_window_getnumframes(void)682 INTBIG sim_window_getnumframes(void)
683 {
684 	return(sim_window_lines);
685 }
686 
687 /*
688  * routine that returns the number of visible signals in the simulation window
689  */
sim_window_getnumvisframes(void)690 INTBIG sim_window_getnumvisframes(void)
691 {
692 	return(sim_window_visframes);
693 }
694 
695 /*
696  * routine that changes the top visible trace frame in the simulation window to "count"
697  */
sim_window_settopvisframe(INTBIG top)698 void sim_window_settopvisframe(INTBIG top)
699 {
700 	if (top < 0) top = 0;
701 	sim_window_topframes = top;
702 }
703 
704 /*
705  * routine that returns the top visible signal in the simulation window.
706  */
sim_window_gettopvisframe(void)707 INTBIG sim_window_gettopvisframe(void)
708 {
709 	return(sim_window_topframes);
710 }
711 
712 /********************************* CONTROL OF TRACES *********************************/
713 
714 /*
715  * routine to create a new trace to be displayed in window frame
716  * "frameno".  Its name is set to "name", and "userdata" is
717  * associated with it.  A pointer to the trace is returned (zero on error).
718  */
sim_window_newtrace(INTBIG frameno,CHAR * name,INTBIG userdata)719 INTBIG sim_window_newtrace(INTBIG frameno, CHAR *name, INTBIG userdata)
720 {
721 	REGISTER TRACE *tr, *otr, *lasttr;
722 
723 	/* create a new trace */
724 	tr = sim_window_alloctrace();
725 	if (tr == NOTRACE) return(0);
726 	tr->nodeptr = userdata;
727 	tr->mintime = sim_window_maincursor;
728 	tr->maxtime = sim_window_extensioncursor;
729 
730 	/* set name and convert if it has array index form */
731 	(void)allocstring(&tr->name, name, sim_tool->cluster);
732 	(void)allocstring(&tr->origname, name, sim_tool->cluster);
733 
734 	/* put in active list */
735 	lasttr = NOTRACE;
736 	for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
737 		lasttr = otr;
738 	sim_window_addtrace(tr, lasttr);
739 
740 	if (frameno >= 0) tr->frameno = frameno; else
741 	{
742 		tr->frameno = -1;
743 		sim_window_renumberlines();
744 
745 		sim_window_setnumframes(sim_window_lines);
746 		sim_window_redraw();
747 	}
748 
749 	/* save the new configuration */
750 	sim_window_savesignalorder();
751 
752 	return((INTBIG)tr);
753 }
754 
755 /*
756  * Routine to open/close a bus.  Returns true on error.
757  */
sim_window_buscommand(void)758 BOOLEAN sim_window_buscommand(void)
759 {
760 	REGISTER TRACE *tr;
761 	REGISTER INTBIG i, count, newtr;
762 	INTBIG *tracelist;
763 
764 	if (sim_window_highlightedtracecount == 0) return(TRUE);
765 	if (sim_window_highlightedtracecount == 1)
766 	{
767 		tr = sim_window_highlightedtraces[0];
768 		switch (tr->flags&TRACETYPE)
769 		{
770 			case TRACEISDIGITAL:
771 			case TRACEISANALOG:
772 				ttyputerr(_("Must select multiple signals to pack into a bus"));
773 				break;
774 			case TRACEISBUS:
775 				ttyputmsg(_("Double-click the bus name to open it"));
776 				break;
777 			case TRACEISOPENBUS:
778 				ttyputmsg(_("Double-click the bus name to close it"));
779 				break;
780 		}
781 		return(TRUE);
782 	}
783 
784 	/* copy highlighted traces to an array and remove highlighting */
785 	count = sim_window_highlightedtracecount;
786 	tracelist = (INTBIG *)emalloc(count * SIZEOFINTBIG, sim_tool->cluster);
787 	if (tracelist == 0) return(TRUE);
788 	for(i=0; i<count; i++)
789 		tracelist[i] = (INTBIG)sim_window_highlightedtraces[i];
790 	sim_window_cleartracehighlight();
791 
792 	/* make the bus */
793 	newtr = sim_window_makebus(count, tracelist, 0);
794 	efree((CHAR *)tracelist);
795 	if (newtr == 0) return(TRUE);
796 	sim_window_addhighlighttrace(newtr);
797 
798 	/* redisplay */
799 	sim_window_redraw();
800 
801 	/* save the new configuration */
802 	sim_window_savesignalorder();
803 	return(FALSE);
804 }
805 
sim_window_makebus(INTBIG count,INTBIG * traces,CHAR * busname)806 INTBIG sim_window_makebus(INTBIG count, INTBIG *traces, CHAR *busname)
807 {
808 	REGISTER TRACE *tr, *lasttr, *newtr, **tracelist;
809 	REGISTER INTBIG i, flags;
810 
811 	/* check for errors */
812 	tracelist = (TRACE **)traces;
813 	for(i=0; i<count; i++)
814 	{
815 		flags = tracelist[i]->flags & TRACETYPE;
816 		if (flags == TRACEISBUS || flags == TRACEISOPENBUS)
817 		{
818 			ttyputerr(_("Cannot place a bus into another bus"));
819 			return(0);
820 		}
821 		if (tracelist[i]->buschannel != NOTRACE)
822 		{
823 			ttyputerr(_("Signal '%s' is already on bus '%s'"), tracelist[i]->name,
824 				tracelist[i]->buschannel->name);
825 			return(0);
826 		}
827 	}
828 	if (count > MAXSIMWINDOWBUSWIDTH)
829 	{
830 		ttyputerr(_("Can only handle busses that are %d bits wide"), MAXSIMWINDOWBUSWIDTH);
831 		return(0);
832 	}
833 
834 	/* find place to insert bus */
835 	lasttr = NOTRACE;
836 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
837 	{
838 		for(i=0; i<count; i++)
839 			if (tracelist[i] == tr) break;
840 		if (i < count) break;
841 		lasttr = tr;
842 	}
843 
844 	/* create a new trace that combines all of these */
845 	newtr = sim_window_alloctrace();
846 	if (newtr == NOTRACE) return(0);
847 	if (busname != 0) (void)allocstring(&newtr->name, busname, sim_tool->cluster); else
848 		(void)allocstring(&newtr->name, sim_window_namesignals(count, tracelist),
849 			sim_tool->cluster);
850 	(void)allocstring(&newtr->origname, newtr->name, sim_tool->cluster);
851 	newtr->nodeptr = 0;
852 	newtr->flags = TRACEISBUS;
853 
854 	/* insert it after "lasttr" */
855 	sim_window_addtrace(newtr, lasttr);
856 
857 	/* flag the signals as part of this bus */
858 	for(i=0; i<count; i++)
859 	{
860 		tr = tracelist[i];
861 		tr->buschannel = newtr;
862 		tr->flags |= TRACENOTDRAWN;
863 		if (i == 0)
864 		{
865 			newtr->mintime = tr->mintime;
866 			newtr->maxtime = tr->maxtime;
867 		} else
868 		{
869 			if (tr->mintime < newtr->mintime) newtr->mintime = tr->mintime;
870 			if (tr->maxtime > newtr->maxtime) newtr->maxtime = tr->maxtime;
871 		}
872 	}
873 
874 	/* renumber the lines in the display */
875 	sim_window_renumberlines();
876 	return((INTBIG)newtr);
877 }
878 
879 /*
880  * Routine to generate a bus name for the "count" signals in "list".
881  */
sim_window_namesignals(INTBIG count,TRACE ** list)882 CHAR *sim_window_namesignals(INTBIG count, TRACE **list)
883 {
884 	REGISTER INTBIG i, j, rootlen, lastvalue, thisvalue, direction;
885 	REGISTER TRACE *tr, *ptr;
886 	REGISTER void *infstr;
887 
888 	/* look for common root */
889 	rootlen = 0;
890 	for(i=1; i<count; i++)
891 	{
892 		ptr = list[i-1];
893 		tr = list[i];
894 		for(j=0; ; j++)
895 		{
896 			if (ptr->name[j] == 0 || tr->name[0] == 0) break;
897 			if (ptr->name[j] != tr->name[j]) break;
898 		}
899 		if (i == 1 || j < rootlen) rootlen = j;
900 	}
901 
902 	/* if there is a common root, make sure it is proper */
903 	if (rootlen > 0)
904 	{
905 		tr = list[0];
906 		if (tr->name[rootlen-1] != '[')
907 		{
908 			for(i=0; i<count; i++)
909 			{
910 				tr = list[i];
911 				if (isdigit(tr->name[rootlen]) == 0) break;
912 			}
913 			if (i < count) rootlen = 0;
914 		}
915 	}
916 
917 	/* if there is a common root, use it */
918 	if (rootlen > 0)
919 	{
920 		infstr = initinfstr();
921 		tr = list[0];
922 		for(j=0; j<rootlen; j++) (void)addtoinfstr(infstr, tr->name[j]);
923 
924 		for(i=0; i<count; i++)
925 		{
926 			tr = list[i];
927 			if (i != 0) addtoinfstr(infstr, ',');
928 			for(j=rootlen; tr->name[j] != ']' && tr->name[j] != 0; j++)
929 				addtoinfstr(infstr, tr->name[j]);
930 
931 			/* see if there is a sequence */
932 			thisvalue = 0;
933 			lastvalue = eatoi(&tr->name[rootlen]);
934 			direction = 0;
935 			for(j=i+1; j<count; j++)
936 			{
937 				thisvalue = eatoi(&list[j]->name[rootlen]);
938 				if (direction == 0)
939 				{
940 					if (lastvalue+1 == thisvalue) direction = 1; else
941 						if (lastvalue-1 == thisvalue) direction = -1; else
942 							break;
943 				}
944 				if (lastvalue + direction != thisvalue) break;
945 				lastvalue = thisvalue;
946 			}
947 			if (j > i+1)
948 			{
949 				formatinfstr(infstr, x_(":%ld"), thisvalue);
950 				i = j;
951 			}
952 		}
953 		if (tr->name[rootlen-1] == '[') addtoinfstr(infstr, ']');
954 		return(returninfstr(infstr));
955 	}
956 
957 	/* no common root: concatenate all signal names */
958 	infstr = initinfstr();
959 	for(i=0; i<count; i++)
960 	{
961 		if (i != 0) addtoinfstr(infstr, ',');
962 		tr = list[i];
963 		addstringtoinfstr(infstr, tr->name);
964 	}
965 	return(returninfstr(infstr));
966 }
967 
968 /*
969  * Routine called when simulating, and the current cell changes to "cell".
970  * caches the signal order for that cell, and updates the waveform window to
971  * be associated with that cell.
972  *
973  * The list of signals can be found by calling "sim_window_getcachedsignals()"
974  */
sim_window_grabcachedsignalsoncell(NODEPROTO * cell)975 void sim_window_grabcachedsignalsoncell(NODEPROTO *cell)
976 {
977 	REGISTER VARIABLE *var;
978 	REGISTER INTBIG i, count;
979 	REGISTER WINDOWPART *w;
980 
981 	if (sim_veroldstringarray == 0)
982 		sim_veroldstringarray = newstringarray(sim_tool->cluster);
983 	clearstrings(sim_veroldstringarray);
984 	var = getvalkey((INTBIG)cell, VNODEPROTO, VSTRING|VISARRAY,
985 		sim_window_signalorder_key);
986 	if (var != NOVARIABLE)
987 	{
988 		count = getlength(var);
989 		for(i=0; i<count; i++)
990 			addtostringarray(sim_veroldstringarray, ((CHAR **)var->addr)[i]);
991 	}
992 
993 	/* find the waveform window and make sure it has the right cell */
994 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
995 	{
996 		if ((w->state & WINDOWTYPE) != WAVEFORMWINDOW) continue;
997 		w->curnodeproto = cell;
998 		break;
999 	}
1000 }
1001 
1002 /*
1003  * Routine to return the number of strings that were found on the cell that
1004  * was passed to "sim_window_grabcachedsignalsoncell()".  The strings are returned
1005  * in "strings".
1006  */
sim_window_getcachedsignals(CHAR *** strings)1007 INTBIG sim_window_getcachedsignals(CHAR ***strings)
1008 {
1009 	INTBIG count;
1010 
1011 	*strings = getstringarray(sim_veroldstringarray, &count);
1012 	return(count);
1013 }
1014 
sim_window_savesignalorder(void)1015 void sim_window_savesignalorder(void)
1016 {
1017 	REGISTER TRACE *tr, *otr;
1018 	NODEPROTO *np;
1019 	CHAR **strings;
1020 	INTBIG count, i, j;
1021 	REGISTER void *infstr;
1022 
1023 	if (sim_window_isactive(&np) == 0) return;
1024 	for(count = 0, tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1025 		if ((tr->flags&TRACENOTDRAWN) == 0 && tr->buschannel == NOTRACE) count++;
1026 	if (count == 0)
1027 	{
1028 		if (getvalkey((INTBIG)np, VNODEPROTO, VSTRING|VISARRAY, sim_window_signalorder_key) != NOVARIABLE)
1029 			(void)delvalkey((INTBIG)np, VNODEPROTO, sim_window_signalorder_key);
1030 	} else
1031 	{
1032 		strings = (CHAR **)emalloc(count * (sizeof (CHAR *)), sim_tool->cluster);
1033 		for(i=0, j=0, tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace, i++)
1034 		{
1035 			if ((tr->flags&TRACENOTDRAWN) != 0 || tr->buschannel != NOTRACE) continue;
1036 			if ((tr->flags&TRACETYPE) == TRACEISBUS || (tr->flags&TRACETYPE) == TRACEISOPENBUS)
1037 			{
1038 				/* construct name for this bus */
1039 				infstr = initinfstr();
1040 				addstringtoinfstr(infstr, tr->origname);
1041 				for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
1042 				{
1043 					if (otr->buschannel != tr) continue;
1044 					formatinfstr(infstr, x_("\t%ld:%s"), otr->frameno, otr->origname);
1045 				}
1046 				(void)allocstring(&strings[j++], returninfstr(infstr), sim_tool->cluster);
1047 			} else
1048 			{
1049 				infstr = initinfstr();
1050 				formatinfstr(infstr, x_("%ld:%s"), tr->frameno, tr->origname);
1051 				(void)allocstring(&strings[j++], returninfstr(infstr), sim_tool->cluster);
1052 			}
1053 		}
1054 		(void)setvalkey((INTBIG)np, VNODEPROTO, sim_window_signalorder_key, (INTBIG)strings,
1055 			VSTRING|VISARRAY|(count<<VLENGTHSH));
1056 		for(i=0; i<count; i++) efree((CHAR *)strings[i]);
1057 		efree((CHAR *)strings);
1058 	}
1059 }
1060 
1061 /*
1062  * routine to load trace "tri" with "count" digital events.  The events occur
1063  * at time "time" and have state "state".  "State" is encoded with a
1064  * level in the upper 8 bits (LOGIC_LOW, LOGIC_HIGH, LOGIC_X, or LOGIC_Z) and a
1065  * strength in the lower 8 bits (OFF_STRENGTH, NODE_STRENGTH, GATE_STRENGTH,
1066  * or VDD_STRENGTH).
1067  */
sim_window_loaddigtrace(INTBIG tri,INTBIG count,double * time,INTSML * state)1068 void sim_window_loaddigtrace(INTBIG tri, INTBIG count, double *time, INTSML *state)
1069 {
1070 	REGISTER INTBIG wanted, i;
1071 	REGISTER TRACE *tr;
1072 
1073 	/* ensure space in the arrays */
1074 	tr = (TRACE *)tri;
1075 	if (tr == NOTRACE || tr == 0) return;
1076 	if (count > tr->timelimit)
1077 	{
1078 		if (tr->timelimit > 0)
1079 		{
1080 			efree((CHAR *)tr->timearray);
1081 			tr->timelimit = 0;
1082 		}
1083 		wanted = count + 10;
1084 		tr->timearray = (double *)emalloc(wanted * (sizeof (double)), sim_tool->cluster);
1085 		if (tr->timearray == 0) return;
1086 		tr->timelimit = wanted;
1087 	}
1088 	if (count > tr->statelimit)
1089 	{
1090 		if (tr->statelimit > 0)
1091 		{
1092 			efree((CHAR *)tr->statearray);
1093 			tr->statelimit = 0;
1094 		}
1095 		wanted = count + 10;
1096 		tr->statearray = (INTBIG *)emalloc(wanted * SIZEOFINTBIG, sim_tool->cluster);
1097 		tr->statelimit = wanted;
1098 	}
1099 
1100 	/* load the data */
1101 	for(i=0; i<count; i++)
1102 	{
1103 		tr->timearray[i] = time[i];
1104 		tr->statearray[i] = state[i];
1105 	}
1106 	tr->flags = (tr->flags & ~TRACETYPE) | TRACEISDIGITAL;
1107 	tr->numsteps = count;
1108 }
1109 
1110 /*
1111  * routine to load trace "tri" with "count" analog events.  The events occur
1112  * at time "time" and have value "value".
1113  */
sim_window_loadanatrace(INTBIG tri,INTBIG count,double * time,float * value)1114 void sim_window_loadanatrace(INTBIG tri, INTBIG count, double *time, float *value)
1115 {
1116 	REGISTER INTBIG wanted, i;
1117 	REGISTER TRACE *tr;
1118 
1119 	/* ensure space in the arrays */
1120 	tr = (TRACE *)tri;
1121 	if (tr == NOTRACE || tr == 0) return;
1122 	if (count > tr->timelimit)
1123 	{
1124 		if (tr->timelimit > 0)
1125 		{
1126 			efree((CHAR *)tr->timearray);
1127 			tr->timelimit = 0;
1128 		}
1129 		wanted = count + 10;
1130 		tr->timearray = (double *)emalloc(wanted * (sizeof (double)), sim_tool->cluster);
1131 		if (tr->timearray == 0) return;
1132 		tr->timelimit = wanted;
1133 	}
1134 	if (count > tr->valuelimit)
1135 	{
1136 		if (tr->valuelimit > 0)
1137 		{
1138 			efree((CHAR *)tr->valuearray);
1139 			tr->valuelimit = 0;
1140 		}
1141 		wanted = count + 10;
1142 		tr->valuearray = (float *)emalloc(wanted * (sizeof (float)), sim_tool->cluster);
1143 		if (tr->valuearray == 0) return;
1144 		tr->valuelimit = wanted;
1145 	}
1146 
1147 	/* load the data */
1148 	for(i=0; i<count; i++)
1149 	{
1150 		tr->timearray[i] = time[i];
1151 		tr->valuearray[i] = value[i];
1152 	}
1153 	tr->flags = (tr->flags & ~TRACETYPE) | TRACEISANALOG;
1154 	tr->color = sim_window_anacolor[sim_window_curanacolor];
1155 	sim_window_curanacolor++;
1156 	if (sim_window_anacolor[sim_window_curanacolor] == 0) sim_window_curanacolor = 0;
1157 	tr->numsteps = count;
1158 	sim_window_trace_range(tri);
1159 #if 1
1160 	sim_window_auto_anarange();
1161 #endif
1162 }
1163 
sim_window_settraceframe(INTBIG tri,INTBIG frameno)1164 void sim_window_settraceframe(INTBIG tri, INTBIG frameno)
1165 {
1166 	REGISTER TRACE *tr;
1167 
1168 	tr = (TRACE *)tri;
1169 	if (tr == NOTRACE || tr == 0) return;
1170 	tr->frameno = frameno;
1171 }
1172 
1173 /*
1174  * routine to delete the trace "tri"
1175  */
sim_window_killtrace(INTBIG tri)1176 void sim_window_killtrace(INTBIG tri)
1177 {
1178 	REGISTER TRACE *tr, *str, *ltr, *otr;
1179 	REGISTER INTBIG frameno;
1180 
1181 	tr = (TRACE *)tri;
1182 	if (tr == NOTRACE || tr == 0) return;
1183 	frameno = tr->frameno;
1184 	ltr = NOTRACE;
1185 	for(str = sim_window_firstrace; str != NOTRACE; str = str->nexttrace)
1186 	{
1187 		if (str == tr) break;
1188 		ltr = str;
1189 	}
1190 	if (ltr == NOTRACE) sim_window_firstrace = tr->nexttrace; else
1191 		ltr->nexttrace = tr->nexttrace;
1192 	tr->nexttrace = sim_window_tracefree;
1193 	sim_window_tracefree = tr;
1194 	efree(tr->name);
1195 	efree(tr->origname);
1196 
1197 	/* if a bus was deleted, make it's individual signals be visible and independent */
1198 	if ((tr->flags&TRACETYPE) == TRACEISBUS || (tr->flags&TRACETYPE) == TRACEISOPENBUS)
1199 	{
1200 		for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
1201 		{
1202 			if (otr->buschannel != tr) continue;
1203 			otr->buschannel = NOTRACE;
1204 			otr->flags &= ~TRACENOTDRAWN;
1205 		}
1206 	}
1207 
1208 	/* renumber the lines in the display */
1209 	sim_window_renumberlines();
1210 
1211 	/* save the new configuration */
1212 	sim_window_savesignalorder();
1213 
1214 	/* if the number of lines is less than the number of visible lines, redisplay */
1215 	if (sim_window_lines < sim_window_visframes)
1216 	{
1217 		sim_window_setnumframes(sim_window_lines);
1218 		sim_window_redraw();
1219 	}
1220 }
1221 
1222 /*
1223  * routine to delete all traces
1224  */
sim_window_killalltraces(BOOLEAN save)1225 void sim_window_killalltraces(BOOLEAN save)
1226 {
1227 	REGISTER TRACE *tr, *nexttr;
1228 
1229 	/* return all plot channels to the free list */
1230 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = nexttr)
1231 	{
1232 		nexttr = tr->nexttrace;
1233 		tr->nexttrace = sim_window_tracefree;
1234 		sim_window_tracefree = tr;
1235 		efree(tr->name);
1236 		efree(tr->origname);
1237 	}
1238 	sim_window_firstrace = NOTRACE;
1239 	sim_window_highlightedtracecount = 0;
1240 
1241 	/* save the new configuration */
1242 	if (save) sim_window_savesignalorder();
1243 	sim_window_set_frames(1);
1244 	sim_window_visframes = 1;
1245 	sim_window_topframes = 0;
1246 	sim_window_highframe = -1;
1247 }
1248 
1249 /*
1250  * Ignore "prefix" when it appears at the start of a trace name.
1251  */
sim_window_supresstraceprefix(CHAR * prefix)1252 void sim_window_supresstraceprefix(CHAR *prefix)
1253 {
1254 	if (sim_window_traceprefix != 0) efree((CHAR *)sim_window_traceprefix);
1255 	allocstring(&sim_window_traceprefix, prefix, sim_tool->cluster);
1256 }
1257 
1258 /********************************* TRACE INFORMATION *********************************/
1259 
sim_window_getbustraces(INTBIG tri)1260 INTBIG *sim_window_getbustraces(INTBIG tri)
1261 {
1262 	REGISTER TRACE *tr, *otr;
1263 	REGISTER INTBIG count, newtotal, i;
1264 	REGISTER TRACE **newbustraces;
1265 	static INTBIG nullbustraces[1];
1266 
1267 	tr = (TRACE *)tri;
1268 	count = 0;
1269 	for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
1270 	{
1271 		if (otr->buschannel != tr) continue;
1272 		if (count+1 >= sim_window_bustracetotal)
1273 		{
1274 			newtotal = sim_window_bustracetotal*2;
1275 			if (newtotal == 0) newtotal = 5;
1276 			if (count+1 > newtotal) newtotal = count+1;
1277 			newbustraces = (TRACE **)emalloc(newtotal * (sizeof (TRACE *)),
1278 				sim_tool->cluster);
1279 			if (newbustraces == 0) return(0);
1280 			for(i=0; i<count; i++)
1281 				newbustraces[i] = sim_window_bustraces[i];
1282 			if (sim_window_bustracetotal > 0) efree((CHAR *)sim_window_bustraces);
1283 			sim_window_bustraces = newbustraces;
1284 			sim_window_bustracetotal = newtotal;
1285 		}
1286 		sim_window_bustraces[count++] = otr;
1287 		sim_window_bustraces[count] = 0;
1288 	}
1289 	if (count == 0)
1290 	{
1291 		nullbustraces[0] = 0;
1292 		return(nullbustraces);
1293 	}
1294 	return((INTBIG *)sim_window_bustraces);
1295 }
1296 
1297 /*
1298  * routine to return the frame number associated with trace "tri"
1299  */
sim_window_gettraceframe(INTBIG tri)1300 INTBIG sim_window_gettraceframe(INTBIG tri)
1301 {
1302 	REGISTER TRACE *tr;
1303 
1304 	tr = (TRACE *)tri;
1305 	if (tr == NOTRACE || tr == 0) return(0);
1306 	return(tr->frameno);
1307 }
1308 
1309 /*
1310  * routine to return the current frame number
1311  */
sim_window_getcurframe(void)1312 INTBIG sim_window_getcurframe(void)
1313 {
1314 	return(sim_window_highframe);
1315 }
1316 
1317 /*
1318  * routine to return the name of trace "tri".
1319  */
sim_window_gettracename(INTBIG tri)1320 CHAR *sim_window_gettracename(INTBIG tri)
1321 {
1322 	REGISTER TRACE *tr;
1323 
1324 	tr = (TRACE *)tri;
1325 	if (tr == NOTRACE || tr == 0) return(x_(""));
1326 	return(tr->origname);
1327 }
1328 
1329 /*
1330  * routine to return the "user" data associated with trace "tri"
1331  */
sim_window_gettracedata(INTBIG tri)1332 INTBIG sim_window_gettracedata(INTBIG tri)
1333 {
1334 	REGISTER TRACE *tr;
1335 
1336 	tr = (TRACE *)tri;
1337 	if (tr == NOTRACE || tr == 0) return(0);
1338 	return(tr->nodeptr);
1339 }
1340 
1341 /*
1342  * Routine to return the value of analog trace "tri" at time "time".
1343  * Interpolates the data to get the answer.
1344  */
sim_window_getanatracevalue(INTBIG tri,double time)1345 float sim_window_getanatracevalue(INTBIG tri, double time)
1346 {
1347 	REGISTER TRACE *tr;
1348 	REGISTER INTBIG j;
1349 	REGISTER float lastvalue, thisvalue, v;
1350 	REGISTER double lasttime, thistime;
1351 
1352 	tr = (TRACE *)tri;
1353 	if (tr == NOTRACE || tr == 0) return(0.0);
1354 
1355 	/* must be an analog trace */
1356 	if ((tr->flags&TRACETYPE) != TRACEISANALOG) return(0.0);
1357 
1358 	lastvalue = 0.0;
1359 	lasttime = 0.0;
1360 	for(j=0; j<tr->numsteps; j++)
1361 	{
1362 		thistime = tr->timearray[j];
1363 		thisvalue = tr->valuearray[j];
1364 		if (thistime == time) return(thisvalue);
1365 		if (time > thistime)
1366 		{
1367 			lasttime = thistime;
1368 			lastvalue = thisvalue;
1369 			continue;
1370 		}
1371 		if (j == 0) return(thisvalue);
1372 		v = (float)(lastvalue + (time-lasttime) * (thisvalue-lastvalue) / (thistime-lasttime));
1373 		return(v);
1374 	}
1375 
1376 	return(lastvalue);
1377 }
1378 
1379 /*
1380  * Routine to return the value of digital trace "tri" at time "time".
1381  * Sets the level (high/low/etc) in "level" and the strength in "strength".
1382  */
sim_window_getdigtracevalue(INTBIG tri,double time,INTBIG * level,INTBIG * strength)1383 void sim_window_getdigtracevalue(INTBIG tri, double time, INTBIG *level, INTBIG *strength)
1384 {
1385 	REGISTER TRACE *tr;
1386 	REGISTER INTBIG j;
1387 	REGISTER double thistime;
1388 
1389 	*level = *strength = 0;
1390 	tr = (TRACE *)tri;
1391 	if (tr == NOTRACE || tr == 0) return;
1392 
1393 	/* must be an analog trace */
1394 	if ((tr->flags&TRACETYPE) != TRACEISDIGITAL) return;
1395 
1396 	for(j=0; j<tr->numsteps; j++)
1397 	{
1398 		thistime = tr->timearray[j];
1399 		if (thistime > time) break;
1400 		*level = tr->statearray[j] >> 8;
1401 		*strength = tr->statearray[j] & 0377;
1402 	}
1403 }
1404 
1405 /*
1406  * Routine to return the value of bus trace "tri" at time "time".
1407  * Returns the value as a string.
1408  */
sim_window_getbustracevalue(INTBIG tri,double time)1409 CHAR *sim_window_getbustracevalue(INTBIG tri, double time)
1410 {
1411 	REGISTER TRACE *tr, *bustr;
1412 	REGISTER INTBIG j, sigcount;
1413 
1414 	tr = (TRACE *)tri;
1415 	if (tr == NOTRACE || tr == 0) return(x_(""));
1416 
1417 	/* must be an analog trace */
1418 	if ((tr->flags&TRACETYPE) != TRACEISBUS &&
1419 		(tr->flags&TRACETYPE) != TRACEISOPENBUS) return(x_(""));
1420 
1421 	sigcount = sim_window_ensurespace(tr);
1422 	for(bustr = sim_window_firstrace; bustr != NOTRACE; bustr = bustr->nexttrace)
1423 	{
1424 		if (bustr->buschannel != tr) continue;
1425 		for(j=0; j<bustr->numsteps; j++)
1426 			if (time < bustr->timearray[j]) break;
1427 		if (j > 0) j--;
1428 		sim_window_sigvalues[bustr->busindex] = bustr->statearray[j] >> 8;
1429 	}
1430 	return(sim_window_makewidevalue(sigcount, sim_window_sigvalues));
1431 }
1432 
1433 LISTINTBIG *sim_window_foundtraces = 0;
1434 
1435 /*
1436  * Routine to return the traces associated with name "name" (if it is a bus, there may be
1437  * multiple traces).  The number of traces is returned in "count" and the trace list is
1438  * returned by the routine.
1439  */
sim_window_findtrace(CHAR * name,INTBIG * count)1440 INTBIG *sim_window_findtrace(CHAR *name, INTBIG *count)
1441 {
1442 	REGISTER TRACE *tr;
1443 	REGISTER CHAR *pt;
1444 	CHAR **strings;
1445 	REGISTER INTBIG len, i;
1446 
1447 	if (sim_window_foundtraces == 0)
1448 		sim_window_foundtraces = newintlistobj(sim_tool->cluster);
1449 	clearintlistobj(sim_window_foundtraces);
1450 
1451 	/* look for this name without modifications */
1452 	sim_window_findthistrace(name);
1453 
1454 	/* look for bus names in the requested string */
1455 	for(pt = name; *pt != 0; pt++)
1456 		if (*pt == '[') break;
1457 	if (*pt == '[')
1458 	{
1459 		/* parse into individual signal names */
1460 		len = net_evalbusname(APBUS, name, &strings, NOARCINST, NONODEPROTO, 0);
1461 		for(i=0; i<len; i++)
1462 			sim_window_findthistrace(strings[i]);
1463 	} else
1464 	{
1465 		/* look for bus names that have no indexing */
1466 		len = estrlen(name);
1467 		for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1468 		{
1469 			if ((tr->flags&TRACETYPE) != TRACEISBUS &&
1470 				(tr->flags&TRACETYPE) != TRACEISOPENBUS) continue;
1471 			if (namesamen(tr->name, name, len) == 0 && tr->name[len] == '[')
1472 				addtointlistobj(sim_window_foundtraces, (INTBIG)tr, FALSE);
1473 		}
1474 	}
1475 	return(getintlistobj(sim_window_foundtraces, count));
1476 }
1477 
sim_window_findthistrace(CHAR * name)1478 void sim_window_findthistrace(CHAR *name)
1479 {
1480 	REGISTER TRACE *tr;
1481 	REGISTER INTBIG i, len;
1482 	REGISTER CHAR *tempname;
1483 	REGISTER void *infstr;
1484 
1485 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1486 	{
1487 		if (namesame(tr->name, name) == 0)
1488 		{
1489 			addtointlistobj(sim_window_foundtraces, (INTBIG)tr, FALSE);
1490 			if (tr->buschannel != NOTRACE)
1491 				addtointlistobj(sim_window_foundtraces, (INTBIG)tr->buschannel, TRUE);
1492 			return;
1493 		}
1494 	}
1495 
1496 	/* see if the name is found when considering the prefix */
1497 	if (sim_window_traceprefix != 0)
1498 	{
1499 		len = estrlen(sim_window_traceprefix);
1500 		for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1501 		{
1502 			if (namesamen(tr->name, sim_window_traceprefix, len) == 0 &&
1503 				namesame(&tr->name[len], name) == 0)
1504 			{
1505 				addtointlistobj(sim_window_foundtraces, (INTBIG)tr, FALSE);
1506 				if (tr->buschannel != NOTRACE)
1507 					addtointlistobj(sim_window_foundtraces, (INTBIG)tr->buschannel, TRUE);
1508 				return;
1509 			}
1510 		}
1511 	}
1512 
1513 	/* keywords get the letters "NV" added to the end */
1514 	infstr = initinfstr();
1515 	addstringtoinfstr(infstr, name);
1516 	addstringtoinfstr(infstr, x_("NV"));
1517 	tempname = returninfstr(infstr);
1518 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1519 	{
1520 		if (namesame(tr->name, tempname) == 0)
1521 		{
1522 			addtointlistobj(sim_window_foundtraces, (INTBIG)tr, FALSE);
1523 			return;
1524 		}
1525 	}
1526 
1527 	/* handle "v(" and "l(" prefixes of HSPICE (see also "dbtext.c:getcomplexnetworks()") */
1528 	len = estrlen(name);
1529 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1530 	{
1531 		if ((tr->name[0] == 'l' || tr->name[0] == 'v') && tr->name[1] == '(')
1532 		{
1533 			if (namesamen(&tr->name[2], name, len) == 0)
1534 			{
1535 				if (tr->name[len+2] == 0 || tr->name[len+2] == ')')
1536 				{
1537 					addtointlistobj(sim_window_foundtraces, (INTBIG)tr, FALSE);
1538 					return;
1539 				}
1540 			}
1541 		}
1542 	}
1543 
1544 	/* allow "_" in simulator text to match any punctuation in desired name */
1545 	len = estrlen(name);
1546 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1547 	{
1548 		for(i=0; ; i++)
1549 		{
1550 			if (tr->name[i] == 0 || tolower(name[i]) == 0) break;
1551 			if (tolower(tr->name[i]) == tolower(name[i])) continue;
1552 			if (tr->name[i] == '_' && ispunct(name[i])) continue;
1553 			break;
1554 		}
1555 		if (tr->name[i] == 0 && tolower(name[i]) == 0)
1556 		{
1557 			addtointlistobj(sim_window_foundtraces, (INTBIG)tr, FALSE);
1558 			return;
1559 		}
1560 	}
1561 }
1562 
sim_window_inittraceloop(void)1563 void sim_window_inittraceloop(void)
1564 {
1565 	sim_window_loop = sim_window_firstrace;
1566 }
1567 
sim_window_inittraceloop2(void)1568 void sim_window_inittraceloop2(void)
1569 {
1570 	sim_window_loop2 = sim_window_firstrace;
1571 }
1572 
sim_window_nexttraceloop(void)1573 INTBIG sim_window_nexttraceloop(void)
1574 {
1575 	REGISTER TRACE *tr;
1576 
1577 	tr = sim_window_loop;
1578 	if (tr == NOTRACE) return(0);
1579 	sim_window_loop = tr->nexttrace;
1580 	return((INTBIG)tr);
1581 }
1582 
sim_window_nexttraceloop2(void)1583 INTBIG sim_window_nexttraceloop2(void)
1584 {
1585 	REGISTER TRACE *tr;
1586 
1587 	tr = sim_window_loop2;
1588 	if (tr == NOTRACE) return(0);
1589 	sim_window_loop2 = tr->nexttrace;
1590 	return((INTBIG)tr);
1591 }
1592 
1593 /********************************* TRACE/FRAME HIGHLIGHTING *********************************/
1594 
1595 /*
1596  * Routine to initialize changes to the trace highlighting.  After calling this, any
1597  * trace whose highlighting changes should have the "TRACEHIGHCHANGED" bit set in its flags.
1598  */
sim_window_inithighlightchange(void)1599 void sim_window_inithighlightchange(void)
1600 {
1601 	REGISTER TRACE *tr;
1602 
1603 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1604 		tr->flags &= ~TRACEHIGHCHANGED;
1605 }
1606 
1607 /*
1608  * Routine to terminate changes to the trace highlighting.  Redisplays any frames
1609  * where the trace highlighting changed.
1610  */
sim_window_donehighlightchange(WINDOWPART * wavewin)1611 void sim_window_donehighlightchange(WINDOWPART *wavewin)
1612 {
1613 	REGISTER TRACE *tr, *otr;
1614 	REGISTER INTBIG highframe;
1615 
1616 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1617 	{
1618 		if ((tr->flags&TRACEHIGHCHANGED) == 0) continue;
1619 		sim_window_drawframe(tr->frameno, wavewin);
1620 		for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
1621 			if (otr->frameno == tr->frameno)
1622 				otr->flags &= ~TRACEHIGHCHANGED;
1623 	}
1624 
1625 	/* see if a single frame is highlighted */
1626 	highframe = -1;
1627 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1628 	{
1629 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
1630 		if ((tr->flags&TRACESELECTED) == 0) continue;
1631 //		if ((tr->flags&TRACETYPE) != TRACEISANALOG) continue;
1632 		if (highframe == -1) highframe = tr->frameno;
1633 		if (highframe != tr->frameno) highframe = -2;
1634 	}
1635 
1636 	if (highframe == -2) highframe = -1;
1637 	if (highframe != sim_window_highframe)
1638 	{
1639 		sim_window_setviewport(wavewin);
1640 
1641 		if (sim_window_highframe >= 0)
1642 			sim_window_showtracebar(wavewin, sim_window_highframe, 2);
1643 		sim_window_highframe = highframe;
1644 		if (sim_window_highframe >= 0)
1645 			sim_window_showtracebar(wavewin, sim_window_highframe, 1);
1646 	}
1647 }
1648 
1649 /*
1650  * Routine to highlight trace "tr" in window "wavewin".  If "on" is TRUE, highlight it,
1651  * otherwise remove highlighting.
1652  */
sim_window_highlightname(WINDOWPART * wavewin,TRACE * tr,BOOLEAN on)1653 void sim_window_highlightname(WINDOWPART *wavewin, TRACE *tr, BOOLEAN on)
1654 {
1655 	REGISTER INTBIG lx, hx, ly, hy, color, temp_trace_spacing, slot, y_min;
1656 
1657 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
1658 	slot = tr->frameno - sim_window_topframes;
1659 	if (slot < 0 || slot >= sim_window_visframes) return;
1660 	y_min = (sim_window_visframes - 1 - slot) * temp_trace_spacing + WAVEYSIGBOT;
1661 
1662 	/* highlight/unhighlight trace name */
1663 	ly = y_min + tr->nameoff+1;   hy = ly + sim_window_txthei;
1664 	lx = 0;                       hx = sim_window_wavexnameend;
1665 	sim_window_setmask(LAYERH);
1666 	if (on) color = HIGHLIT; else color = 0;
1667 	sim_window_setcolor(color);
1668 	sim_window_moveto(lx, ly);
1669 	sim_window_drawto(wavewin, hx, ly, 0);
1670 	sim_window_drawto(wavewin, hx, hy, 0);
1671 	sim_window_drawto(wavewin, lx, hy, 0);
1672 	sim_window_drawto(wavewin, lx, ly, 0);
1673 	sim_window_setmask(LAYERA);
1674 }
1675 
1676 /*
1677  * Routine to make sure the highlighted traces are visible (not scrolled away)
1678  */
sim_window_showhighlightedtraces(void)1679 void sim_window_showhighlightedtraces(void)
1680 {
1681 	REGISTER INTBIG slot;
1682 	REGISTER TRACE *tr;
1683 
1684 	if (sim_window_visframes == 0) return;
1685 	if (sim_window_highlightedtracecount == 0) return;
1686 	tr = sim_window_highlightedtraces[0];
1687 	slot = tr->frameno - sim_window_topframes;
1688 	if (slot >= 0 && slot < sim_window_visframes) return;
1689 
1690 	/* shift the scroll */
1691 	sim_window_topframes = tr->frameno - sim_window_visframes/2;
1692 	if (sim_window_topframes < 0) sim_window_topframes = 0;
1693 	sim_window_redraw();
1694 }
1695 
1696 /*
1697  * Routine to clear all highlighting in the waveform window.
1698  */
sim_window_cleartracehighlight(void)1699 void sim_window_cleartracehighlight(void)
1700 {
1701 	REGISTER WINDOWPART *wavewin;
1702 	REGISTER INTBIG i;
1703 	REGISTER TRACE *tr;
1704 
1705 	/* get the waveform window */
1706 	wavewin = sim_window_findwaveform();
1707 	if (wavewin == NOWINDOWPART) return;
1708 	sim_window_setviewport(wavewin);
1709 
1710 	/* initialize changes to highlighted traces */
1711 	sim_window_inithighlightchange();
1712 
1713 	/* clear all highlighting */
1714 	for(i=0; i<sim_window_highlightedtracecount; i++)
1715 	{
1716 		tr = sim_window_highlightedtraces[i];
1717 		tr->flags &= ~TRACESELECTED;
1718 		tr->flags |= TRACEHIGHCHANGED;
1719 		sim_window_highlightname(wavewin, tr, FALSE);
1720 	}
1721 	sim_window_highlightedtracecount = 0;
1722 
1723 	/* show changes to highlighted traces */
1724 	sim_window_donehighlightchange(wavewin);
1725 
1726 	sim_window_drawcursors(wavewin);
1727 }
1728 
1729 /*
1730  * routine that adds trace "tri" to the highlighted traces in the waveform window
1731  */
sim_window_addhighlighttrace(INTBIG tri)1732 void sim_window_addhighlighttrace(INTBIG tri)
1733 {
1734 	REGISTER TRACE *tr, **newtraces;
1735 	REGISTER WINDOWPART *wavewin;
1736 	REGISTER INTBIG newtotal, i;
1737 
1738 	tr = (TRACE *)tri;
1739 
1740 	/* get the waveform window */
1741 	wavewin = sim_window_findwaveform();
1742 	if (wavewin == NOWINDOWPART) return;
1743 	sim_window_setviewport(wavewin);
1744 
1745 	/* initialize changes to trace highlighting */
1746 	sim_window_inithighlightchange();
1747 
1748 	/* add this signal to highlighting */
1749 	if (sim_window_highlightedtracecount+1 >= sim_window_highlightedtracetotal)
1750 	{
1751 		newtotal = sim_window_highlightedtracetotal * 2;
1752 		if (newtotal == 0) newtotal = 2;
1753 		if (sim_window_highlightedtracecount+1 > newtotal)
1754 			newtotal = sim_window_highlightedtracecount+1;
1755 		newtraces = (TRACE **)emalloc(newtotal * (sizeof (TRACE *)), sim_tool->cluster);
1756 		if (newtraces == 0) return;
1757 		for(i=0; i<sim_window_highlightedtracecount; i++)
1758 			newtraces[i] = sim_window_highlightedtraces[i];
1759 		if (sim_window_highlightedtracetotal > 0) efree((CHAR *)sim_window_highlightedtraces);
1760 		sim_window_highlightedtraces = newtraces;
1761 		sim_window_highlightedtracetotal = newtotal;
1762 	}
1763 	sim_window_highlightedtraces[sim_window_highlightedtracecount++] = tr;
1764 	tr->flags |= (TRACESELECTED | TRACEHIGHCHANGED);
1765 	sim_window_highlightedtraces[sim_window_highlightedtracecount] = 0;
1766 	sim_window_highlightname(wavewin, tr, TRUE);
1767 
1768 	/* show highlighting */
1769 	sim_window_donehighlightchange(wavewin);
1770 	sim_window_drawcursors(wavewin);
1771 }
1772 
1773 /*
1774  * routine that removes trace "tri" from the highlighted traces in the waveform window
1775  */
sim_window_deletehighlighttrace(INTBIG tri)1776 void sim_window_deletehighlighttrace(INTBIG tri)
1777 {
1778 	REGISTER TRACE *tr;
1779 	REGISTER WINDOWPART *wavewin;
1780 	REGISTER INTBIG k, j, i;
1781 
1782 	tr = (TRACE *)tri;
1783 
1784 	/* get the waveform window */
1785 	wavewin = sim_window_findwaveform();
1786 	if (wavewin == NOWINDOWPART) return;
1787 	sim_window_setviewport(wavewin);
1788 
1789 	/* find this signal in the highlighting */
1790 	for(j=0; j<sim_window_highlightedtracecount; j++)
1791 		if (tr == sim_window_highlightedtraces[j]) break;
1792 	if (j < sim_window_highlightedtracecount)
1793 	{
1794 		/* erase highlighting */
1795 		sim_window_inithighlightchange();
1796 
1797 		/* remove the signal from the list */
1798 		k = 0;
1799 		for(i=0; i<sim_window_highlightedtracecount; i++)
1800 		{
1801 			if (i == j) continue;
1802 			sim_window_highlightedtraces[k++] = sim_window_highlightedtraces[i];
1803 		}
1804 		sim_window_highlightedtracecount = k;
1805 		tr->flags &= ~TRACESELECTED;
1806 		tr->flags |= TRACEHIGHCHANGED;
1807 		sim_window_highlightname(wavewin, tr, FALSE);
1808 
1809 		/* show highlighting */
1810 		sim_window_donehighlightchange(wavewin);
1811 	}
1812 	sim_window_drawcursors(wavewin);
1813 }
1814 
1815 /*
1816  * routine that returns the highlighted trace in the waveform window
1817  */
sim_window_gethighlighttrace(void)1818 INTBIG sim_window_gethighlighttrace(void)
1819 {
1820 	if (sim_window_highlightedtracecount == 0) return(0);
1821 	return((INTBIG)sim_window_highlightedtraces[0]);
1822 }
1823 
1824 /*
1825  * routine that returns a 0-terminated list of highlighted traces in the waveform window
1826  */
sim_window_gethighlighttraces(void)1827 INTBIG *sim_window_gethighlighttraces(void)
1828 {
1829 	static INTBIG nothing[1];
1830 
1831 	nothing[0] = 0;
1832 	if (sim_window_highlightedtracecount == 0) return(nothing);
1833 	return((INTBIG *)sim_window_highlightedtraces);
1834 }
1835 
1836 /*
1837  * Routine to update associated layout windows when the main cursor changes
1838  */
sim_window_updatelayoutwindow(void)1839 void sim_window_updatelayoutwindow(void)
1840 {
1841 	REGISTER TRACE *tr, *otr;
1842 	REGISTER NETWORK *net;
1843 	REGISTER ARCINST *ai;
1844 	REGISTER NODEINST *ni;
1845 	REGISTER PORTARCINST *pi;
1846 	REGISTER INTBIG fx, fy, tx, ty, i, x, y, count;
1847 	REGISTER NODEPROTO *simnt;
1848 	REGISTER VARIABLE *var;
1849 	REGISTER WINDOWPART *schemwin;
1850 	INTBIG texture, color, lx, hx, ly, hy;
1851 	static POLYGON *poly = NOPOLYGON;
1852 	XARRAY trans;
1853 
1854 	/* make sure there is a layout/schematic window being simulated */
1855 	schemwin = sim_window_findschematics();
1856 	if (schemwin == NOWINDOWPART) return;
1857 	simnt = schemwin->curnodeproto;
1858 
1859 	/* reset all values on networks */
1860 	for(net = simnt->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1861 		net->temp1 = net->temp2 = -1;
1862 
1863 	/* assign values from simulation window traces to networks */
1864 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
1865 	{
1866 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
1867 
1868 		/* can only handle digital waveforms right now */
1869 		if ((tr->flags&TRACETYPE) == TRACEISDIGITAL)
1870 		{
1871 			sim_window_putvalueontrace(tr, simnt);
1872 		} else if ((tr->flags&TRACETYPE) == TRACEISBUS || (tr->flags&TRACETYPE) == TRACEISOPENBUS)
1873 		{
1874 			for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
1875 			{
1876 				if (otr->buschannel != tr) continue;
1877 				sim_window_putvalueontrace(otr, simnt);
1878 			}
1879 		}
1880 	}
1881 
1882 	/* light up any simulation-probe objects */
1883 	for(ni = simnt->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1884 	{
1885 		if (ni->proto != gen_simprobeprim) continue;
1886 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1887 		{
1888 			ai = pi->conarcinst;
1889 			if (ai->network == NONETWORK) continue;
1890 			if (ai->network->temp1 != -1) break;
1891 		}
1892 		if (pi == NOPORTARCINST) continue;
1893 
1894 		sim_window_gethighlightcolor(ai->network->temp1, &texture, &color);
1895 		sim_window_desc.col = color;
1896 		var = gettrace(ni);
1897 		if (var != NOVARIABLE)
1898 		{
1899 			count = getlength(var) / 2;
1900 			(void)needstaticpolygon(&poly, count, sim_tool->cluster);
1901 			x = (ni->highx + ni->lowx) / 2;   y = (ni->highy + ni->lowy) / 2;
1902 			for(i=0; i<count; i++)
1903 			{
1904 				poly->xv[i] = applyxscale(schemwin, ((INTBIG *)var->addr)[i*2] + x - schemwin->screenlx) + schemwin->uselx;
1905 				poly->yv[i] = applyyscale(schemwin, ((INTBIG *)var->addr)[i*2+1] + y - schemwin->screenly) + schemwin->usely;
1906 			}
1907 			poly->count = count;
1908 			poly->style = FILLED;
1909 			makerot(ni, trans);
1910 			xformpoly(poly, trans);
1911 			clippoly(poly, schemwin->uselx, schemwin->usehx, schemwin->usely, schemwin->usehy);
1912 			if (poly->count > 1)
1913 			{
1914 				if (poly->count > 2)
1915 				{
1916 					/* always clockwise */
1917 					if (areapoly(poly) < 0.0) reversepoly(poly);
1918 					screendrawpolygon(schemwin, poly->xv, poly->yv, poly->count, &sim_window_desc);
1919 				} else screendrawline(schemwin, poly->xv[0], poly->yv[0], poly->xv[1], poly->yv[1],
1920 					&sim_window_desc, 0);
1921 			}
1922 			ai->network->temp2 = 0;
1923 		} else
1924 		{
1925 			lx = ni->geom->lowx;   hx = ni->geom->highx;
1926 			ly = ni->geom->lowy;   hy = ni->geom->highy;
1927 			if (!us_makescreen(&lx, &ly, &hx, &hy, schemwin))
1928 			{
1929 				screendrawbox(schemwin, lx, hx, ly, hy, &sim_window_desc);
1930 				ai->network->temp2 = 0;
1931 			}
1932 		}
1933 	}
1934 
1935 	/* redraw all arcs in the layout/schematic window */
1936 	sim_window_desc.bits = LAYERA;
1937 	for(ai = simnt->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1938 	{
1939 		net = ai->network;
1940 		if (net == NONETWORK) continue;
1941 		if (net->temp1 == -1 || net->temp2 != -1) continue;
1942 
1943 		/* get extent of arc */
1944 		fx = ai->end[0].xpos;   fy = ai->end[0].ypos;
1945 		tx = ai->end[1].xpos;   ty = ai->end[1].ypos;
1946 		if (ai->proto == sch_wirearc)
1947 		{
1948 			/* for schematic wires, ask technology about drawing so negating bubbles work */
1949 			(void)needstaticpolygon(&poly, 4, sim_tool->cluster);
1950 			(void)arcpolys(ai, NOWINDOWPART);
1951 			shapearcpoly(ai, 0, poly);
1952 			fx = poly->xv[0];   fy = poly->yv[0];
1953 			tx = poly->xv[1];   ty = poly->yv[1];
1954 		}
1955 
1956 		sim_window_gethighlightcolor(net->temp1, &texture, &color);
1957 
1958 		/* reset background arc if trace is textured */
1959 		if (texture != 0)
1960 		{
1961 			sim_window_desc.col = ALLOFF;
1962 			us_wanttodraw(fx, fy, tx, ty, schemwin, &sim_window_desc, 0);
1963 			if (texture < 0) texture = 0;
1964 		}
1965 		sim_window_desc.col = color;
1966 
1967 		/* draw the trace on the arc */
1968 		us_wanttodraw(fx, fy, tx, ty, schemwin, &sim_window_desc, texture);
1969 	}
1970 }
1971 
sim_window_gethighlightcolor(INTBIG state,INTBIG * texture,INTBIG * color)1972 void sim_window_gethighlightcolor(INTBIG state, INTBIG *texture, INTBIG *color)
1973 {
1974 	REGISTER INTBIG strength;
1975 
1976 	if ((sim_window_state&FULLSTATE) != 0)
1977 	{
1978 		/* 12-state display: determine trace texture */
1979 		strength = state & 0377;
1980 		if (strength == 0) *texture = -1; else
1981 			if (strength <= NODE_STRENGTH) *texture = 1; else
1982 				if (strength <= GATE_STRENGTH) *texture = 0; else
1983 					*texture = 2;
1984 
1985 		/* determine trace color */
1986 		switch (state >> 8)
1987 		{
1988 			case LOGIC_LOW:  *color = sim_colorlevellow;     break;
1989 			case LOGIC_X:    *color = sim_colorlevelundef;   break;
1990 			case LOGIC_HIGH: *color = sim_colorlevelhigh;    break;
1991 			case LOGIC_Z:    *color = sim_colorlevelzdef;    break;
1992 		}
1993 	} else
1994 	{
1995 		/* 2-state display */
1996 		*texture = 0;
1997 		if ((state >> 8) == LOGIC_HIGH) *color = sim_colorstrengthgate; else
1998 			*color = sim_colorstrengthoff;
1999 	}
2000 }
2001 
sim_window_putvalueontrace(TRACE * tr,NODEPROTO * simnt)2002 void sim_window_putvalueontrace(TRACE *tr, NODEPROTO *simnt)
2003 {
2004 	REGISTER NETWORK *net, **netlist;
2005 	REGISTER INTBIG j;
2006 
2007 	if (tr->statearray == 0) return;
2008 
2009 	/* set simulation value on the network in the associated layout/schematic window */
2010 	netlist = getcomplexnetworks(tr->name, simnt);
2011 	net = netlist[0];
2012 	if (net != NONETWORK && netlist[1] == NONETWORK)
2013 	{
2014 		/* find the proper data for the time of the main cursor */
2015 		for(j=1; j<tr->numsteps; j++)
2016 			if (sim_window_maincursor < tr->timearray[j]) break;
2017 		j--;
2018 		net->temp1 = tr->statearray[j];
2019 	}
2020 }
2021 
2022 /********************************* TIME AND CURSOR CONTROL *********************************/
2023 
2024 /*
2025  * routine to set the time for the "main" cursor in the simulation window
2026  */
sim_window_setmaincursor(double time)2027 void sim_window_setmaincursor(double time)
2028 {
2029 	REGISTER WINDOWPART *wavewin;
2030 
2031 	/* get the waveform window */
2032 	wavewin = sim_window_findwaveform();
2033 	if (wavewin == NOWINDOWPART) return;
2034 
2035 	sim_window_maincursor = time;
2036 	sim_window_updatelayoutwindow();
2037 	sim_window_drawcursors(wavewin);
2038 }
2039 
2040 /*
2041  * routine to return the time of the "main" cursor in the simulation window
2042  */
sim_window_getmaincursor(void)2043 double sim_window_getmaincursor(void)
2044 {
2045 	return(sim_window_maincursor);
2046 }
2047 
2048 /*
2049  * routine to set the time for the "extension" cursor in the simulation window
2050  */
sim_window_setextensioncursor(double time)2051 void sim_window_setextensioncursor(double time)
2052 {
2053 	REGISTER WINDOWPART *wavewin;
2054 
2055 	/* get the waveform window */
2056 	wavewin = sim_window_findwaveform();
2057 	if (wavewin == NOWINDOWPART) return;
2058 
2059 	sim_window_extensioncursor = time;
2060 	sim_window_drawcursors(wavewin);
2061 }
2062 
2063 /*
2064  * routine to return the time of the "extension" cursor in the simulation window
2065  */
sim_window_getextensioncursor(void)2066 double sim_window_getextensioncursor(void)
2067 {
2068 	return(sim_window_extensioncursor);
2069 }
2070 
2071 /*
2072  * routine to set the simulation trace "tri" to run from time "min" to time "max"
2073  */
sim_window_settimerange(INTBIG tri,double min,double max)2074 void sim_window_settimerange(INTBIG tri, double min, double max)
2075 {
2076 	REGISTER TRACE *tr, *otr;
2077 
2078 	tr = (TRACE *)tri;
2079 	for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
2080 	{
2081 		if (tr != 0 && otr->frameno != tr->frameno) continue;
2082 		otr->mintime = min;
2083 		otr->maxtime = max;
2084 	}
2085 }
2086 
2087 /*
2088  * routine to return the range of time displayed in the simulation window
2089  */
sim_window_gettimerange(INTBIG tri,double * min,double * max)2090 void sim_window_gettimerange(INTBIG tri, double *min, double *max)
2091 {
2092 	REGISTER TRACE *tr;
2093 
2094 	tr = (TRACE *)tri;
2095 	*min = tr->mintime;
2096 	*max = tr->maxtime;
2097 }
2098 
2099 /*
2100  * routine to return the average range of time displayed in the simulation window
2101  */
sim_window_getaveragetimerange(double * totmintime,double * totmaxtime)2102 void sim_window_getaveragetimerange(double *totmintime, double *totmaxtime)
2103 {
2104 	double mintime, maxtime;
2105 	REGISTER INTBIG tottraces, tr, j;
2106 
2107 	sim_window_inittraceloop();
2108 	*totmintime = *totmaxtime = 0.0;
2109 	tottraces = 0;
2110 	for(j=0; ; j++)
2111 	{
2112 		tr = sim_window_nexttraceloop();
2113 		if (tr == 0) break;
2114 		sim_window_gettimerange(tr, &mintime, &maxtime);
2115 		*totmintime += mintime;
2116 		*totmaxtime += maxtime;
2117 		tottraces++;
2118 	}
2119 	if (tottraces > 0)
2120 	{
2121 		*totmintime /= tottraces;
2122 		*totmaxtime /= tottraces;
2123 	}
2124 }
2125 
2126 /*
2127  * routine to return the range of time that is in the data
2128  */
sim_window_gettimeextents(double * min,double * max)2129 void sim_window_gettimeextents(double *min, double *max)
2130 {
2131 	REGISTER TRACE *tr;
2132 	double time;
2133 	REGISTER INTBIG j;
2134 
2135 	/* initially enclose the cursors */
2136 	*min = sim_window_maincursor;
2137 	*max = sim_window_extensioncursor;
2138 	if (*max < *min)
2139 	{
2140 		*min = sim_window_extensioncursor;
2141 		*max = sim_window_maincursor;
2142 	}
2143 
2144 	/* also enclose all of the data */
2145 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
2146 	{
2147 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
2148 		for(j=0; j<tr->numsteps; j++)
2149 		{
2150 			time = tr->timearray[j];
2151 			if (time < *min) *min = time;
2152 			if (time > *max) *max = time;
2153 		}
2154 	}
2155 	if (*min > 0.0) *min = 0.0;
2156 }
2157 
2158 /********************************* WINDOW METHODS *********************************/
2159 
sim_window_zoomdown(INTBIG x,INTBIG y)2160 BOOLEAN sim_window_zoomdown(INTBIG x, INTBIG y)
2161 {
2162 	REGISTER WINDOWPART *wavewin;
2163 
2164 	/* get the waveform window */
2165 	wavewin = sim_window_findwaveform();
2166 	if (wavewin == NOWINDOWPART) return(FALSE);
2167 
2168 	sim_window_drawareazoom(wavewin, FALSE, sim_window_zoominix, sim_window_zoominiy,
2169 		sim_window_zoomothx, sim_window_zoomothy);
2170 	sim_window_scaletowindow(wavewin, &x, &y);
2171 	sim_window_zoomothx = x;
2172 	sim_window_zoomothy = y;
2173 	sim_window_drawareazoom(wavewin, TRUE, sim_window_zoominix, sim_window_zoominiy,
2174 		sim_window_zoomothx, sim_window_zoomothy);
2175 	return(FALSE);
2176 }
2177 
sim_window_drawareazoom(WINDOWPART * w,BOOLEAN on,INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty)2178 void sim_window_drawareazoom(WINDOWPART *w, BOOLEAN on, INTBIG fx, INTBIG fy, INTBIG tx, INTBIG ty)
2179 {
2180 	sim_window_setmask(LAYERH);
2181 	if (on) sim_window_setcolor(HIGHLIT); else
2182 		sim_window_setcolor(ALLOFF);
2183 	sim_window_moveto(fx, fy);
2184 	sim_window_drawto(w, fx, ty, 0);
2185 	sim_window_drawto(w, tx, ty, 0);
2186 	sim_window_drawto(w, tx, fy, 0);
2187 	sim_window_drawto(w, fx, fy, 0);
2188 }
2189 
sim_window_eachwdown(INTBIG x,INTBIG y)2190 BOOLEAN sim_window_eachwdown(INTBIG x, INTBIG y)
2191 {
2192 	sim_window_eachcursordown(x, y, &sim_window_maincursor);
2193 	sim_window_updatelayoutwindow();
2194 	return(FALSE);
2195 }
2196 
sim_window_eachbdown(INTBIG x,INTBIG y)2197 BOOLEAN sim_window_eachbdown(INTBIG x, INTBIG y)
2198 {
2199 	sim_window_eachcursordown(x, y, &sim_window_extensioncursor);
2200 	return(FALSE);
2201 }
2202 
sim_window_eachcursordown(INTBIG x,INTBIG y,double * cursor)2203 void sim_window_eachcursordown(INTBIG x, INTBIG y, double *cursor)
2204 {
2205 	REGISTER WINDOWPART *wavewin;
2206 	REGISTER TRACE *tr, *trh;
2207 	double val, valh;
2208 	INTBIG frameno, yh;
2209 
2210 	/* get the waveform window */
2211 	wavewin = sim_window_findwaveform();
2212 	if (wavewin == NOWINDOWPART) return;
2213 
2214 	tr = (TRACE *)sim_window_firstrace;
2215 	if (tr == NOTRACE) return;
2216 	sim_window_scaletowindow(wavewin, &x, &y);
2217 	*cursor = sim_window_xpostotime(x);
2218 	if (*cursor < tr->mintime) *cursor = tr->mintime;
2219 	if (*cursor > tr->maxtime) *cursor = tr->maxtime;
2220 
2221 	/* check if mouse is near voltage threshold horizontal line */
2222 	yh = -1;
2223 	valh = 0.0;
2224 	frameno = sim_window_ypostoval(y, &val);
2225 	if (frameno >= 0 && sim_window_vdd != 0)
2226 	{
2227 		INTBIG ymax = 10;
2228 		int i;
2229 		for (i = 0; i < PERCENTSIZE; i++)
2230 		{
2231 			double v = sim_window_vdd * sim_window_percent[i];
2232 			INTBIG yp = sim_window_valtoypos(frameno, v);
2233 			if (yp >= 0 && labs(yp - y) < ymax)
2234 			{
2235 				ymax = labs(yp - y);
2236 				yh = yp;
2237 				valh = v;
2238 			}
2239 		}
2240 	}
2241 
2242 	/* check if mouse is near crosspoint of some trace */
2243 	trh = NOTRACE;
2244 	if (yh >= 0)
2245 	{
2246 		double th = 0;
2247 		for (tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
2248 		{
2249 			double t = *cursor;
2250 
2251 			if (tr->frameno != frameno) continue;
2252 			if (sim_window_findcross(tr, valh, &t) && (trh == NOTRACE || fabs(t - *cursor) < fabs(th - *cursor)))
2253 			{
2254 				th = t;
2255 				trh = tr;
2256 			}
2257 		}
2258 
2259 		/* align cursor time to crosspoint */
2260 		if (trh != NOTRACE)
2261 		{
2262 			if (labs(sim_window_timetoxpos(*cursor) - sim_window_timetoxpos(th)) <= 10)
2263 				*cursor = th;
2264 			else
2265 				trh = NOTRACE;
2266 		}
2267 	}
2268 	sim_window_drawcursors(wavewin);
2269 	if (trh != NOTRACE)
2270 	{
2271 		/* highlight crossing trace and threshold line */
2272 		sim_window_setmask(LAYERH);
2273 		sim_window_setcolor(HIGHLIT);
2274 		sim_window_moveto(sim_window_wavexsigstart, yh);
2275 		sim_window_drawto(wavewin, WAVEXSIGEND, yh, 1);
2276 		sim_window_plottrace(trh, wavewin, 2, 0, 0);
2277 	}
2278 }
2279 
sim_window_hthumbtrackingcallback(INTBIG delta)2280 void sim_window_hthumbtrackingcallback(INTBIG delta)
2281 {
2282 	REGISTER INTBIG thumbarea, j, tr;
2283 	double mintime, maxtime, range, truerange;
2284 
2285 	if (delta == 0) return;
2286 	sim_waveforminiththumbpos += delta;
2287 	thumbarea = sim_waveformwindow->usehx - sim_waveformwindow->uselx - DISPLAYSLIDERSIZE*2;
2288 	sim_window_gettimeextents(&mintime, &maxtime);
2289 	range = maxtime * 2.0;
2290 	range = sim_waveformhrange;
2291 	sim_window_inittraceloop();
2292 	for(j=0; ; j++)
2293 	{
2294 		tr = sim_window_nexttraceloop();
2295 		if (tr == 0) break;
2296 		sim_window_gettimerange(tr, &mintime, &maxtime);
2297 		truerange = maxtime - mintime;
2298 
2299 		mintime = (sim_waveforminiththumbpos -
2300 			(sim_waveformwindow->uselx+DISPLAYSLIDERSIZE+2)) * range / thumbarea;
2301 		if (mintime < 0.0) mintime = 0.0;
2302 		maxtime = mintime + truerange;
2303 
2304 		sim_window_settimerange(tr, mintime, maxtime);
2305 	}
2306 	if (sim_window_format == ALS) (void)simals_initialize_simulator(TRUE); else
2307 		sim_window_redraw();
2308 }
2309 
sim_window_vthumbtrackingcallback(INTBIG delta)2310 void sim_window_vthumbtrackingcallback(INTBIG delta)
2311 {
2312 	REGISTER INTBIG thumbarea, point;
2313 
2314 	sim_window_deltasofar += delta;
2315 	thumbarea = sim_waveformwindow->usehy - sim_waveformwindow->usely - DISPLAYSLIDERSIZE*2;
2316 	point = (sim_waveformwindow->usehy - DISPLAYSLIDERSIZE -
2317 		(sim_window_initialthumb + sim_window_deltasofar)) *
2318 			sim_window_lines / thumbarea;
2319 	if (point < 0) point = 0;
2320 	if (point > sim_window_lines-sim_window_visframes)
2321 		point = sim_window_lines-sim_window_visframes;
2322 	if (point == sim_window_topframes) return;
2323 	sim_window_topframes = point;
2324 	sim_window_redisphandler(sim_waveformwindow);
2325 }
2326 
2327 /*
2328  * Routine for drawing highlight around dragged trace name.
2329  */
sim_window_drawtracedrag(WINDOWPART * wavewin,BOOLEAN on)2330 void sim_window_drawtracedrag(WINDOWPART *wavewin, BOOLEAN on)
2331 {
2332 	INTBIG y_pos, temp_trace_spacing, frameno, lx, hx, ly, hy;
2333 
2334 	/* compute positions */
2335 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
2336 	frameno = sim_window_tracedragtr->frameno - sim_window_topframes;
2337 	if (frameno < 0 || frameno >= sim_window_visframes) return;
2338 	y_pos = (sim_window_visframes - 1 - frameno) * temp_trace_spacing +
2339 		WAVEYSIGBOT + sim_window_tracedragyoff;
2340 	ly = y_pos + sim_window_tracedragtr->nameoff + 1;
2341 	hy = ly + sim_window_txthei;
2342 	lx = 0;
2343 	hx = sim_window_wavexnameend;
2344 
2345 	sim_window_setmask(LAYERH);
2346 	if (on) sim_window_setcolor(HIGHLIT); else
2347 		sim_window_setcolor(ALLOFF);
2348 	sim_window_moveto(lx, ly);
2349 	sim_window_drawto(wavewin, hx, ly, 0);
2350 	sim_window_drawto(wavewin, hx, hy, 0);
2351 	sim_window_drawto(wavewin, lx, hy, 0);
2352 	sim_window_drawto(wavewin, lx, ly, 0);
2353 }
2354 
2355 /*
2356  * Routine for tracking the drag of signal names in the waveform window.
2357  */
sim_window_eachdown(INTBIG x,INTBIG y)2358 BOOLEAN sim_window_eachdown(INTBIG x, INTBIG y)
2359 {
2360 	REGISTER WINDOWPART *wavewin;
2361 
2362 	/* get the waveform window */
2363 	wavewin = sim_window_findwaveform();
2364 	if (wavewin == NOWINDOWPART) return(FALSE);
2365 
2366 	sim_window_scaletowindow(wavewin, &x, &y);
2367 	sim_window_drawtracedrag(wavewin, FALSE);
2368 	sim_window_tracedragyoff = y - sim_window_initialy;
2369 	sim_window_drawtracedrag(wavewin, TRUE);
2370 	return(FALSE);
2371 }
2372 
2373 /*
2374  * Routine for drawing highlight around selected trace names.
2375  */
sim_window_drawtraceselect(WINDOWPART * wavewin,INTBIG y1,INTBIG y2,BOOLEAN on)2376 void sim_window_drawtraceselect(WINDOWPART *wavewin, INTBIG y1, INTBIG y2, BOOLEAN on)
2377 {
2378 	INTBIG x, ly, hy;
2379 
2380 	/* compute positions */
2381 	if (y1 == y2) return;
2382 	ly = mini(y1, y2);
2383 	hy = maxi(y1, y2);
2384 	x = sim_window_initialx;
2385 
2386 	sim_window_setmask(LAYERH);
2387 	if (!on) sim_window_setcolor(ALLOFF); else
2388 		sim_window_setcolor(HIGHLIT);
2389 	sim_window_moveto(x, ly);
2390 	sim_window_drawto(wavewin, x, hy, 0);
2391 }
2392 
2393 /*
2394  * Routine for tracking the selection of signal names in the waveform window.
2395  */
sim_window_seleachdown(INTBIG x,INTBIG y)2396 BOOLEAN sim_window_seleachdown(INTBIG x, INTBIG y)
2397 {
2398 	REGISTER WINDOWPART *wavewin;
2399 	INTBIG lowy, highy, ind, i, redo, ypos, temp_trace_spacing;
2400 	REGISTER TRACE *tr;
2401 
2402 	/* get the waveform window */
2403 	wavewin = sim_window_findwaveform();
2404 	if (wavewin == NOWINDOWPART) return(FALSE);
2405 
2406 	sim_window_scaletowindow(wavewin, &x, &y);
2407 
2408 	/* undraw former selection line */
2409 	sim_window_drawtraceselect(wavewin, sim_window_currentdragy, sim_window_initialy, FALSE);
2410 	if (y < sim_window_initialy)
2411 	{
2412 		lowy = y;    highy = sim_window_initialy;
2413 	} else
2414 	{
2415 		lowy = sim_window_initialy;    highy = y;
2416 	}
2417 
2418 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
2419 		tr->flags &= ~TRACEMARK;
2420 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
2421 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
2422 	{
2423 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
2424 		ind = tr->frameno - sim_window_topframes;
2425 		ypos = (sim_window_visframes - 1 - ind) * temp_trace_spacing + WAVEYSIGBOT + tr->nameoff;
2426 		if (ypos > highy || ypos + sim_window_txthei < lowy) continue;
2427 		tr->flags |= TRACEMARK;
2428 	}
2429 
2430 	/* see if what is highlighted has changed */
2431 	redo = 0;
2432 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
2433 	{
2434 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
2435 		for(i=0; i<sim_window_highlightedtracecount; i++)
2436 			if (sim_window_highlightedtraces[i] == tr) break;
2437 		if (i < sim_window_highlightedtracecount)
2438 		{
2439 			/* this signal was highlighted */
2440 			if ((tr->flags&TRACEMARK) == 0) redo++;
2441 		} else
2442 		{
2443 			/* this signal was not highlighted */
2444 			if ((tr->flags&TRACEMARK) != 0) redo++;
2445 		}
2446 	}
2447 
2448 	/* redo highlighting if it changed */
2449 	if (redo != 0)
2450 	{
2451 		sim_window_cleartracehighlight();
2452 		for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
2453 			if ((tr->flags&TRACEMARK) != 0) sim_window_addhighlighttrace((INTBIG)tr);
2454 	}
2455 
2456 	/* show what is dragged out */
2457 	sim_window_currentdragy = y;
2458 	sim_window_drawtraceselect(wavewin, sim_window_currentdragy, sim_window_initialy, TRUE);
2459 	return(FALSE);
2460 }
2461 
2462 /*
2463  * Routine called when vertical slider parts are clicked.
2464  */
sim_window_verticalslider(INTBIG x,INTBIG y)2465 BOOLEAN sim_window_verticalslider(INTBIG x, INTBIG y)
2466 {
2467 	INTBIG newtopframe;
2468 
2469 	if (x >= sim_waveformwindow->uselx) return(FALSE);
2470 	switch (sim_waveformsliderpart)
2471 	{
2472 		case 0: /* down arrow clicked */
2473 			if (y > sim_waveformwindow->usely + DISPLAYSLIDERSIZE) return(FALSE);
2474 			if (y < sim_waveformwindow->usely) return(FALSE);
2475 			if (sim_window_topframes + sim_window_visframes < sim_window_lines)
2476 			{
2477 				sim_window_topframes++;
2478 				sim_window_redisphandler(sim_waveformwindow);
2479 			}
2480 			break;
2481 		case 1: /* below thumb */
2482 			if (y > sim_waveformwindow->thumbly) return(FALSE);
2483 			newtopframe = sim_window_topframes + sim_window_visframes - 1;
2484 			if (newtopframe + sim_window_visframes > sim_window_lines)
2485 				newtopframe = sim_window_lines - sim_window_visframes;
2486 			if (sim_window_topframes == newtopframe) break;
2487 			sim_window_topframes = newtopframe;
2488 			sim_window_redisphandler(sim_waveformwindow);
2489 			break;
2490 		case 2: /* on thumb (not handled here) */
2491 			break;
2492 		case 3: /* above thumb */
2493 			if (y < sim_waveformwindow->thumbhy) return(FALSE);
2494 			if (sim_window_topframes == 0) return(FALSE);
2495 			sim_window_topframes -= sim_window_visframes - 1;
2496 			if (sim_window_topframes < 0) sim_window_topframes = 0;
2497 			sim_window_redisphandler(sim_waveformwindow);
2498 			break;
2499 		case 4: /* up arrow clicked */
2500 			if (y < sim_waveformwindow->usehy - DISPLAYSLIDERSIZE) return(FALSE);
2501 			if (sim_window_topframes > 0)
2502 			{
2503 				sim_window_topframes--;
2504 				sim_window_redisphandler(sim_waveformwindow);
2505 			}
2506 			break;
2507 	}
2508 	return(FALSE);
2509 }
2510 
2511 /*
2512  * Routine called when horizontal slider parts are clicked.
2513  */
sim_window_horizontalslider(INTBIG x,INTBIG y)2514 BOOLEAN sim_window_horizontalslider(INTBIG x, INTBIG y)
2515 {
2516 	double range;
2517 	REGISTER TRACE *tr;
2518 
2519 	tr = (TRACE *)sim_window_firstrace;
2520 	if (tr == NOTRACE) return(FALSE);
2521 	if (y >= sim_waveformwindow->usely) return(FALSE);
2522 	switch (sim_waveformsliderpart)
2523 	{
2524 		case 0: /* left arrow clicked */
2525 			if (x > sim_waveformwindow->uselx + DISPLAYSLIDERSIZE*11) return(FALSE);
2526 			if (tr->mintime <= 0.0) break;
2527 			range = tr->maxtime - tr->mintime;
2528 			tr->mintime -= range/DISPLAYSMALLSHIFT;
2529 			tr->maxtime -= range/DISPLAYSMALLSHIFT;
2530 			if (tr->mintime < 0.0)
2531 			{
2532 				tr->maxtime -= tr->mintime;
2533 				tr->mintime = 0.0;
2534 			}
2535 			if (sim_window_format == ALS) (void)simals_initialize_simulator(TRUE); else
2536 				sim_window_redraw();
2537 			break;
2538 		case 1: /* left of thumb */
2539 			if (x > sim_waveformwindow->thumblx) return(FALSE);
2540 			if (tr->mintime <= 0.0) break;
2541 			range = tr->maxtime - tr->mintime;
2542 			tr->mintime -= range/DISPLAYLARGESHIFT;
2543 			tr->maxtime -= range/DISPLAYLARGESHIFT;
2544 			if (tr->mintime < 0.0)
2545 			{
2546 				tr->maxtime -= tr->mintime;
2547 				tr->mintime = 0.0;
2548 			}
2549 			if (sim_window_format == ALS) (void)simals_initialize_simulator(TRUE); else
2550 				sim_window_redraw();
2551 			break;
2552 		case 2: /* on thumb (not handled here) */
2553 			break;
2554 		case 3: /* right of thumb */
2555 			if (x < sim_waveformwindow->thumbhx) return(FALSE);
2556 			range = tr->maxtime - tr->mintime;
2557 			tr->mintime += range/DISPLAYLARGESHIFT;
2558 			tr->maxtime += range/DISPLAYLARGESHIFT;
2559 			if (sim_window_format == ALS) (void)simals_initialize_simulator(TRUE); else
2560 				sim_window_redraw();
2561 			break;
2562 		case 4: /* right arrow clicked */
2563 			if (x < sim_waveformwindow->usehx - DISPLAYSLIDERSIZE) return(FALSE);
2564 			range = tr->maxtime - tr->mintime;
2565 			tr->mintime += range/DISPLAYSMALLSHIFT;
2566 			tr->maxtime += range/DISPLAYSMALLSHIFT;
2567 			if (sim_window_format == ALS) (void)simals_initialize_simulator(TRUE); else
2568 				sim_window_redraw();
2569 			break;
2570 	}
2571 	return(FALSE);
2572 }
2573 
sim_window_buttonhandler(WINDOWPART * w,INTBIG button,INTBIG inx,INTBIG iny)2574 void sim_window_buttonhandler(WINDOWPART *w, INTBIG button, INTBIG inx, INTBIG iny)
2575 {
2576 	INTBIG x, y, xpos, ypos, j, ind, temp_trace_spacing, traceframesmoved, important;
2577 	REGISTER INTBIG lx, hx, ly, hy, ind1, ind2, y_min, y_max, frame;
2578 	CHAR *par[2], *butname;
2579 	double range, highdisp, lowdisp, mintime, maxtime, endtime;
2580 	float flow, fhigh;
2581 	BOOLEAN areaselect;
2582 	REGISTER TRACE *tr, *otr, *otrprev, *nexttr, *addloc,
2583 		*buschain, *endbuschain;
2584 
2585 	/* changes to the mouse-wheel are handled by the user interface */
2586 	if (wheelbutton(button))
2587 	{
2588 		us_buttonhandler(w, button, inx, iny);
2589 		return;
2590 	}
2591 	ttynewcommand();
2592 
2593 	/* if in distance-measurement mode, track measurement */
2594 	if ((us_state&MEASURINGDISTANCE) != 0)
2595 	{
2596 		if ((us_state&MEASURINGDISTANCEINI) != 0)
2597 		{
2598 			us_state &= ~MEASURINGDISTANCEINI;
2599 			sim_window_distanceinit(w);
2600 		}
2601 		trackcursor(FALSE, us_ignoreup, us_nullvoid, sim_window_distancedown,
2602 			us_stoponchar, sim_window_distanceup, TRACKDRAGGING);
2603 		return;
2604 	}
2605 
2606 	/* hit in slider on left */
2607 	if (inx < w->uselx)
2608 	{
2609 		if (iny < w->usely)
2610 		{
2611 			/* toggle the cell explorer */
2612 			par[0] = "explore";
2613 			us_window(1, par);
2614 			return;
2615 		}
2616 		if (iny <= w->usely + DISPLAYSLIDERSIZE)
2617 		{
2618 			/* hit in bottom arrow: go down 1 (may repeat) */
2619 			sim_waveformwindow = w;
2620 			sim_waveformsliderpart = 0;
2621 			trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_verticalslider, us_nullchar,
2622 				us_nullvoid, TRACKNORMAL);
2623 			return;
2624 		}
2625 		if (iny < w->thumbly)
2626 		{
2627 			/* hit below thumb: go down lots (may repeat) */
2628 			sim_waveformwindow = w;
2629 			sim_waveformsliderpart = 1;
2630 			trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_verticalslider, us_nullchar,
2631 				us_nullvoid, TRACKNORMAL);
2632 			return;
2633 		}
2634 		if (iny <= w->thumbhy)
2635 		{
2636 			/* hit on thumb: track thumb motion */
2637 			sim_waveformwindow = w;
2638 			sim_window_deltasofar = 0;
2639 			sim_window_initialthumb = w->thumbhy;
2640 			us_vthumbbegin(iny, w, w->uselx-DISPLAYSLIDERSIZE, w->usely, w->usehy,
2641 				TRUE, sim_window_vthumbtrackingcallback);
2642 			trackcursor(FALSE, us_nullup, us_nullvoid, us_vthumbdown, us_nullchar,
2643 				us_vthumbdone, TRACKNORMAL);
2644 			return;
2645 		}
2646 		if (iny < w->usehy - DISPLAYSLIDERSIZE)
2647 		{
2648 			/* hit above thumb: go up lots (may repeat) */
2649 			sim_waveformwindow = w;
2650 			sim_waveformsliderpart = 3;
2651 			trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_verticalslider, us_nullchar,
2652 				us_nullvoid, TRACKNORMAL);
2653 			return;
2654 		}
2655 
2656 		/* hit in up arrow: go up 1 (may repeat) */
2657 		sim_waveformwindow = w;
2658 		sim_waveformsliderpart = 4;
2659 		trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_verticalslider, us_nullchar,
2660 			us_nullvoid, TRACKNORMAL);
2661 		return;
2662 	}
2663 
2664 	/* hit in slider on bottom */
2665 	if (iny < w->usely)
2666 	{
2667 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*1)
2668 		{
2669 			/* hit in blank button */
2670 			return;
2671 		}
2672 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*2)
2673 		{
2674 			/* hit in rewind button */
2675 			sim_window_playing = VCRSTOP;
2676 			sim_window_maincursor = 0.0;
2677 			sim_window_drawcursors(w);
2678 			sim_window_updatelayoutwindow();
2679 			return;
2680 		}
2681 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*3)
2682 		{
2683 			/* hit in play backwards button */
2684 			sim_window_playing = VCRPLAYBACKWARD;
2685 			sim_window_lastadvance = ticktime();
2686 			return;
2687 		}
2688 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*4)
2689 		{
2690 			/* hit in stop button */
2691 			sim_window_playing = VCRSTOP;
2692 			return;
2693 		}
2694 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*5)
2695 		{
2696 			/* hit in play button */
2697 			sim_window_playing = VCRPLAYFOREWARD;
2698 			sim_window_lastadvance = ticktime();
2699 			return;
2700 		}
2701 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*6)
2702 		{
2703 			/* hit in advance to end button */
2704 			endtime = 0.0;
2705 			for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
2706 				if (tr->maxtime > endtime) endtime = tr->maxtime;
2707 			sim_window_playing = VCRSTOP;
2708 			sim_window_maincursor = endtime;
2709 			sim_window_drawcursors(w);
2710 			sim_window_updatelayoutwindow();
2711 			return;
2712 		}
2713 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*7)
2714 		{
2715 			/* hit in blank button */
2716 			return;
2717 		}
2718 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*8)
2719 		{
2720 			/* hit in faster button */
2721 			j = sim_window_advancespeed / 4;
2722 			if (j <= 0) j = 1;
2723 			sim_window_advancespeed += j;
2724 			return;
2725 		}
2726 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*9)
2727 		{
2728 			/* hit in slower button */
2729 			j = sim_window_advancespeed / 4;
2730 			if (j <= 0) j = 1;
2731 			sim_window_advancespeed -= j;
2732 			if (sim_window_advancespeed <= 0) sim_window_advancespeed = 1;
2733 			return;
2734 		}
2735 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*10)
2736 		{
2737 			/* hit in blank button */
2738 			return;
2739 		}
2740 		if (inx <= w->uselx + DISPLAYSLIDERSIZE*11)
2741 		{
2742 			/* hit in left arrow: small shift down in time (may repeat) */
2743 			sim_waveformwindow = w;
2744 			sim_waveformsliderpart = 0;
2745 			trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_horizontalslider, us_nullchar,
2746 				us_nullvoid, TRACKNORMAL);
2747 			return;
2748 		}
2749 		if (inx < w->thumblx)
2750 		{
2751 			/* hit to left of thumb: large shift down in time (may repeat) */
2752 			sim_waveformwindow = w;
2753 			sim_waveformsliderpart = 1;
2754 			trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_horizontalslider, us_nullchar,
2755 				us_nullvoid, TRACKNORMAL);
2756 			return;
2757 		}
2758 		if (inx <= w->thumbhx)
2759 		{
2760 			/* hit on thumb: track thumb motion */
2761 			sim_waveformwindow = w;
2762 			sim_window_gettimeextents(&mintime, &maxtime);
2763 			sim_waveformhrange = maxtime * 2.0;
2764 			sim_window_getaveragetimerange(&mintime, &maxtime);
2765 			if (maxtime*2.0 > sim_waveformhrange) sim_waveformhrange = maxtime*2.0;
2766 
2767 			sim_waveforminiththumbpos = w->thumblx;
2768 			us_hthumbbegin(inx, w, w->usely, w->uselx, w->usehx,
2769 				sim_window_hthumbtrackingcallback);
2770 			trackcursor(FALSE, us_nullup, us_nullvoid, us_hthumbdown, us_nullchar,
2771 				us_hthumbdone, TRACKNORMAL);
2772 			return;
2773 		}
2774 		if (inx < w->usehx - DISPLAYSLIDERSIZE)
2775 		{
2776 			/* hit to right of thumb: large shift up in time (may repeat) */
2777 			sim_waveformwindow = w;
2778 			sim_waveformsliderpart = 3;
2779 			trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_horizontalslider, us_nullchar,
2780 				us_nullvoid, TRACKNORMAL);
2781 			return;
2782 		}
2783 
2784 		/* hit in right arrow: small shift up in time (may repeat) */
2785 		sim_waveformwindow = w;
2786 		sim_waveformsliderpart = 4;
2787 		trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_horizontalslider, us_nullchar,
2788 			us_nullvoid, TRACKNORMAL);
2789 		return;
2790 	}
2791 
2792 	sim_window_setviewport(w);
2793 	x = inx;   y = iny;
2794 	sim_window_scaletowindow(w, &x, &y);
2795 
2796 	/* see if the divider between names and signals was hit */
2797 	if (abs(x - sim_window_wavexbar) <= 3 && y >= 560)
2798 	{
2799 		sim_window_dividerinit(w);
2800 		sim_window_draghighoff = TRUE;
2801 		for(j=0; j<sim_window_highlightedtracecount; j++)
2802 			sim_window_highlightname(w, sim_window_highlightedtraces[j], FALSE);
2803 		trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_dividerdown, us_nullchar,
2804 			sim_window_dividerdone, TRACKNORMAL);
2805 		if (sim_window_draghighoff)
2806 		{
2807 			for(j=0; j<sim_window_highlightedtracecount; j++)
2808 				sim_window_highlightname(w, sim_window_highlightedtraces[j], TRUE);
2809 		}
2810 		return;
2811 	}
2812 
2813 	/* see if a signal name was hit */
2814 	if (x <= sim_window_wavexnameend)
2815 	{
2816 		temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
2817 		ind = sim_window_visframes - 1 - (y - WAVEYSIGBOT) / temp_trace_spacing;
2818 		for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
2819 		{
2820 			if ((tr->flags&TRACENOTDRAWN) == 0)
2821 			{
2822 				if (tr->frameno == ind + sim_window_topframes)
2823 				{
2824 					ypos = (sim_window_visframes - 1 - ind) * temp_trace_spacing + WAVEYSIGBOT + tr->nameoff;
2825 					if (y >= ypos && y <= ypos + sim_window_txthei) break;
2826 				}
2827 			}
2828 		}
2829 		if (tr == NOTRACE)
2830 		{
2831 			/* not over any signal: drag out selection of signal names */
2832 			sim_window_initialx = x;
2833 			sim_window_initialy = y;
2834 			sim_window_currentdragy = y;
2835 			trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_seleachdown,
2836 				us_nullchar, us_nullvoid, TRACKDRAGGING);
2837 			sim_window_drawtraceselect(w, sim_window_currentdragy, sim_window_initialy, FALSE);
2838 			return;
2839 		}
2840 
2841 		/* see if it is a double-click on a bus name */
2842 		if (doublebutton(button))
2843 		{
2844 			if ((tr->flags&TRACETYPE) == TRACEISBUS)
2845 			{
2846 				/* closed bus: open it up */
2847 				j = 0;
2848 				for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
2849 				{
2850 					if (otr->buschannel != tr) continue;
2851 					otr->flags &= ~TRACENOTDRAWN;
2852 					otr->frameno = --j;
2853 				}
2854 				tr->flags = (tr->flags & ~TRACETYPE) | TRACEISOPENBUS;
2855 
2856 				/* renumber lines in the display */
2857 				sim_window_renumberlines();
2858 
2859 				/* adjust the number of visible lines */
2860 				sim_window_setviewport(w);
2861 
2862 				sim_window_redraw();
2863 				return;
2864 			}
2865 			if ((tr->flags&TRACETYPE) == TRACEISOPENBUS)
2866 			{
2867 				/* opened bus: close it up */
2868 				for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
2869 					if (otr->buschannel == tr) otr->flags |= TRACENOTDRAWN;
2870 				tr->flags = (tr->flags & ~TRACETYPE) | TRACEISBUS;
2871 
2872 				/* renumber lines in the display */
2873 				sim_window_renumberlines();
2874 
2875 				sim_window_redraw();
2876 				return;
2877 			}
2878 			return;
2879 		}
2880 
2881 		/* see if the signal shares a line with any others */
2882 		for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
2883 		{
2884 			if ((otr->flags&TRACENOTDRAWN) != 0) continue;
2885 			if (otr != tr && otr->frameno == tr->frameno) break;
2886 		}
2887 		if (otr == NOTRACE)
2888 		{
2889 			/* not a shared signal: handle dragging of the name */
2890 			sim_window_tracedragyoff = 0;
2891 			sim_window_initialy = y;
2892 			sim_window_tracedragtr = tr;
2893 			sim_window_drawtracedrag(w, TRUE);
2894 			trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_eachdown,
2895 				us_nullchar, us_nullvoid, TRACKDRAGGING);
2896 			sim_window_drawtracedrag(w, FALSE);
2897 
2898 			/* see if the signal name was dragged to a new location */
2899 			traceframesmoved = sim_window_tracedragyoff / temp_trace_spacing;
2900 			if (traceframesmoved != 0)
2901 			{
2902 				/* erase highlighting */
2903 				sim_window_cleartracehighlight();
2904 
2905 				/* find which signal name it was dragged to */
2906 				otrprev = NOTRACE;
2907 				for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
2908 				{
2909 					if ((otr->flags&TRACENOTDRAWN) == 0)
2910 					{
2911 						if (otr->frameno == tr->frameno - traceframesmoved) break;
2912 					}
2913 					if (otr != tr) otrprev = otr;
2914 				}
2915 				if (otr != NOTRACE)
2916 				{
2917 					/* pull out the selected signal */
2918 					sim_window_removetrace(tr);
2919 
2920 					/* insert signal in new location */
2921 					if (tr->frameno < otr->frameno)
2922 					{
2923 						sim_window_addtrace(tr, otr);
2924 					} else
2925 					{
2926 						sim_window_addtrace(tr, otrprev);
2927 					}
2928 
2929 					/* move any bus signals inside of this */
2930 					buschain = endbuschain = NOTRACE;
2931 					for(otr = sim_window_firstrace; otr != NOTRACE; otr = nexttr)
2932 					{
2933 						nexttr = otr->nexttrace;
2934 						if (otr->buschannel == tr)
2935 						{
2936 							sim_window_removetrace(otr);
2937 							if (endbuschain == NOTRACE) endbuschain = buschain = otr; else
2938 							{
2939 								endbuschain->nexttrace = otr;
2940 								endbuschain = otr;
2941 							}
2942 							otr->nexttrace = NOTRACE;
2943 						}
2944 					}
2945 					addloc = tr;
2946 					for(otr = buschain; otr != NOTRACE; otr = nexttr)
2947 					{
2948 						nexttr = otr->nexttrace;
2949 						sim_window_addtrace(otr, addloc);
2950 						addloc = otr;
2951 					}
2952 
2953 					/* renumber lines in the display */
2954 					sim_window_renumberlines();
2955 
2956 					/* redisplay window */
2957 					sim_window_redraw();
2958 
2959 					/* save the new configuration */
2960 					sim_window_savesignalorder();
2961 				}
2962 				sim_window_addhighlighttrace((INTBIG)tr);
2963 				par[0] = x_("highlight");
2964 				telltool(net_tool, 1, par);
2965 				return;
2966 			}
2967 		}
2968 
2969 		/* highlight the selected signal */
2970 		if (!shiftbutton(button))
2971 		{
2972 			/* shift not held: simply highlight this signal */
2973 			sim_window_cleartracehighlight();
2974 			sim_window_addhighlighttrace((INTBIG)tr);
2975 		} else
2976 		{
2977 			/* complement state of this signal */
2978 			for(j=0; j<sim_window_highlightedtracecount; j++)
2979 				if (tr == sim_window_highlightedtraces[j]) break;
2980 			if (j < sim_window_highlightedtracecount)
2981 			{
2982 				/* signal already highlighted: unhighlight it */
2983 				sim_window_deletehighlighttrace((INTBIG)tr);
2984 			} else
2985 			{
2986 				/* signal new: add to highlight */
2987 				sim_window_addhighlighttrace((INTBIG)tr);
2988 			}
2989 
2990 		}
2991 		par[0] = x_("highlight");
2992 		telltool(net_tool, 1, par);
2993 		return;
2994 	}
2995 
2996 	/* see if an area-select was requested */
2997 	butname = buttonname(button, &important);
2998 	areaselect = FALSE;
2999 #ifdef WIN32
3000 	if (namesame(butname, x_("SARIGHT")) == 0) areaselect = TRUE;
3001 #endif
3002 #ifdef MACOS
3003 	if (namesame(butname, x_("SMOButton")) == 0) areaselect = TRUE;
3004 #endif
3005 #ifdef ONUNIX
3006 	if (namesame(butname, x_("SMRIGHT")) == 0) areaselect = TRUE;
3007 #endif
3008 	if (areaselect)
3009 	{
3010 		/* select an area of the waveform window */
3011 		sim_window_zoominix = sim_window_zoomothx = x;
3012 		sim_window_zoominiy = sim_window_zoomothy = y;
3013 		sim_window_drawareazoom(w, TRUE, sim_window_zoominix, sim_window_zoominiy,
3014 			sim_window_zoomothx, sim_window_zoomothy);
3015 		trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_zoomdown,
3016 			us_nullchar, us_nullvoid, TRACKDRAGGING);
3017 		sim_window_drawareazoom(w, FALSE, sim_window_zoominix, sim_window_zoominiy,
3018 			sim_window_zoomothx, sim_window_zoomothy);
3019 
3020 		/* find the area */
3021 		lx = mini(sim_window_zoominix, sim_window_zoomothx);
3022 		hx = maxi(sim_window_zoominix, sim_window_zoomothx);
3023 		ly = mini(sim_window_zoominiy, sim_window_zoomothy);
3024 		hy = maxi(sim_window_zoominiy, sim_window_zoomothy);
3025 		lowdisp = sim_window_xpostotime(lx);
3026 		highdisp = sim_window_xpostotime(hx);
3027 		range = highdisp - lowdisp;
3028 
3029 		/* zoom into it horizontally */
3030 		if (sim_window_maincursor < lowdisp || sim_window_maincursor > highdisp)
3031 			sim_window_setmaincursor(lowdisp);
3032 		if (sim_window_extensioncursor < lowdisp || sim_window_extensioncursor > highdisp)
3033 			sim_window_setextensioncursor(highdisp);
3034 		sim_window_settimerange(0, lowdisp-range/15.0f, highdisp+range/15.0f);
3035 
3036 		/* zoom vertically as well */
3037 		temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
3038 		ind1 = sim_window_visframes - 1 - (ly - WAVEYSIGBOT) / temp_trace_spacing;
3039 		ind2 = sim_window_visframes - 1 - (hy - WAVEYSIGBOT) / temp_trace_spacing;
3040 		y_min = (sim_window_visframes - 1 - ind1) * temp_trace_spacing + WAVEYSIGBOT;
3041 		y_max = y_min + temp_trace_spacing - WAVEYSIGGAP;
3042 		if (ind1 == ind2)
3043 		{
3044 			/* dragging happend all in one frame, see if it is analog */
3045 			for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
3046 			{
3047 				if ((tr->flags&TRACENOTDRAWN) != 0) continue;
3048 				if (tr->frameno != ind1 + sim_window_topframes) continue;
3049 				if ((tr->flags & TRACETYPE) == TRACEISANALOG) break;
3050 			}
3051 			if (tr != NOTRACE)
3052 			{
3053 				/* invert the display computation to get real units from screen coordinates */
3054 				frame = ind1 + sim_window_topframes;
3055 				flow = ((ly-y_min) / (float)(y_max - y_min)) * sim_window_get_extanarange(frame) + sim_window_get_botval(frame);
3056 				fhigh = ((hy-y_min) / (float)(y_max - y_min)) * sim_window_get_extanarange(frame) + sim_window_get_botval(frame);
3057 				range = fhigh - flow;
3058 				sim_window_set_analow(frame, flow-(float)range/15.0f);
3059 				sim_window_set_anahigh(frame, fhigh+(float)range/15.0f);
3060 			}
3061 		}
3062 		sim_window_redisphandler(w);
3063 		return;
3064 	}
3065 
3066 	/* see if a cursor was hit */
3067 	xpos = sim_window_timetoxpos(sim_window_maincursor);
3068 	if (abs(x-xpos) < 10 && y < 560)
3069 	{
3070 		/* main cursor hit */
3071 		trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_eachwdown,
3072 			us_nullchar, us_nullvoid, TRACKDRAGGING);
3073 		return;
3074 	}
3075 	xpos = sim_window_timetoxpos(sim_window_extensioncursor);
3076 	if (abs(x-xpos) < 10 && y < 560)
3077 	{
3078 		/* extension cursor hit */
3079 		trackcursor(FALSE, us_nullup, us_nullvoid, sim_window_eachbdown,
3080 			us_nullchar, us_nullvoid, TRACKDRAGGING);
3081 		return;
3082 	}
3083 
3084 	/* see if the line of a signal was hit */
3085 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
3086 	{
3087 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
3088 		if (sim_window_plottrace(tr, w, 1, x, y)) break;
3089 	}
3090 	if (tr != NOTRACE)
3091 	{
3092 		/* highlight the selected signal */
3093 		if (!shiftbutton(button))
3094 		{
3095 			/* shift not held: simply highlight this signal */
3096 			sim_window_cleartracehighlight();
3097 			sim_window_addhighlighttrace((INTBIG)tr);
3098 		} else
3099 		{
3100 			/* complement state of this signal */
3101 			for(j=0; j<sim_window_highlightedtracecount; j++)
3102 				if (tr == sim_window_highlightedtraces[j]) break;
3103 			if (j < sim_window_highlightedtracecount)
3104 			{
3105 				/* signal already highlighted: unhighlight it */
3106 				sim_window_deletehighlighttrace((INTBIG)tr);
3107 			} else
3108 			{
3109 				/* signal new: add to highlight */
3110 				sim_window_addhighlighttrace((INTBIG)tr);
3111 			}
3112 
3113 		}
3114 		par[0] = x_("highlight");
3115 		telltool(net_tool, 1, par);
3116 	} else
3117 	{
3118 		sim_window_cleartracehighlight();
3119 	}
3120 }
3121 
3122 /*
3123  * Routine called when VCR is playing.  Advances time if appropriate.
3124  */
sim_window_advancetime(void)3125 void sim_window_advancetime(void)
3126 {
3127 	REGISTER UINTBIG curtime;
3128 	double dtime;
3129 	REGISTER TRACE *tr;
3130 	REGISTER WINDOWPART *wavewin;
3131 
3132 	if (sim_window_playing == VCRSTOP) return;
3133 
3134 	/* see if there is a waveform window */
3135 	wavewin = sim_window_findwaveform();
3136 	if (wavewin == NOWINDOWPART) return;
3137 
3138 	/* see if it is time to advance the VCR */
3139 	curtime = ticktime();
3140 	if (curtime - sim_window_lastadvance < 5) return;
3141 	sim_window_lastadvance = curtime;
3142 
3143 	/* determine how much the time changes */
3144 	tr = sim_window_firstrace;
3145 	if (tr == NOTRACE) return;
3146 	dtime = sim_window_advancespeed * (tr->maxtime-tr->mintime) / (WAVEXSIGEND-sim_window_wavexsigstart);
3147 
3148 	if (sim_window_playing == VCRPLAYFOREWARD)
3149 	{
3150 		/* advance time forward */
3151 		sim_window_maincursor += dtime;
3152 	} else
3153 	{
3154 		/* advance time backward */
3155 		sim_window_maincursor -= dtime;
3156 		if (sim_window_maincursor < 0.0) sim_window_maincursor = 0.0;
3157 	}
3158 	sim_window_drawcursors(wavewin);
3159 	sim_window_updatelayoutwindow();
3160 }
3161 
3162 /*
3163  * Routine to initialize the display of measurements.
3164  */
sim_window_distanceinit(WINDOWPART * w)3165 void sim_window_distanceinit(WINDOWPART *w)
3166 {
3167 	sim_window_measureframe = -1;
3168 	sim_waveformwindow = w;
3169 }
3170 
3171 /*
3172  * Routine called each time the cursor advances during measurement.
3173  */
sim_window_distancedown(INTBIG x,INTBIG y)3174 BOOLEAN sim_window_distancedown(INTBIG x, INTBIG y)
3175 {
3176 	REGISTER INTBIG frame, y_min, y_max, slot, dragx, dragy, temp_trace_spacing;
3177 	INTBIG i1, i2;
3178 	double xval, yval, position;
3179 	float mintime, maxtime;
3180 	static CHAR distancemessage[200];
3181 
3182 	/* initialize polygon */
3183 	(void)needstaticpolygon(&sim_window_dragpoly, 4, sim_tool->cluster);
3184 	sim_window_dragpoly->desc = &sim_window_desc;
3185 	sim_window_desc.bits = LAYERH;
3186 
3187 	/* determine coordinates of this measurement */
3188 	sim_window_scaletowindow(sim_waveformwindow, &x, &y);
3189 	frame = sim_window_ypostoval(y, &yval);
3190 	xval = sim_window_xpostotime(x);
3191 
3192 	/* convert coordinates back to screen */
3193 	dragx = sim_window_timetoxpos(xval);
3194 	slot = frame - sim_window_topframes;
3195 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
3196 	y_min = (sim_window_visframes - 1 - slot) * temp_trace_spacing + WAVEYSIGBOT;
3197 	y_max = y_min + temp_trace_spacing - WAVEYSIGGAP;
3198 	position = (double)(y_max - y_min);
3199 	position *= (yval - sim_window_get_botval(frame)) / sim_window_get_extanarange(frame);
3200 	dragy = (INTBIG)position + y_min;
3201 
3202 	if (sim_window_measureframe < 0)
3203 	{
3204 		sim_window_firstmeasurex = dragx;   sim_window_firstmeasurey = dragy;
3205 		sim_window_firstmeasuretime = xval;
3206 		sim_window_firstmeasureyval = yval;
3207 		sim_window_measureframe = frame;
3208 	} else
3209 	{
3210 		/* if it didn't actually move, go no further */
3211 		if (dragx == sim_window_lastmeasurex && dragy == sim_window_lastmeasurey) return(FALSE);
3212 
3213 		/* if it changed frames, go no further */
3214 		if (sim_window_measureframe != frame) return(FALSE);
3215 
3216 		/* undraw the distance */
3217 		sim_window_desc.col = 0;
3218 		sim_window_drawdistance();
3219 	}
3220 	sim_window_lastmeasurex = dragx;   sim_window_lastmeasurey = dragy;
3221 
3222 	/* draw the new measurement */
3223 	sim_window_desc.col = HIGHLIT;
3224 	TDCLEAR(sim_window_dragpoly->textdescript);
3225 	TDSETSIZE(sim_window_dragpoly->textdescript, TXTSETPOINTS(12));
3226 	sim_window_dragpoly->tech = el_curtech;
3227 
3228 	mintime = sim_window_mintime;
3229 	maxtime = sim_window_maxtime;
3230 	(void)sim_window_sensible_value(&maxtime, &mintime, &i1, &i2, 5);
3231 	(void)esnprintf(distancemessage, 200, x_("dX=%s dY=%g"),
3232 		sim_windowconvertengineeringnotation2(xval - sim_window_firstmeasuretime, i2),
3233 			yval - sim_window_firstmeasureyval);
3234 	sim_window_dragpoly->string = distancemessage;
3235 	sim_window_drawdistance();
3236 	sim_window_measureframe = 1;
3237 	return(FALSE);
3238 }
3239 
3240 /*
3241  * Routine to display the current measurement information.
3242  */
sim_window_drawdistance(void)3243 void sim_window_drawdistance(void)
3244 {
3245 	INTBIG fx, fy, tx, ty;
3246 
3247 	sim_window_dragpoly->count = 1;
3248 	sim_window_dragpoly->style = TEXTBOTLEFT;
3249 	fx = sim_window_firstmeasurex;   fy = sim_window_firstmeasurey;
3250 	tx = sim_window_lastmeasurex;    ty = sim_window_lastmeasurey;
3251 	if (!clipline(&fx, &fy, &tx, &ty, sim_waveformwindow->screenlx, sim_waveformwindow->screenhx,
3252 		sim_waveformwindow->screenly, sim_waveformwindow->screenhy))
3253 	{
3254 		sim_window_dragpoly->xv[0] = (fx+tx) / 2;
3255 		sim_window_dragpoly->yv[0] = (fy+ty) / 2;
3256 		us_showpoly(sim_window_dragpoly, sim_waveformwindow);
3257 	}
3258 
3259 	/* draw the line */
3260 	sim_window_dragpoly->xv[0] = sim_window_firstmeasurex;
3261 	sim_window_dragpoly->yv[0] = sim_window_firstmeasurey;
3262 	sim_window_dragpoly->xv[1] = sim_window_lastmeasurex;
3263 	sim_window_dragpoly->yv[1] = sim_window_lastmeasurey;
3264 	sim_window_dragpoly->count = 2;
3265 	sim_window_dragpoly->style = OPENED;
3266 	us_showpoly(sim_window_dragpoly, sim_waveformwindow);
3267 
3268 	/* draw crosses at the end */
3269 	sim_window_dragpoly->xv[0] = sim_window_firstmeasurex;
3270 	sim_window_dragpoly->yv[0] = sim_window_firstmeasurey;
3271 	sim_window_dragpoly->count = 1;
3272 	sim_window_dragpoly->style = CROSS;
3273 	us_showpoly(sim_window_dragpoly, sim_waveformwindow);
3274 	sim_window_dragpoly->xv[0] = sim_window_lastmeasurex;
3275 	sim_window_dragpoly->yv[0] = sim_window_lastmeasurey;
3276 	us_showpoly(sim_window_dragpoly, sim_waveformwindow);
3277 }
3278 
3279 /*
3280  * Routine called when the button is released during measurement.
3281  */
sim_window_distanceup(void)3282 void sim_window_distanceup(void)
3283 {
3284 	if (sim_window_measureframe >= 0)
3285 	{
3286 		/* leave the results in the messages window */
3287 		ttyputmsg(x_("%s"), sim_window_dragpoly->string);
3288 	}
3289 }
3290 
3291 /*
3292  * Routine to initialize the dragging of the divider between the signal names and the waveforms.
3293  */
sim_window_dividerinit(WINDOWPART * w)3294 void sim_window_dividerinit(WINDOWPART *w)
3295 {
3296 	sim_waveformwindow = w;
3297 	sim_window_dragshown = FALSE;
3298 }
3299 
3300 /*
3301  * Routine called whenever the mouse moves during dragging of the divider between the signal
3302  * names and the waveforms.
3303  */
sim_window_dividerdown(INTBIG x,INTBIG y)3304 BOOLEAN sim_window_dividerdown(INTBIG x, INTBIG y)
3305 {
3306 	INTBIG dummyx, lowy, highy;
3307 	Q_UNUSED( y );
3308 
3309 	dummyx = 0;
3310 	lowy = 31;
3311 	highy = WAVEYTEXTTOP;
3312 	sim_window_mapcoord(sim_waveformwindow, &dummyx, &lowy);
3313 	sim_window_mapcoord(sim_waveformwindow, &dummyx, &highy);
3314 	if (sim_window_dragshown)
3315 	{
3316 		/* if it didn't actually move, go no further */
3317 		if (x == sim_window_draglastx) return(FALSE);
3318 
3319 		/* undraw the line */
3320 		sim_window_desc.bits = LAYERH;
3321 		sim_window_desc.col = ALLOFF;
3322 		screendrawline(sim_waveformwindow, sim_window_draglastx, lowy,
3323 			sim_window_draglastx, highy, &sim_window_desc, 0);
3324 	}
3325 
3326 	sim_window_draglastx = x;
3327 	if (sim_window_draglastx >= sim_waveformwindow->usehx)
3328 		sim_window_draglastx = sim_waveformwindow->usehx-1;
3329 	if (sim_window_draglastx < sim_waveformwindow->uselx)
3330 		sim_window_draglastx = sim_waveformwindow->uselx;
3331 
3332 	/* draw the outline */
3333 	sim_window_desc.bits = LAYERH;
3334 	sim_window_desc.col = HIGHLIT;
3335 	screendrawline(sim_waveformwindow, sim_window_draglastx, lowy,
3336 		sim_window_draglastx, highy, &sim_window_desc, 0);
3337 
3338 	sim_window_dragshown = TRUE;
3339 	return(FALSE);
3340 }
3341 
3342 /*
3343  * Routine called when the mouse is released after dragging of the divider between the signal
3344  * names and the waveforms.
3345  */
sim_window_dividerdone(void)3346 void sim_window_dividerdone(void)
3347 {
3348 	REGISTER INTBIG newbar;
3349 	INTBIG dummyx, lowy, highy;
3350 
3351 	if (sim_window_dragshown)
3352 	{
3353 		/* undraw the outline */
3354 		sim_window_desc.bits = LAYERH;
3355 		sim_window_desc.col = ALLOFF;
3356 
3357 		dummyx = 0;
3358 		lowy = 31;
3359 		highy = 560;
3360 		sim_window_mapcoord(sim_waveformwindow, &dummyx, &lowy);
3361 		sim_window_mapcoord(sim_waveformwindow, &dummyx, &highy);
3362 		screendrawline(sim_waveformwindow, sim_window_draglastx, lowy,
3363 			sim_window_draglastx, highy, &sim_window_desc, 0);
3364 
3365 		/* compute new bar position and redraw */
3366 		newbar = muldiv(sim_window_draglastx - sim_waveformwindow->uselx,
3367 			sim_waveformwindow->screenhx - sim_waveformwindow->screenlx,
3368 				sim_waveformwindow->usehx - sim_waveformwindow->uselx) +
3369 					sim_waveformwindow->screenlx;
3370 		if (newbar != sim_window_wavexbar && newbar > 20 && newbar < WAVEXSIGEND-10)
3371 		{
3372 			sim_window_wavexbar = newbar;
3373 			sim_window_wavexsigstart = newbar+1;
3374 			sim_window_wavexnameend = newbar-1;
3375 			sim_window_wavexnameendana = newbar-13;
3376 			sim_window_redisphandler(sim_waveformwindow);
3377 			sim_window_draghighoff = FALSE;
3378 		}
3379 	}
3380 }
3381 
sim_window_termhandler(WINDOWPART * w)3382 void sim_window_termhandler(WINDOWPART *w)
3383 {
3384 	REGISTER WINDOWPART *schemwin;
3385 	REGISTER WINDOWPART *ww;
3386 	Q_UNUSED( w );
3387 
3388 	/* see if there is another simulation window (because this one split) */
3389 	for(ww = el_topwindowpart; ww != NOWINDOWPART; ww = ww->nextwindowpart)
3390 	{
3391 		if (ww == w) continue;
3392 		if ((ww->state&WINDOWTYPE) == WAVEFORMWINDOW) break;
3393 	}
3394 	if (ww != NOWINDOWPART) return;
3395 
3396 	/* disable simulation control in schematics/layout window */
3397 	schemwin = sim_window_findschematics();
3398 	if (schemwin == NOWINDOWPART) return;
3399 
3400 	startobjectchange((INTBIG)schemwin, VWINDOWPART);
3401 	(void)setval((INTBIG)schemwin, VWINDOWPART, x_("state"), schemwin->state &
3402 		~WINDOWSIMMODE, VINTEGER);
3403 	(void)setval((INTBIG)schemwin, VWINDOWPART, x_("charhandler"),
3404 		(INTBIG)DEFAULTCHARHANDLER, VADDRESS);
3405 	endobjectchange((INTBIG)schemwin, VWINDOWPART);
3406 }
3407 
3408 static INTBIG sim_rewinddots[] = {
3409 	1,9, 1,8, 1,7, 1,6, 1,5, 1,4, 1,3, 1,2, 1,1,
3410 	2,5,
3411 	3,4, 3,5, 3,6,
3412 	4,4, 4,5, 4,6,
3413 	5,3, 5,4, 5,5, 5,6, 5,7,
3414 	6,3, 6,4, 6,5, 6,6, 6,7,
3415 	7,2, 7,3, 7,4, 7,5, 7,6, 7,7, 7,8,
3416 	8,2, 8,3, 8,4, 8,5, 8,6, 8,7, 8,8,
3417 	9,1, 9,2, 9,3, 9,4, 9,5, 9,6, 9,7, 9,8, 9,9,
3418 	-1,-1};
3419 static INTBIG sim_playbackwardsdots[] = {
3420 	1,5,
3421 	2,5,
3422 	3,4, 3,5, 3,6,
3423 	4,4, 4,5, 4,6,
3424 	5,3, 5,4, 5,5, 5,6, 5,7,
3425 	6,3, 6,4, 6,5, 6,6, 6,7,
3426 	7,2, 7,3, 7,4, 7,5, 7,6, 7,7, 7,8,
3427 	8,2, 8,3, 8,4, 8,5, 8,6, 8,7, 8,8,
3428 	9,1, 9,2, 9,3, 9,4, 9,5, 9,6, 9,7, 9,8, 9,9,
3429 	-1,-1};
3430 static INTBIG sim_stopdots[] = {
3431 	2,2, 2,3, 2,4, 2,5, 2,6, 2,7, 2,8,
3432 	3,2, 3,3, 3,4, 3,5, 3,6, 3,7, 3,8,
3433 	4,2, 4,3, 4,4, 4,5, 4,6, 4,7, 4,8,
3434 	5,2, 5,3, 5,4, 5,5, 5,6, 5,7, 5,8,
3435 	6,2, 6,3, 6,4, 6,5, 6,6, 6,7, 6,8,
3436 	7,2, 7,3, 7,4, 7,5, 7,6, 7,7, 7,8,
3437 	8,2, 8,3, 8,4, 8,5, 8,6, 8,7, 8,8,
3438 	-1,-1};
3439 static INTBIG sim_playforwarddots[] = {
3440 	1,1, 1,2, 1,3, 1,4, 1,5, 1,6, 1,7, 1,8, 1,9,
3441 	2,2, 2,3, 2,4, 2,5, 2,6, 2,7, 2,8,
3442 	3,2, 3,3, 3,4, 3,5, 3,6, 3,7, 3,8,
3443 	4,3, 4,4, 4,5, 4,6, 4,7,
3444 	5,3, 5,4, 5,5, 5,6, 5,7,
3445 	6,4, 6,5, 6,6,
3446 	7,4, 7,5, 7,6,
3447 	8,5,
3448 	9,5,
3449 	-1,-1};
3450 static INTBIG sim_fastforwarddots[] = {
3451 	1,1, 1,2, 1,3, 1,4, 1,5, 1,6, 1,7, 1,8, 1,9,
3452 	2,2, 2,3, 2,4, 2,5, 2,6, 2,7, 2,8,
3453 	3,2, 3,3, 3,4, 3,5, 3,6, 3,7, 3,8,
3454 	4,3, 4,4, 4,5, 4,6, 4,7,
3455 	5,3, 5,4, 5,5, 5,6, 5,7,
3456 	6,4, 6,5, 6,6,
3457 	7,4, 7,5, 7,6,
3458 	8,5,
3459 	9,1, 9,2, 9,3, 9,4, 9,5, 9,6, 9,7, 9,8, 9,9,
3460 	-1,-1};
3461 static INTBIG sim_fasterdots[] = {
3462 	2,7,
3463 	3,7, 3,8,
3464 	4,1, 4,2, 4,3, 4,4, 4,5, 4,6, 4,7, 4,8, 4,9,
3465 	5,7, 5,8,
3466 	6,7,
3467 	7,1, 7,2, 7,3, 7,4, 7,5,
3468 	8,3, 8,5,
3469 	9,5,
3470 	-1,-1};
3471 static INTBIG sim_slowerdots[] = {
3472 	2,3,
3473 	3,2, 3,3,
3474 	4,1, 4,2, 4,3, 4,4, 4,5, 4,6, 4,7, 4,8, 4,9,
3475 	5,2, 5,3,
3476 	6,3,
3477 	7,5, 7,7, 7,8, 7,9,
3478 	8,5, 8,7, 8,9,
3479 	9,5, 9,6, 9,7, 9,9,
3480 	-1,-1};
3481 
3482 /*
3483  * This procedure redraws the display, allowing for resize.
3484  */
sim_window_redisphandler(WINDOWPART * w)3485 void sim_window_redisphandler(WINDOWPART *w)
3486 {
3487 	INTBIG lx, hx, ly, hy;
3488 	UINTBIG descript[TEXTDESCRIPTSIZE];
3489 	double range;
3490 	REGISTER INTBIG thumbtop, thumbarea, thumbsize, extraroom;
3491 	REGISTER TRACE *tr;
3492 	REGISTER CHAR *simname;
3493 	REGISTER void *infstr;
3494 
3495 	sim_window_setviewport(w);
3496 
3497 	/* clear the window */
3498 	sim_window_desc.bits = LAYERA;
3499 	sim_window_desc.col = ALLOFF;
3500 	w->uselx -= DISPLAYSLIDERSIZE;
3501 	w->usely -= DISPLAYSLIDERSIZE;
3502 	lx = w->uselx;   hx = w->usehx;
3503 	ly = w->usely;   hy = w->usehy;
3504 	screendrawbox(w, lx, hx, ly, hy, &sim_window_desc);
3505 
3506 	/* draw vertical slider on the left */
3507 	us_drawverticalslider(w, lx-2, ly+DISPLAYSLIDERSIZE, hy, TRUE);
3508 	if (sim_window_lines > 0)
3509 	{
3510 		thumbsize = sim_window_visframes * 100 / sim_window_lines;
3511 		if (thumbsize >= 100) thumbsize = 100;
3512 		if (thumbsize == 100 && sim_window_topframes == 0)
3513 		{
3514 			w->thumbly = 0;   w->thumbhy = -1;
3515 		} else
3516 		{
3517 			thumbtop = sim_window_topframes * 100 / sim_window_lines;
3518 			thumbarea = w->usehy - w->usely - DISPLAYSLIDERSIZE*2;
3519 
3520 			w->thumbhy = w->usehy - DISPLAYSLIDERSIZE - thumbarea * thumbtop / 100;
3521 			w->thumbly = w->thumbhy - thumbarea * thumbsize / 100;
3522 			if (w->thumbhy > w->usehy-DISPLAYSLIDERSIZE-2) w->thumbhy = w->usehy-DISPLAYSLIDERSIZE-2;
3523 			if (w->thumbly < w->usely+DISPLAYSLIDERSIZE*2+2) w->thumbly = w->usely+DISPLAYSLIDERSIZE*2+2;
3524 		}
3525 		us_drawverticalsliderthumb(w, lx-2, ly+DISPLAYSLIDERSIZE, hy, w->thumbly, w->thumbhy);
3526 	}
3527 
3528 	/* draw horizontal slider on the bottom */
3529 	tr = (TRACE *)sim_window_firstrace;
3530 	if (tr != NOTRACE)
3531 	{
3532 		extraroom = DISPLAYSLIDERSIZE * 10;
3533 		us_drawhorizontalslider(w, ly+DISPLAYSLIDERSIZE, lx+DISPLAYSLIDERSIZE+extraroom, hx, 0);
3534 		thumbarea = w->usehx - w->uselx - DISPLAYSLIDERSIZE*2 - extraroom;
3535 		if (tr->mintime <= 0.0)
3536 		{
3537 			w->thumblx = w->uselx+extraroom+DISPLAYSLIDERSIZE*2+2;
3538 			w->thumbhx = w->thumblx + thumbarea/2;
3539 		} else
3540 		{
3541 			range = tr->maxtime * 2.0;
3542 			w->thumblx = (INTBIG)(w->uselx+extraroom+DISPLAYSLIDERSIZE*2+2 + tr->mintime/range*thumbarea);
3543 			w->thumbhx = (INTBIG)(w->uselx+extraroom+DISPLAYSLIDERSIZE*2+2 + tr->maxtime/range*thumbarea);
3544 			if (w->thumbhx < w->thumblx + MINTHUMB) w->thumbhx = w->thumblx + MINTHUMB;
3545 		}
3546 		if (w->thumbhx > w->usehx-DISPLAYSLIDERSIZE-2) w->thumbhx = w->usehx-DISPLAYSLIDERSIZE-2;
3547 		if (w->thumblx < w->uselx+DISPLAYSLIDERSIZE*2+2) w->thumblx = w->uselx+DISPLAYSLIDERSIZE*2+2;
3548 		us_drawhorizontalsliderthumb(w, ly+DISPLAYSLIDERSIZE, lx+DISPLAYSLIDERSIZE+extraroom, hx, w->thumblx, w->thumbhx, 0);
3549 	}
3550 
3551 	/* draw the VCR controls in horizontal slider */
3552 	us_drawwindowicon(w, lx+DISPLAYSLIDERSIZE*2, ly, sim_rewinddots);
3553 	us_drawwindowicon(w, lx+DISPLAYSLIDERSIZE*3, ly, sim_playbackwardsdots);
3554 	us_drawwindowicon(w, lx+DISPLAYSLIDERSIZE*4, ly, sim_stopdots);
3555 	us_drawwindowicon(w, lx+DISPLAYSLIDERSIZE*5, ly, sim_playforwarddots);
3556 	us_drawwindowicon(w, lx+DISPLAYSLIDERSIZE*6, ly, sim_fastforwarddots);
3557 	us_drawslidercorner(w, lx+DISPLAYSLIDERSIZE*7, lx+DISPLAYSLIDERSIZE*7-1, ly, ly+DISPLAYSLIDERSIZE-1, TRUE);
3558 	us_drawwindowicon(w, lx+DISPLAYSLIDERSIZE*8, ly, sim_fasterdots);
3559 	us_drawwindowicon(w, lx+DISPLAYSLIDERSIZE*9, ly, sim_slowerdots);
3560 	us_drawslidercorner(w, lx+DISPLAYSLIDERSIZE*10, lx+DISPLAYSLIDERSIZE*10-1, ly, ly+DISPLAYSLIDERSIZE-1, TRUE);
3561 
3562 	/* draw explorer icon in corner of sliders */
3563 	us_drawexplorericon(w, lx, ly);
3564 
3565 	/* reset bounds */
3566 	w->uselx += DISPLAYSLIDERSIZE;
3567 	w->usely += DISPLAYSLIDERSIZE;
3568 
3569 	/* draw red outline */
3570 	if ((w->state&WINDOWSIMMODE) != 0)
3571 		us_showwindowmode(w);
3572 
3573 	/* write banner at top of window */
3574 	TDCLEAR(descript);
3575 	TDSETSIZE(descript, TXTSETPOINTS(12));
3576 	screensettextinfo(w, NOTECHNOLOGY, descript);
3577 	sim_window_desc.col = el_colmentxt;
3578 	simname = 0;
3579 	switch (sim_window_state & SIMENGINECUR)
3580 	{
3581 		case SIMENGINECURALS:     simname = "ALS";       break;
3582 		case SIMENGINECURIRSIM:   simname = "IRSIM";     break;
3583 		case SIMENGINECURVERILOG: simname = "Verilog";   break;
3584 		case SIMENGINECURSPICE:   simname = "Spice";     break;
3585 	}
3586 	infstr = initinfstr();
3587 	if ((w->state&WINDOWSIMMODE) == 0)
3588 	{
3589 		formatinfstr(infstr, _("Inactive %s Simulation Window"), simname);
3590 	} else
3591 	{
3592 		formatinfstr(infstr, _("%s Simulation Window"), simname);
3593 	}
3594 	if (sim_window_title != 0) formatinfstr(infstr, x_(", %s"), sim_window_title);
3595 	addstringtoinfstr(infstr, x_(", ? for help"));
3596 	lx = w->uselx;
3597 	screendrawtext(w, lx+5, hy-TOPBARSIZE+2, returninfstr(infstr), &sim_window_desc);
3598 	screeninvertbox(w, lx, hx, hy-TOPBARSIZE, hy);
3599 
3600 	sim_window_drawtimescale(w);
3601 	sim_window_drawgraph(w);
3602 	sim_window_drawcursors(w);
3603 	if (sim_window_highframe >= 0)
3604 		sim_window_showtracebar(w, sim_window_highframe, 1);
3605 }
3606 
3607 /****************************** SUPPORT FUNCTIONS ******************************/
3608 
3609 /*
3610  * Routine to convert from simulation time to the proper X position in the waveform window.
3611  */
sim_window_timetoxpos(double time)3612 INTBIG sim_window_timetoxpos(double time)
3613 {
3614 	double result;
3615 	REGISTER TRACE *tr;
3616 
3617 	tr = sim_window_firstrace;
3618 	if (tr == NOTRACE) return(0);
3619 	result = (WAVEXSIGEND-sim_window_wavexsigstart) * (time - tr->mintime) /
3620 		(tr->maxtime - tr->mintime) + sim_window_wavexsigstart;
3621 	return(rounddouble(result));
3622 }
3623 
3624 /*
3625  * Routine to convert from the X position in the waveform window to simulation time.
3626  */
sim_window_xpostotime(INTBIG xpos)3627 double sim_window_xpostotime(INTBIG xpos)
3628 {
3629 	double result;
3630 	REGISTER TRACE *tr;
3631 
3632 	tr = sim_window_firstrace;
3633 	if (tr == NOTRACE) return(xpos);
3634 	result = (xpos-sim_window_wavexsigstart) * (tr->maxtime-tr->mintime) /
3635 		(WAVEXSIGEND-sim_window_wavexsigstart) + tr->mintime;
3636 	return(result);
3637 }
3638 
3639 /*
3640  * Routine to convert from framno and simulation value to the proper Y position in the waveform window.
3641  */
sim_window_valtoypos(INTBIG frameno,double val)3642 INTBIG sim_window_valtoypos(INTBIG frameno, double val)
3643 {
3644 	float topval, botval;
3645 	INTBIG y_min, y, trace_spacing;
3646 
3647 	topval = sim_window_get_topval(frameno);
3648 	botval = sim_window_get_botval(frameno);
3649 	if (val < botval || val > topval || topval == botval) return(-1);
3650 	if (sim_window_visframes <= 0) return(-1);
3651 	trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
3652 	y_min = (sim_window_visframes - 1 - (frameno - sim_window_topframes)) *
3653 		trace_spacing + WAVEYSIGBOT;
3654 	y = (INTBIG) ((val - botval) / (topval - botval) * (trace_spacing - WAVEYSIGGAP));
3655 	return y_min + y;
3656 }
3657 
3658 /*
3659  * Routine to convert from the Y position in the waveform window to simulation value and frameno.
3660  */
sim_window_ypostoval(INTBIG ypos,double * val)3661 INTBIG sim_window_ypostoval(INTBIG ypos, double *val)
3662 {
3663 	INTBIG frameno, trace_spacing;
3664 	float topval, botval;
3665 
3666 	if (sim_window_visframes <= 0) return(-1);
3667 	trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
3668 	frameno = (INTBIG)((ypos - WAVEYSIGBOT)/(double)trace_spacing);
3669 	ypos -= WAVEYSIGBOT + frameno*trace_spacing;
3670 	if (ypos < 0 || ypos > trace_spacing - WAVEYSIGGAP) return(-1);
3671 	frameno = sim_window_visframes - 1 - (frameno - sim_window_topframes);
3672 	topval = sim_window_get_topval(frameno);
3673 	botval = sim_window_get_botval(frameno);
3674 	if (topval == botval) return(-1);
3675 	*val = botval + (topval - botval)*ypos/(trace_spacing - WAVEYSIGGAP);
3676 	return(frameno);
3677 }
3678 
3679 /*
3680  * This procedure prints out the time scale on the bottom of the waveform window.
3681  */
sim_window_drawtimescale(WINDOWPART * wavewin)3682 void sim_window_drawtimescale(WINDOWPART *wavewin)
3683 {
3684 	INTBIG x_pos;
3685 	float time;
3686 	REGISTER TRACE *tr;
3687 	INTBIG i1, i2;
3688 
3689 	tr = sim_window_firstrace;
3690 	if (tr == NOTRACE) return;
3691 
3692 	sim_window_setmask(LAYERA);
3693 	sim_window_setcolor(MENTXT);
3694 	sim_window_max_timetick = sim_window_maxtime = (float)tr->maxtime;
3695 	sim_window_min_timetick = sim_window_mintime = (float)tr->mintime;
3696 	sim_window_time_separation = sim_window_sensible_value(&sim_window_max_timetick, &sim_window_min_timetick, &i1, &i2, 5);
3697 	if (sim_window_time_separation == 0.0) return;
3698 
3699 	time = sim_window_min_timetick;
3700 	for(;;)
3701 	{
3702 		if (time > sim_window_maxtime) break;
3703 		x_pos = sim_window_timetoxpos(time);
3704 		sim_window_moveto(x_pos, 0);
3705 		sim_window_drawcstring(wavewin, sim_windowconvertengineeringnotation2(time, i2));
3706 		time += sim_window_time_separation;
3707 	}
3708 }
3709 
sim_window_draw_timeticks(WINDOWPART * wavewin,INTBIG y1,INTBIG y2,BOOLEAN grid)3710 void sim_window_draw_timeticks(WINDOWPART *wavewin, INTBIG y1, INTBIG y2, BOOLEAN grid)
3711 {
3712 	INTBIG x_pos;
3713 	float time;
3714 
3715 	time = sim_window_max_timetick;
3716 
3717 	for(;;)
3718 	{
3719 		if (time < sim_window_mintime) break;
3720 		x_pos = sim_window_timetoxpos(time);
3721 
3722 		if (grid == TRUE) {
3723 			sim_window_moveto(x_pos, y1);
3724 			sim_window_drawto(wavewin, x_pos, y2, 1);
3725 		}
3726 
3727 		sim_window_moveto(x_pos, y1);
3728 		sim_window_drawto(wavewin, x_pos, y1+10, 0);
3729 		sim_window_moveto(x_pos, y2);
3730 		sim_window_drawto(wavewin, x_pos, y2-10, 0);
3731 		time -= sim_window_time_separation;
3732 	}
3733 }
3734 
3735 /*
3736  * Routine to truncate the time value "time" to the next lower value that is "integral"
3737  */
sim_window_sensibletimevalue(double time)3738 double sim_window_sensibletimevalue(double time)
3739 {
3740 	double scale;
3741 
3742 	if (time != 0.0)
3743 	{
3744 		scale = 1.0;
3745 		while (doubleslessthan(time, 1.0))
3746 		{
3747 			time *= 10.0;
3748 			scale /= 10.0;
3749 		}
3750 		time = doublefloor(time) * scale;
3751 	}
3752 	return(time);
3753 }
3754 
3755 /*
3756  * Routine to show the vertical bar between signal names and waveform data.
3757  * If "style" is 0, draw it solid
3758  * If "style" is 1, highlight it
3759  * If "style" is 2, unhighlight it
3760  */
sim_window_showtracebar(WINDOWPART * wavewin,INTBIG frame,INTBIG style)3761 void sim_window_showtracebar(WINDOWPART *wavewin, INTBIG frame, INTBIG style)
3762 {
3763 	INTBIG y_pos, temp_trace_spacing, visframe, ly, hy, xpos;
3764 
3765 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
3766 	visframe = frame - sim_window_topframes;
3767 	if (visframe < 0 || visframe >= sim_window_visframes) return;
3768 	y_pos = (sim_window_visframes - 1 - visframe) * temp_trace_spacing + WAVEYSIGBOT;
3769 
3770 	/* draw the vertical line between the label and the trace */
3771 	switch (style)
3772 	{
3773 		case 0:
3774 			sim_window_setcolor(MENGLY);
3775 			sim_window_moveto(sim_window_wavexbar, y_pos);
3776 			sim_window_drawto(wavewin, sim_window_wavexbar, y_pos+temp_trace_spacing-WAVEYSIGGAP, 0);
3777 			break;
3778 		case 1:
3779 			sim_window_setcolor(HIGHLIT);
3780 			sim_window_setmask(LAYERH);
3781 			ly = y_pos;   xpos = 0;
3782 			sim_window_mapcoord(wavewin, &xpos, &ly);
3783 			hy = y_pos+temp_trace_spacing-WAVEYSIGGAP;
3784 			xpos = sim_window_wavexbar;
3785 			sim_window_mapcoord(wavewin, &xpos, &hy);
3786 			screendrawbox(wavewin, xpos-3, xpos+1, ly, hy, &sim_window_desc);
3787 			sim_window_setmask(LAYERA);
3788 			break;
3789 		case 2:
3790 			sim_window_setcolor(ALLOFF);
3791 			sim_window_setmask(LAYERH);
3792 			ly = y_pos;   xpos = 0;
3793 			sim_window_mapcoord(wavewin, &xpos, &ly);
3794 			hy = y_pos+temp_trace_spacing-WAVEYSIGGAP;
3795 			xpos = sim_window_wavexbar;
3796 			sim_window_mapcoord(wavewin, &xpos, &hy);
3797 			screendrawbox(wavewin, xpos-3, xpos+1, ly, hy, &sim_window_desc);
3798 			sim_window_setmask(LAYERA);
3799 			break;
3800 	}
3801 }
3802 
sim_window_writetracename(WINDOWPART * wavewin,TRACE * tr)3803 void sim_window_writetracename(WINDOWPART *wavewin, TRACE *tr)
3804 {
3805 	INTBIG y_pos, temp_trace_spacing, frameno, px, py, textwid,
3806 		maxheight, maxwidth, len, save, size;
3807 	REGISTER CHAR *pt;
3808 	UINTBIG descript[TEXTDESCRIPTSIZE];
3809 	INTBIG wid, hei;
3810 
3811 	/* compute positions */
3812 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
3813 	frameno = tr->frameno - sim_window_topframes;
3814 	if (frameno < 0 || frameno >= sim_window_visframes) return;
3815 	y_pos = (sim_window_visframes - 1 - frameno) * temp_trace_spacing + WAVEYSIGBOT;
3816 
3817 	/* draw the vertical line between the label and the trace */
3818 	sim_window_showtracebar(wavewin, tr->frameno, 0);
3819 
3820 	/* set the text color */
3821 	if ((tr->flags&TRACETYPE) == TRACEISANALOG) sim_window_setcolor(tr->color); else
3822 		sim_window_setcolor(MENTXT);
3823 
3824 	/* write the text */
3825 	if (tr->buschannel == NOTRACE) px = 1; else px = 10;
3826 	if ((tr->flags&TRACETYPE) == TRACEISANALOG) textwid = sim_window_wavexnameendana; else
3827 		textwid = sim_window_wavexnameend;
3828 	py = y_pos + tr->nameoff;
3829 	maxheight = applyyscale(wavewin, temp_trace_spacing);
3830 	maxwidth = applyxscale(wavewin, textwid-px);
3831 	sim_window_mapcoord(wavewin, &px, &py);
3832 	pt = tr->name;
3833 	if (sim_window_traceprefix != 0)
3834 	{
3835 		len = estrlen(sim_window_traceprefix);
3836 		if (namesamen(pt, sim_window_traceprefix, len) == 0)
3837 			pt += len;
3838 	}
3839 	len = estrlen(pt);
3840 	TDCLEAR(descript);
3841 	for(size = sim_window_textsize; size >= 4; size--)
3842 	{
3843 		TDSETSIZE(descript, TXTSETPOINTS(size));
3844 		screensettextinfo(wavewin, NOTECHNOLOGY, descript);
3845 		screengettextsize(wavewin, pt, &wid, &hei);
3846 		if (hei > maxheight && size > 4) continue;
3847 		sim_window_txthei = hei * (wavewin->screenhy - wavewin->screenly) /
3848 			(wavewin->usehy - wavewin->usely - 20);
3849 		while (len > 1 && wid > maxwidth)
3850 		{
3851 			len--;
3852 			save = pt[len];   pt[len] = 0;
3853 			screengettextsize(wavewin, pt, &wid, &hei);
3854 			pt[len] = (CHAR)save;
3855 		}
3856 		save = pt[len];   pt[len] = 0;
3857 		screendrawtext(wavewin, px, py, pt, &sim_window_desc);
3858 		pt[len] = (CHAR)save;
3859 		break;
3860 	}
3861 }
3862 
3863 /*
3864  * This procedure draws the cursors on the timing diagram.  The other color
3865  * planes are write protected so that the cursor doesn't alter any of the
3866  * timing diagram information.
3867  */
sim_window_drawcursors(WINDOWPART * wavewin)3868 void sim_window_drawcursors(WINDOWPART *wavewin)
3869 {
3870 	INTBIG x_pos;
3871 	INTBIG lx, ly, hx, hy, swap, textwid, extx, deltax, level, strength;
3872 	CHAR s2[60];
3873 	double mainv, extv, deltav;
3874 	REGISTER TRACE *tr;
3875 
3876 	/* erase all cursors */
3877 	sim_window_setcolor(ALLOFF);
3878 	sim_window_setmask(LAYERH);
3879 	sim_window_drawbox(wavewin, sim_window_wavexsigstart, 0, WAVEXSIGEND, WAVEYCURSTOP, 0);
3880 	sim_window_setcolor(HIGHLIT);
3881 
3882 	/* draw main cursor */
3883 	x_pos = sim_window_timetoxpos(sim_window_maincursor);
3884 	if (x_pos >= sim_window_wavexsigstart && x_pos <= WAVEXSIGEND)
3885 	{
3886 		sim_window_moveto(x_pos, WAVEYSIGBOT);
3887 		sim_window_drawto(wavewin, x_pos, WAVEYCURSTOP, 0);
3888 	}
3889 
3890 	/* draw extension cursor */
3891 	x_pos = sim_window_timetoxpos(sim_window_extensioncursor);
3892 	if (x_pos >= sim_window_wavexsigstart && x_pos <= WAVEXSIGEND)
3893 	{
3894 		sim_window_moveto(x_pos, WAVEYSIGBOT);
3895 		sim_window_drawto(wavewin, x_pos, WAVEYCURSTOP, 0);
3896 		sim_window_moveto(x_pos-5, WAVEYCURSTOP-12);
3897 		sim_window_drawto(wavewin, x_pos+5, WAVEYCURSTOP-2, 0);
3898 		sim_window_moveto(x_pos+5, WAVEYCURSTOP-12);
3899 		sim_window_drawto(wavewin, x_pos-5, WAVEYCURSTOP-2, 0);
3900 	}
3901 
3902 	/* draw cursor locations textually */
3903 	sim_window_setmask(LAYERA & ~LAYERH);
3904 	sim_window_setcolor(ALLOFF);
3905 	lx = sim_window_wavexsigstart;   ly = WAVEYTEXTBOT;
3906 	hx = WAVEXSIGEND;                hy = WAVEYTEXTTOP;
3907 	sim_window_mapcoord(wavewin, &lx, &ly);
3908 	sim_window_mapcoord(wavewin, &hx, &hy);
3909 	if (lx > hx) { swap = lx;   lx = hx;   hx = swap; }
3910 	if (ly > hy) { swap = ly;   ly = hy;   hy = swap; }
3911 	screendrawbox(wavewin, lx, hx, ly+1, hy, &sim_window_desc);
3912 
3913 	sim_window_setcolor(MENTXT);
3914 	sim_window_moveto(sim_window_wavexsigstart, WAVEYTEXTTOP);
3915 	estrcpy(s2, _("Main: "));
3916 	estrcat(s2, sim_windowconvertengineeringnotation(sim_window_maincursor));
3917 	sim_window_drawulstring(wavewin, s2);
3918 
3919 	textwid = (WAVEXSIGEND - sim_window_wavexsigstart) / 3;
3920 	extx = sim_window_wavexsigstart + textwid;
3921 	deltax = WAVEXSIGEND - textwid;
3922 	if (sim_window_highlightedtracecount == 1)
3923 	{
3924 		tr = sim_window_highlightedtraces[0];
3925 		switch (tr->flags&TRACETYPE)
3926 		{
3927 			case TRACEISANALOG:
3928 				mainv = sim_window_getanatracevalue((INTBIG)tr, sim_window_maincursor);
3929 				sim_window_moveto(sim_window_wavexsigstart, 585);
3930 				esnprintf(s2, 60, x_("Y=%g"), mainv);
3931 				sim_window_drawulstring(wavewin, s2);
3932 
3933 				extv = sim_window_getanatracevalue((INTBIG)tr, sim_window_extensioncursor);
3934 				sim_window_moveto(extx, 585);
3935 				esnprintf(s2, 60, x_("Y=%g"), extv);
3936 				sim_window_drawulstring(wavewin, s2);
3937 
3938 				deltav = fabs(mainv-extv);
3939 				sim_window_moveto(deltax, 585);
3940 				esnprintf(s2, 60, x_("dY=%g"), deltav);
3941 				sim_window_drawulstring(wavewin, s2);
3942 				break;
3943 			case TRACEISDIGITAL:
3944 				sim_window_getdigtracevalue((INTBIG)tr, sim_window_maincursor, &level, &strength);
3945 				switch (level)
3946 				{
3947 					case LOGIC_LOW:  estrcpy(s2, x_("=LOW"));   break;
3948 					case LOGIC_HIGH: estrcpy(s2, x_("=HIGH"));  break;
3949 					case LOGIC_X:    estrcpy(s2, x_("=X"));     break;
3950 					case LOGIC_Z:    estrcpy(s2, x_("=Z"));     break;
3951 					default:         estrcpy(s2, x_("=?"));     break;
3952 				}
3953 				sim_window_moveto(sim_window_wavexsigstart, 585);
3954 				sim_window_drawulstring(wavewin, s2);
3955 
3956 				sim_window_getdigtracevalue((INTBIG)tr, sim_window_extensioncursor, &level, &strength);
3957 				switch (level)
3958 				{
3959 					case LOGIC_LOW:  estrcpy(s2, x_("=LOW"));   break;
3960 					case LOGIC_HIGH: estrcpy(s2, x_("=HIGH"));  break;
3961 					case LOGIC_X:    estrcpy(s2, x_("=X"));     break;
3962 					case LOGIC_Z:    estrcpy(s2, x_("=Z"));     break;
3963 					default:         estrcpy(s2, x_("=?"));     break;
3964 				}
3965 				sim_window_moveto(extx, 585);
3966 				sim_window_drawulstring(wavewin, s2);
3967 				break;
3968 			case TRACEISBUS:
3969 			case TRACEISOPENBUS:
3970 				sim_window_moveto(sim_window_wavexsigstart, 585);
3971 				esnprintf(s2, 60, x_("=%s"),
3972 					sim_window_getbustracevalue((INTBIG)tr, sim_window_maincursor));
3973 				sim_window_drawulstring(wavewin, s2);
3974 
3975 				sim_window_moveto(extx, 585);
3976 				esnprintf(s2, 60, x_("=%s"),
3977 					sim_window_getbustracevalue((INTBIG)tr, sim_window_extensioncursor));
3978 				sim_window_drawulstring(wavewin, s2);
3979 				break;
3980 		}
3981 	}
3982 
3983 	sim_window_moveto(extx, WAVEYTEXTTOP);
3984 	estrcpy(s2, _("Ext: "));
3985 	estrcat(s2, sim_windowconvertengineeringnotation(sim_window_extensioncursor));
3986 	sim_window_drawulstring(wavewin, s2);
3987 
3988 	sim_window_moveto(deltax, WAVEYTEXTTOP);
3989 	estrcpy(s2, _("Delta: "));
3990 	deltav = sim_window_extensioncursor - sim_window_maincursor;
3991 	if (deltav < 0.0) deltav = -deltav;
3992 	estrcat(s2, sim_windowconvertengineeringnotation(deltav));
3993 	sim_window_drawulstring(wavewin, s2);
3994 }
3995 
sim_window_drawgraph(WINDOWPART * wavewin)3996 void sim_window_drawgraph(WINDOWPART *wavewin)
3997 {
3998 	REGISTER INTBIG i, lx, ly;
3999 	INTBIG x, y, wid, hei;
4000 	UINTBIG descript[TEXTDESCRIPTSIZE];
4001 	CHAR *msg;
4002 
4003 	/* determine height of text in the window */
4004 	TDCLEAR(descript);
4005 	TDSETSIZE(descript, TXTSETPOINTS(sim_window_textsize));
4006 	screensettextinfo(wavewin, NOTECHNOLOGY, descript);
4007 	screengettextsize(wavewin, x_("Xy"), &x, &y);
4008 	sim_window_txthei = y * (wavewin->screenhy - wavewin->screenly) /
4009 		(wavewin->usehy - wavewin->usely - 20);
4010 
4011 	/* draw vertical divider between signal names and signal waveforms */
4012 	sim_window_setcolor(MENTXT);
4013 	sim_window_moveto(sim_window_wavexbar, WAVEYTEXTBOT);
4014 	sim_window_drawto(wavewin, sim_window_wavexbar, WAVEYTEXTTOP, 0);
4015 
4016 	/* plot it all */
4017 	if (sim_window_firstrace == NOTRACE)
4018 	{
4019 		sim_window_setcolor(MENTXT);
4020 		TDCLEAR(descript);
4021 		TDSETSIZE(descript, TXTSETPOINTS(20));
4022 		screensettextinfo(wavewin, NOTECHNOLOGY, descript);
4023 		msg = _("Nothing plotted: type 'a' to add a signal");
4024 		screengettextsize(wavewin, msg, &wid, &hei);
4025 		lx = (wavewin->usehx + wavewin->uselx) / 2 - wid / 2;
4026 		ly = (wavewin->usehy + wavewin->usely) / 2 - hei / 2;
4027 		screendrawtext(wavewin, lx, ly, msg, &sim_window_desc);
4028 	} else
4029 	{
4030 		/* draw the frames */
4031 		for(i=0; i<sim_window_visframes; i++)
4032 			sim_window_drawframe(i+sim_window_topframes, wavewin);
4033 		for(i=0; i<sim_window_highlightedtracecount; i++)
4034 			sim_window_highlightname(wavewin, sim_window_highlightedtraces[i], TRUE);
4035 	}
4036 }
4037 
4038 /*
4039  * Routine to draw frame "frame" in waveform window "wavewin".
4040  */
sim_window_drawframe(INTBIG frame,WINDOWPART * wavewin)4041 void sim_window_drawframe(INTBIG frame, WINDOWPART *wavewin)
4042 {
4043 	INTBIG y_min, y_max, y_pos, maxoff, slot, i, temp_trace_spacing, i1, i2;
4044 	BOOLEAN hasana, last, drawtext, grid=TRUE;
4045 	UINTBIG descript[TEXTDESCRIPTSIZE];
4046 	INTBIG x, y, px, py;
4047 	float separation, topval, botval, val;
4048 	CHAR *s2;
4049 	REGISTER TRACE *tr, *onetr;
4050 	int vgrid;
4051 
4052 	/* see how many traces are in this frame, determine whether it is analog */
4053 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
4054 	hasana = FALSE;
4055 	maxoff = 0;
4056 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
4057 	{
4058 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
4059 		if (tr->frameno != frame) continue;
4060 		tr->nameoff = -1;
4061 		maxoff++;
4062 		if ((tr->flags&TRACETYPE) == TRACEISANALOG) hasana = TRUE;
4063 		onetr = tr;
4064 	}
4065 	if (maxoff == 1)
4066 	{
4067 		/* only one trace: center it */
4068 		onetr->nameoff = (temp_trace_spacing - WAVEYSIGGAP - sim_window_txthei) / 2;
4069 		if (onetr->nameoff < 0) onetr->nameoff = 0;
4070 	} else
4071 	{
4072 		/* multiple traces: compute them */
4073 		slot = 0;
4074 		for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
4075 		{
4076 			if (tr->frameno != frame) continue;
4077 			tr->nameoff = muldiv(slot, temp_trace_spacing - WAVEYSIGGAP - sim_window_txthei, maxoff-1);
4078 			slot++;
4079 		}
4080 	}
4081 
4082 	if (wavewin->state & GRIDON) grid = TRUE;
4083 		else grid = FALSE;
4084 
4085 	/* clear the waveform area */
4086 	y_min = (sim_window_visframes - 1 - (frame - sim_window_topframes)) *
4087 		temp_trace_spacing + WAVEYSIGBOT;
4088 	y_max = y_min + temp_trace_spacing - WAVEYSIGGAP;
4089 
4090 	/* if there are analog traces on this line, show height values */
4091 	if (hasana)
4092 	{
4093 		sim_window_setmask(LAYERA);
4094 		sim_window_setcolor(MENTXT);
4095 		sim_window_drawbox(wavewin, sim_window_wavexsigstart, y_min, WAVEXSIGEND, y_max, 0);
4096 		topval = sim_window_get_anahigh(frame);
4097 		botval = sim_window_get_analow(frame);
4098 		vgrid = (y_max-y_min) / (2 * sim_window_txthei);
4099 		if (vgrid < 1) vgrid = 1;
4100 		if (vgrid > 4) vgrid = 4 + (vgrid-4)/3;
4101 		separation = sim_window_sensible_value(&topval, &botval, &i1, &i2, vgrid);
4102 		sim_window_set_topval(frame, topval);
4103 		sim_window_set_botval(frame, botval);
4104 		if (sim_window_vdd > 0.0)
4105 		{
4106 			/* draw voltage thresholds */
4107 			sim_window_setcolor(ALLOFF);
4108 			for(i=0; i < PERCENTSIZE; i++)
4109 			{
4110 				y = sim_window_valtoypos(frame, sim_window_percent[i] * sim_window_vdd);
4111 				if (y < 0) continue;
4112 				sim_window_moveto(sim_window_wavexsigstart, y);
4113 				sim_window_drawto(wavewin, WAVEXSIGEND, y, 1);
4114 			}
4115 		}
4116 		sim_window_setcolor(MENTXT);
4117 		sim_window_draw_timeticks(wavewin, y_min, y_max, grid);
4118 		val = topval;
4119 		if (separation > 0.0)
4120 		{
4121 			for(i=0; ; i++)
4122 			{
4123 				if (val + 0.5f * separation < botval) break;
4124 
4125 				y_pos = roundfloat((val-botval) / (topval-botval) * (float)(y_max-y_min)) + y_min;
4126 				sim_window_moveto(sim_window_wavexnameendana, y_pos);
4127 				sim_window_drawto(wavewin, sim_window_wavexbar, y_pos, 0);
4128 
4129 				if (grid)
4130 				{
4131 					sim_window_moveto(sim_window_wavexsigstart, y_pos);
4132 					sim_window_drawto(wavewin, WAVEXSIGEND, y_pos, 1);
4133 				}
4134 
4135 				if (val - 0.5f*separation < botval) last = TRUE; else
4136 					last = FALSE;
4137 
4138 				/* see if the text should be drawn */
4139 				drawtext = FALSE;
4140 				if (sim_window_txthei*2 < temp_trace_spacing)
4141 				{
4142 					if (sim_window_txthei*4 < temp_trace_spacing)
4143 					{
4144 						drawtext = TRUE;
4145 					} else
4146 					{
4147 						if (i == 0 || last) drawtext = TRUE;
4148 					}
4149 				}
4150 				if (drawtext)
4151 				{
4152 					s2 = sim_window_prettyprint(val, i1, i2);
4153 
4154 					TDCLEAR(descript);
4155 					TDSETSIZE(descript, TXTSETPOINTS(sim_window_textsize));
4156 					screensettextinfo(wavewin, NOTECHNOLOGY, descript);
4157 					screengettextsize(wavewin, s2, &x, &y);
4158 					px = sim_window_wavexnameendana;   py = y_pos;
4159 					sim_window_mapcoord(wavewin, &px, &py);
4160 					if (!last)
4161 					{
4162 						if (i == 0) py -= y; else
4163 							py -= y/2;
4164 					}
4165 					screendrawtext(wavewin, px-x, py, s2, &sim_window_desc);
4166 				}
4167 				val -= separation;
4168 			}
4169 		}
4170 	} else
4171 	{
4172 		sim_window_setmask(LAYERA);
4173 		sim_window_setcolor(0);
4174 		sim_window_drawbox(wavewin, sim_window_wavexsigstart, y_min, WAVEXSIGEND, y_max, 2);
4175 		sim_window_set_topval(frame, 0.0);
4176 		sim_window_set_botval(frame, 0.0);
4177 	}
4178 
4179 	/* draw the highlighted traces in this frame */
4180 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
4181 	{
4182 		if (tr->frameno != frame) continue;
4183 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
4184 		if ((tr->flags&TRACESELECTED) == 0) continue;
4185 		(void)sim_window_plottrace(tr, wavewin, 0, 0, 0);
4186 	}
4187 
4188 	/* draw the unhighlighted traces in this frame */
4189 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
4190 	{
4191 		if (tr->frameno != frame) continue;
4192 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
4193 		if ((tr->flags&TRACESELECTED) != 0) continue;
4194 		(void)sim_window_plottrace(tr, wavewin, 0, 0, 0);
4195 	}
4196 }
4197 
4198 /*
4199  * Routine to draw a trace "tr" in waveform window "wavewin".  "style" is:
4200  *  0   draw normal trace
4201  *  1   search for point (x,y) on trace, return TRUE if found
4202  *  2   draw trace in highlight
4203  */
sim_window_plottrace(TRACE * tr,WINDOWPART * wavewin,INTBIG style,INTBIG x,INTBIG y)4204 BOOLEAN sim_window_plottrace(TRACE *tr, WINDOWPART *wavewin, INTBIG style, INTBIG x, INTBIG y)
4205 {
4206 	INTBIG x_min, x_max, y_min, y_max, y_ctr, j, state, laststate, first,
4207 		slot, temp_trace_spacing, fx, fy, tx, ty, color, strength,
4208 		cfx, cfy, ctx, cty, sigcount, flags;
4209 	CHAR s2[50];
4210 	REGISTER BOOLEAN hitpoint, firstinbus, thick;
4211 	REGISTER TRACE *bustr;
4212 	double time, position, nexttime;
4213 
4214 	/* get coordinates */
4215 	if (sim_window_visframes == 0) return(FALSE);
4216 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
4217 	slot = tr->frameno - sim_window_topframes;
4218 	if (slot < 0 || slot >= sim_window_visframes) return(FALSE);
4219 	y_min = (sim_window_visframes - 1 - slot) * temp_trace_spacing + WAVEYSIGBOT;
4220 	y_max = y_min + temp_trace_spacing - WAVEYSIGGAP;
4221 
4222 	if ((tr->flags&TRACESELECTED) != 0) thick = TRUE; else
4223 		thick = FALSE;
4224 
4225 	/* handle name field on the left */
4226 	if (style == 0)
4227 	{
4228 		/* draw normal trace name */
4229 		sim_window_writetracename(wavewin, tr);
4230 	}
4231 	hitpoint = FALSE;
4232 
4233 	/* handle busses */
4234 	flags = tr->flags & TRACETYPE;
4235 	if (flags == TRACEISBUS || flags == TRACEISOPENBUS)
4236 	{
4237 		/* enumerate signals on the bus and make sure the global array has room */
4238 		sigcount = sim_window_ensurespace(tr);
4239 
4240 		/* find starting time */
4241 		firstinbus = TRUE;
4242 		for(bustr = sim_window_firstrace; bustr != NOTRACE; bustr = bustr->nexttrace)
4243 		{
4244 			if (bustr->buschannel != tr) continue;
4245 
4246 			/* LINTED "time" used in proper order */
4247 			if (firstinbus || bustr->timearray[0] < time)
4248 				time = bustr->timearray[0];
4249 			firstinbus = FALSE;
4250 		}
4251 
4252 		/* draw the waveform */
4253 		x_min = sim_window_wavexsigstart;
4254 		for(;;)
4255 		{
4256 			/* compute signal value at time "time" */
4257 			for(bustr = sim_window_firstrace; bustr != NOTRACE; bustr = bustr->nexttrace)
4258 			{
4259 				if (bustr->buschannel != tr) continue;
4260 				for(j=0; j<bustr->numsteps; j++)
4261 					if (time < bustr->timearray[j]) break;
4262 				if (j > 0) j--;
4263 				sim_window_sigvalues[bustr->busindex] = bustr->statearray[j] >> 8;
4264 			}
4265 
4266 			/* compute the value string */
4267 			estrcpy(s2, sim_window_makewidevalue(sigcount, sim_window_sigvalues));
4268 
4269 			/* draw the value */
4270 			x_max = sim_window_timetoxpos(time);
4271 			if (x_max < sim_window_wavexsigstart) x_max = sim_window_wavexsigstart;
4272 			if (x_max > WAVEXSIGEND) break;
4273 			if (x_max > x_min)
4274 			{
4275 				if (style == 0)
4276 				{
4277 					sim_window_setcolor(sim_colorstrengthpower);
4278 					sim_window_moveto(x_max+BUSANGLE/2, (y_min+y_max)/2);
4279 					sim_window_drawhcstring(wavewin, s2);
4280 				}
4281 				hitpoint |= sim_window_lineseg(wavewin, x_min, (y_min+y_max)/2, x_min+BUSANGLE, y_min,
4282 					style, x, y, thick);
4283 				hitpoint |= sim_window_lineseg(wavewin, x_min+BUSANGLE, y_min, x_max-BUSANGLE, y_min,
4284 					style, x, y, thick);
4285 				hitpoint |= sim_window_lineseg(wavewin, x_max-BUSANGLE, y_min, x_max, (y_min+y_max)/2,
4286 					style, x, y, thick);
4287 				hitpoint |= sim_window_lineseg(wavewin, x_max, (y_min+y_max)/2, x_max-BUSANGLE, y_max,
4288 					style, x, y, thick);
4289 				hitpoint |= sim_window_lineseg(wavewin, x_max-BUSANGLE, y_max, x_min+BUSANGLE, y_max,
4290 					style, x, y, thick);
4291 				hitpoint |= sim_window_lineseg(wavewin, x_min+BUSANGLE, y_max, x_min, (y_min+y_max)/2,
4292 					style, x, y, thick);
4293 				x_min = x_max;
4294 			}
4295 
4296 			/* advance to the next time */
4297 			nexttime = time;
4298 			for(bustr = sim_window_firstrace; bustr != NOTRACE; bustr = bustr->nexttrace)
4299 			{
4300 				if (bustr->buschannel != tr) continue;
4301 				for(j=0; j<bustr->numsteps; j++)
4302 					if (bustr->timearray[j] > time) break;
4303 				if (j < bustr->numsteps)
4304 				{
4305 					if (nexttime == time || bustr->timearray[j] < nexttime)
4306 						nexttime = bustr->timearray[j];
4307 				}
4308 			}
4309 			if (nexttime == time) break;
4310 			time = nexttime;
4311 		}
4312 		if (x_min < WAVEXSIGEND)
4313 		{
4314 			x_max = WAVEXSIGEND;
4315 			sim_window_setcolor(sim_colorstrengthpower);
4316 			hitpoint |= sim_window_lineseg(wavewin, x_min, (y_min+y_max)/2, x_min+BUSANGLE, y_min,
4317 				style, x, y, thick);
4318 			hitpoint |= sim_window_lineseg(wavewin, x_min+BUSANGLE, y_min, x_max-BUSANGLE, y_min,
4319 				style, x, y, thick);
4320 			hitpoint |= sim_window_lineseg(wavewin, x_max-BUSANGLE, y_min, x_max, (y_min+y_max)/2,
4321 				style, x, y, thick);
4322 			hitpoint |= sim_window_lineseg(wavewin, x_max, (y_min+y_max)/2, x_max-BUSANGLE, y_max,
4323 				style, x, y, thick);
4324 			hitpoint |= sim_window_lineseg(wavewin, x_max-BUSANGLE, y_max, x_min+BUSANGLE, y_max,
4325 				style, x, y, thick);
4326 			hitpoint |= sim_window_lineseg(wavewin, x_min+BUSANGLE, y_max, x_min, (y_min+y_max)/2,
4327 				style, x, y, thick);
4328 		}
4329 		return(hitpoint);
4330 	}
4331 
4332 	/* handle digital waveform */
4333 	if (flags == TRACEISDIGITAL)
4334 	{
4335 		first = 1;
4336 		for(j=0; j<tr->numsteps; j++)
4337 		{
4338 			time = tr->timearray[j];
4339 			if (j == tr->numsteps-1) x_max = WAVEXSIGEND; else
4340 			{
4341 				x_max = sim_window_timetoxpos(tr->timearray[j+1]);
4342 				if (x_max < sim_window_wavexsigstart) continue;
4343 				if (x_max > WAVEXSIGEND) x_max = WAVEXSIGEND;
4344 			}
4345 			x_min = sim_window_timetoxpos(time);
4346 			if (x_min < sim_window_wavexsigstart) x_min = sim_window_wavexsigstart;
4347 			if (x_min > WAVEXSIGEND) continue;
4348 
4349 			state = tr->statearray[j] >> 8;
4350 			strength = tr->statearray[j] & 0377;
4351 			if (strength == 0) color = sim_colorstrengthoff; else
4352 				if (strength <= NODE_STRENGTH) color = sim_colorstrengthnode; else
4353 					if (strength <= GATE_STRENGTH) color = sim_colorstrengthgate; else
4354 						color = sim_colorstrengthpower;
4355 			sim_window_setcolor(color);
4356 
4357 			/* LINTED "laststate" used in proper order */
4358 			if (first == 0 && state != laststate)
4359 			{
4360 				hitpoint |= sim_window_lineseg(wavewin, x_min, y_min, x_min, y_max,
4361 					style, x, y, thick);
4362 			}
4363 			first = 0;
4364 			switch (state)
4365 			{
4366 				case LOGIC_LOW:
4367 					hitpoint |= sim_window_lineseg(wavewin, x_min, y_min, x_max, y_min,
4368 						style, x, y, thick);
4369 					break;
4370 				case LOGIC_X:
4371 					if (style == 1)
4372 					{
4373 						if (x >= x_min && x <= x_max && y >= y_min && y <= y_max)
4374 							hitpoint = TRUE;
4375 					} else
4376 					{
4377 						sim_window_drawbox(wavewin, x_min, y_min, x_max, y_max, 1);
4378 					}
4379 					break;
4380 				case LOGIC_HIGH:
4381 					hitpoint |= sim_window_lineseg(wavewin, x_min, y_max, x_max, y_max,
4382 						style, x, y, thick);
4383 					break;
4384 				case LOGIC_Z:
4385 					y_ctr = (y_min+y_max)/2;
4386 					hitpoint |= sim_window_lineseg(wavewin, x_min, y_ctr, x_max, y_ctr,
4387 						style, x, y, thick);
4388 					break;
4389 				default:
4390 					if (style == 1)
4391 					{
4392 						if (x >= x_min && x <= x_max && y >= y_min && y <= y_max)
4393 							hitpoint = TRUE;
4394 					} else
4395 					{
4396 						sim_window_drawbox(wavewin, x_min, y_min, x_max, y_max, 0);
4397 						if ((x_max - x_min) <= 1) break;
4398 						sim_window_setcolor(ALLOFF);
4399 						sim_window_drawbox(wavewin, x_min+1, y_min+1, x_max-1, y_max-1, 0);
4400 						(void)esnprintf(s2, 50, x_("0x%lX"), state);
4401 						sim_window_moveto((x_min + x_max) / 2, y_min+3);
4402 						sim_window_setcolor(color);
4403 						sim_window_drawcstring(wavewin, s2);
4404 					}
4405 					break;
4406 			}
4407 			laststate = state;
4408 		}
4409 		return(hitpoint);
4410 	}
4411 
4412 	/* handle analog waveform */
4413 	first = 1;
4414 	for(j=0; j<tr->numsteps; j++)
4415 	{
4416 		time = tr->timearray[j];
4417 		tx = sim_window_timetoxpos(time);
4418 		position = (double)(y_max - y_min);
4419 		position *= (tr->valuearray[j] - sim_window_get_botval(tr->frameno)) / sim_window_get_extanarange(tr->frameno);
4420 		ty = (INTBIG)position + y_min;
4421 		if (j != 0 && tx >= sim_window_wavexsigstart)
4422 		{
4423 			if (tx > WAVEXSIGEND)
4424 			{
4425 				/* "to" data point off the screen: interpolate */
4426 				/* LINTED "fx" and "fy" used in proper order */
4427 				ty = (ty-fy) * (WAVEXSIGEND-fx) / (tx-fx) + fy;
4428 				tx = WAVEXSIGEND;
4429 			}
4430 
4431 			if (first != 0 && fx < sim_window_wavexsigstart)
4432 			{
4433 				/* "from" data point off the screen: interpolate */
4434 				fy = (ty-fy) * (sim_window_wavexsigstart-fx) / (tx-fx) + fy;
4435 				fx = sim_window_wavexsigstart;
4436 			}
4437 			first = 0;
4438 			if (style != 2) sim_window_setcolor(tr->color);
4439 			if (fy >= y_min && fy <= y_max &&
4440 				ty >= y_min && ty <= y_max)
4441 			{
4442 				hitpoint |= sim_window_lineseg(wavewin, fx, fy, tx, ty, style, x, y, thick);
4443 			} else
4444 			{
4445 				cfx = fx;   cfy = fy;
4446 				ctx = tx;   cty = ty;
4447 				if (!clipline(&cfx, &cfy, &ctx, &cty, sim_window_wavexsigstart, WAVEXSIGEND,
4448 					y_min, y_max))
4449 				{
4450 					hitpoint |= sim_window_lineseg(wavewin, cfx, cfy, ctx, cty, style, x, y, thick);
4451 				}
4452 			}
4453 		}
4454 		fx = tx;   fy = ty;
4455 		if (fx >= WAVEXSIGEND) break;
4456 	}
4457 	return(hitpoint);
4458 }
4459 
sim_window_ensurespace(TRACE * tr)4460 INTBIG sim_window_ensurespace(TRACE *tr)
4461 {
4462 	REGISTER INTBIG sigcount, newtotal;
4463 	REGISTER TRACE *bustr;
4464 
4465 	sigcount = 0;
4466 	for(bustr = sim_window_firstrace; bustr != NOTRACE; bustr = bustr->nexttrace)
4467 	{
4468 		if (bustr->buschannel == tr)
4469 			bustr->busindex = sigcount++;
4470 	}
4471 
4472 	/* make sure there is room for all of the signal values */
4473 	if (sigcount > sim_window_sigtotal)
4474 	{
4475 		newtotal = sim_window_sigtotal * 2;
4476 		if (newtotal == 0) newtotal = 8;
4477 		if (newtotal < sigcount) newtotal = sigcount;
4478 		if (sim_window_sigtotal > 0) efree((CHAR *)sim_window_sigvalues);
4479 		sim_window_sigtotal = 0;
4480 		sim_window_sigvalues = (INTBIG *)emalloc(newtotal * SIZEOFINTBIG, sim_tool->cluster);
4481 		if (sim_window_sigvalues == 0) return(0);
4482 		sim_window_sigtotal = newtotal;
4483 	}
4484 	return(sigcount);
4485 }
4486 
4487 /*
4488  * Routine to draw from (xf,yf) to (xt,yt) in window "wavewin".  If "style" is zero, draw it.
4489  * If "style" is 1, do not draw, but return TRUE if (x,y) is on the line.
4490  */
sim_window_lineseg(WINDOWPART * wavewin,INTBIG xf,INTBIG yf,INTBIG xt,INTBIG yt,INTBIG style,INTBIG x,INTBIG y,BOOLEAN thick)4491 BOOLEAN sim_window_lineseg(WINDOWPART *wavewin, INTBIG xf, INTBIG yf, INTBIG xt, INTBIG yt,
4492 	INTBIG style, INTBIG x, INTBIG y, BOOLEAN thick)
4493 {
4494 	REGISTER INTBIG dist, drawstyle;
4495 
4496 	if (style != 1)
4497 	{
4498 		sim_window_moveto(xf, yf);
4499 		if (thick) drawstyle = 3; else
4500 			drawstyle = 0;
4501 		sim_window_drawto(wavewin, xt, yt, drawstyle);
4502 		return(FALSE);
4503 	}
4504 	dist = disttoline(xf, yf, xt, yt, x, y);
4505 	if (dist < 5) return(TRUE);
4506 	return(FALSE);
4507 }
4508 
4509 /*
4510  * Routine to find cross of a trace "tr" with horizontal line "val" nearest to "time".
4511  * Return TRUE if crass was found
4512  */
sim_window_findcross(TRACE * tr,double val,double * time)4513 BOOLEAN sim_window_findcross(TRACE *tr, double val, double *time)
4514 {
4515 	INTBIG j;
4516 	double btime, ctime;
4517 	BOOLEAN bfound;
4518 
4519 	/* handle analog waveform */
4520 	bfound = FALSE;
4521 	btime = 0;
4522 	for(j=1; j<tr->numsteps; j++)
4523 	{
4524 		if ((tr->valuearray[j-1] > val && tr->valuearray[j] > val) ||
4525 			(tr->valuearray[j-1] < val && tr->valuearray[j] < val)) continue;
4526 		if (tr->valuearray[j-1] == val && tr->valuearray[j] == val)
4527 		{
4528 			if (*time < tr->timearray[j-1]) ctime = tr->timearray[j-1];
4529 			else if (tr->timearray[j] < *time) ctime = tr->timearray[j];
4530 			else ctime = *time;
4531 		} else
4532 		{
4533 			ctime = (val - tr->valuearray[j-1]) / (tr->valuearray[j] - tr->valuearray[j-1]) *
4534 				(tr->timearray[j] - tr->timearray[j-1]) + tr->timearray[j-1];
4535 		}
4536 		if (!bfound || fabs(ctime - *time) < fabs(btime - *time))
4537 		{
4538 			bfound = TRUE;
4539 			btime = ctime;
4540 		}
4541 	}
4542 	if (bfound)
4543 		*time = btime;
4544 	return(bfound);
4545 }
4546 
4547 /*
4548  * routine to snapshot the simulation window in a cell with artwork primitives
4549  */
sim_window_savegraph(void)4550 void sim_window_savegraph(void)
4551 {
4552 	REGISTER INTBIG x_min, x_max, y_min, y_max, j, maxoff, state, laststate, color, first,
4553 		slot, temp_trace_spacing, range, lastcolor, fx, fy, tx, ty, strength,
4554 		sigcount, cx, cy, *data, maxsteps, len;
4555 	UINTBIG descript[TEXTDESCRIPTSIZE];
4556 	REGISTER BOOLEAN hasana, firstinbus;
4557 	INTBIG x, y, busdescr[12], tx1, ty1, tx2, ty2, datapos, cfx, cfy, ctx, cty;
4558 	CHAR s2[15], *pt, *newname;
4559 	REGISTER NODEPROTO *np, *plotnp;
4560 	REGISTER NODEINST *ni;
4561 	REGISTER VARIABLE *var;
4562 	REGISTER WINDOWPART *wavewin;
4563 	REGISTER TRACE *tr, *otr, *bustr;
4564 	double time, position, separation, nexttime;
4565 	REGISTER void *infstr;
4566 
4567 	/* get cell being saved */
4568 	np = getcurcell();
4569 	if (np == NONODEPROTO) return;
4570 
4571 	/* get waveform window */
4572 	wavewin = sim_window_findwaveform();
4573 	if (wavewin == NOWINDOWPART) return;
4574 
4575 	/* determine height of text in the window */
4576 	TDCLEAR(descript);
4577 	TDSETSIZE(descript, TXTSETPOINTS(sim_window_textsize));
4578 	screensettextinfo(wavewin, NOTECHNOLOGY, descript);
4579 	screengettextsize(wavewin, x_("Xy"), &x, &y);
4580 	sim_window_txthei = y * (wavewin->screenhy - wavewin->screenly) /
4581 		(wavewin->usehy - wavewin->usely - 20);
4582 
4583 	/* create the plot cell */
4584 	infstr = initinfstr();
4585 	addstringtoinfstr(infstr, np->protoname);
4586 	addstringtoinfstr(infstr, x_("{sim}"));
4587 	plotnp = newnodeproto(returninfstr(infstr), el_curlib);
4588 	if (plotnp == NONODEPROTO) return;
4589 	setactivity(x_("Make Simulation Plot"));
4590 
4591 	/* determine maximum number of steps */
4592 	maxsteps = 1;
4593 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
4594 	{
4595 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
4596 		if (tr->numsteps > maxsteps) maxsteps = tr->numsteps;
4597 	}
4598 
4599 	/* make space */
4600 	data = (INTBIG *)emalloc(maxsteps * 4 * SIZEOFINTBIG, el_tempcluster);
4601 	if (data == 0) return;
4602 
4603 	/* compute transformation for points in the plot area */
4604 	tx1 = sim_window_wavexsigstart;   ty1 = WAVEYSIGBOT;    sim_window_mapcoord(wavewin, &tx1, &ty1);
4605 	tx2 = WAVEXSIGEND;                ty2 = WAVEYCURSTOP;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4606 	sim_window_offx = (tx2 - tx1) / 2;   sim_window_basex = tx1;
4607 	sim_window_offy = (ty2 - ty1) / 2;   sim_window_basey = ty1;
4608 
4609 	/* write the header */
4610 	tx1 = 383;   ty1 = WAVEYTEXTTOP;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4611 	ni = newnodeinst(gen_invispinprim, tx1, tx1, ty1, ty1, 0, 0, plotnp);
4612 	if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4613 	infstr = initinfstr();
4614 	addstringtoinfstr(infstr, x_("Simulation snapshot of cell "));
4615 	addstringtoinfstr(infstr, describenodeproto(np));
4616 	allocstring(&newname, returninfstr(infstr), el_tempcluster);
4617 	var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)newname, VSTRING|VDISPLAY);
4618 	efree(newname);
4619 	if (var != NOVARIABLE)
4620 	{
4621 		TDSETSIZE(var->textdescript, TXTSETPOINTS(14));
4622 		TDSETPOS(var->textdescript, VTPOSUP);
4623 	}
4624 	endobjectchange((INTBIG)ni, VNODEINST);
4625 
4626 	/* set name offsets */
4627 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace) tr->nameoff = -1;
4628 	temp_trace_spacing = WAVEYSIGRANGE / sim_window_visframes;
4629 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
4630 	{
4631 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
4632 		slot = tr->frameno - sim_window_topframes;
4633 		if (slot < 0 || slot >= sim_window_visframes) continue;
4634 
4635 		/* determine position of trace label on the line */
4636 		if (tr->nameoff < 0)
4637 		{
4638 			hasana = FALSE;
4639 			maxoff = 0;
4640 			for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
4641 			{
4642 				if ((otr->flags&TRACENOTDRAWN) != 0) continue;
4643 				if (otr->frameno != tr->frameno) continue;
4644 				maxoff++;
4645 				if ((otr->flags&TRACETYPE) == TRACEISANALOG) hasana = TRUE;
4646 			}
4647 			if (maxoff == 1)
4648 			{
4649 				/* only one trace: center it */
4650 				tr->nameoff = (temp_trace_spacing - WAVEYSIGGAP - sim_window_txthei) / 2;
4651 				if (tr->nameoff < 0) tr->nameoff = 0;
4652 			} else
4653 			{
4654 				/* multiple traces: compute them */
4655 				range = (temp_trace_spacing - WAVEYSIGGAP - sim_window_txthei*3) / (maxoff-1);
4656 				if (range <= 0) range = 1;
4657 				slot = 0;
4658 				for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
4659 				{
4660 					if ((otr->flags&TRACENOTDRAWN) != 0) continue;
4661 					if (otr->frameno != tr->frameno) continue;
4662 					otr->nameoff = slot * range + sim_window_txthei;
4663 					slot++;
4664 				}
4665 			}
4666 
4667 			/* if there are analog traces on this line, show height values */
4668 			if (hasana)
4669 			{
4670 				y_min = (sim_window_visframes - 1 - (tr->frameno - sim_window_topframes)) *
4671 					temp_trace_spacing + WAVEYSIGBOT;
4672 				y_max = y_min + temp_trace_spacing - WAVEYSIGGAP;
4673 
4674 				tx1 = sim_window_wavexnameendana;   ty1 = y_min;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4675 				tx2 = sim_window_wavexbar;          ty2 = y_min;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4676 				data[0] = -(tx2-tx1)/2;  data[1] = 0;
4677 				data[2] = (tx2-tx1)/2;   data[3] = 0;
4678 				ni = newnodeinst(art_openedpolygonprim, tx1,tx2, ty1,ty2, 0, 0, plotnp);
4679 				if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4680 				(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)data,
4681 					VINTEGER|VISARRAY|(4<<VLENGTHSH));
4682 				endobjectchange((INTBIG)ni, VNODEINST);
4683 
4684 				(void)esnprintf(s2, 15, x_("%g"), sim_window_get_analow(tr->frameno));
4685 				tx1 = sim_window_wavexnameend;   ty1 = y_min;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4686 				ni = newnodeinst(gen_invispinprim, tx1, tx1, ty1, ty1, 0, 0, plotnp);
4687 				if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4688 				var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)s2, VSTRING|VDISPLAY);
4689 				if (var != NOVARIABLE)
4690 				{
4691 					TDSETSIZE(var->textdescript, TXTSETPOINTS(10));
4692 					TDSETPOS(var->textdescript, VTPOSUPLEFT);
4693 				}
4694 				endobjectchange((INTBIG)ni, VNODEINST);
4695 
4696 				tx1 = sim_window_wavexnameendana;   ty1 = y_max;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4697 				tx2 = sim_window_wavexbar;          ty2 = y_max;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4698 				data[0] = -(tx2-tx1)/2;  data[1] = 0;
4699 				data[2] = (tx2-tx1)/2;   data[3] = 0;
4700 				ni = newnodeinst(art_openedpolygonprim, tx1,tx2, ty1,ty2, 0, 0, plotnp);
4701 				if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4702 				(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)data,
4703 					VINTEGER|VISARRAY|(4<<VLENGTHSH));
4704 				endobjectchange((INTBIG)ni, VNODEINST);
4705 
4706 				(void)esnprintf(s2, 15, x_("%g"), sim_window_get_anahigh(tr->frameno));
4707 				tx1 = sim_window_wavexnameend;   ty1 = y_max;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4708 				ni = newnodeinst(gen_invispinprim, tx1, tx1, ty1, ty1, 0, 0, plotnp);
4709 				if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4710 				var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)s2, VSTRING|VDISPLAY);
4711 				if (var != NOVARIABLE)
4712 				{
4713 					TDSETSIZE(var->textdescript, TXTSETPOINTS(10));
4714 					TDSETPOS(var->textdescript, VTPOSDOWNLEFT);
4715 				}
4716 				endobjectchange((INTBIG)ni, VNODEINST);
4717 			}
4718 		}
4719 	}
4720 
4721 	/* plot time values */
4722 	tr = sim_window_firstrace;
4723 	if (tr != NOTRACE)
4724 	{
4725 		separation = sim_window_sensibletimevalue((tr->maxtime - tr->mintime) / 5.0);
4726 		time = sim_window_sensibletimevalue(tr->maxtime);
4727 		while (time + separation <tr->maxtime)
4728 			time += separation;
4729 		for(;;)
4730 		{
4731 			if (time < tr->mintime) break;
4732 			x = sim_window_timetoxpos(time);
4733 			tx1 = x;   ty1 = 0;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4734 			ni = newnodeinst(gen_invispinprim, tx1, tx1, ty1, ty1, 0, 0, plotnp);
4735 			if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4736 			var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey,
4737 				(INTBIG)sim_windowconvertengineeringnotation(time), VSTRING|VDISPLAY);
4738 			if (var != NOVARIABLE)
4739 			{
4740 				TDSETSIZE(var->textdescript, TXTSETPOINTS(10));
4741 				TDSETPOS(var->textdescript, VTPOSUP);
4742 			}
4743 			endobjectchange((INTBIG)ni, VNODEINST);
4744 			time -= separation;
4745 		}
4746 	}
4747 
4748 	/* plot it all */
4749 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
4750 	{
4751 		if ((tr->flags&TRACENOTDRAWN) != 0) continue;
4752 		if (stopping(STOPREASONDISPLAY)) break;
4753 
4754 		/* compute positions */
4755 		slot = tr->frameno - sim_window_topframes;
4756 		if (slot < 0 || slot >= sim_window_visframes) continue;
4757 		y_min = (sim_window_visframes - 1 - slot) * temp_trace_spacing + WAVEYSIGBOT;
4758 		y_max = y_min + temp_trace_spacing - WAVEYSIGGAP;
4759 
4760 		/* draw the vertical line between the label and the trace */
4761 		tx1 = sim_window_wavexbar;   ty1 = y_min;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4762 		tx2 = sim_window_wavexbar;   ty2 = y_min+temp_trace_spacing-WAVEYSIGGAP;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4763 		data[0] = 0;   data[1] = -(ty2-ty1)/2;
4764 		data[2] = 0;   data[3] = (ty2-ty1)/2;
4765 		ni = newnodeinst(art_openedpolygonprim, tx1, tx2, ty1, ty2, 0, 0, plotnp);
4766 		if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4767 		(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)data,
4768 			VINTEGER|VISARRAY|(4<<VLENGTHSH));
4769 		endobjectchange((INTBIG)ni, VNODEINST);
4770 
4771 		/* write the text */
4772 		(void)esnprintf(s2, 15, x_("%g"), sim_window_get_anahigh(tr->frameno));
4773 		tx1 = 1;   ty1 = (y_min + y_max)/2;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4774 		ni = newnodeinst(gen_invispinprim, tx1, tx1, ty1, ty1, 0, 0, plotnp);
4775 		if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4776 		pt = tr->name;
4777 		if (sim_window_traceprefix != 0)
4778 		{
4779 			len = estrlen(sim_window_traceprefix);
4780 			if (namesamen(pt, sim_window_traceprefix, len) == 0)
4781 				pt += len;
4782 		}
4783 		var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)pt, VSTRING|VDISPLAY);
4784 		if (var != NOVARIABLE)
4785 		{
4786 			TDSETSIZE(var->textdescript, TXTSETPOINTS(10));
4787 			TDSETPOS(var->textdescript, VTPOSRIGHT);
4788 		}
4789 		endobjectchange((INTBIG)ni, VNODEINST);
4790 		if ((tr->flags&TRACETYPE) == TRACEISANALOG)
4791 		{
4792 			tx1 = 0;     ty1 = y_min + tr->nameoff;
4793 			sim_window_mapcoord(wavewin, &tx1, &ty1);
4794 			tx2 = sim_window_wavexnameendana;   ty2 = y_min + tr->nameoff;
4795 			sim_window_mapcoord(wavewin, &tx2, &ty2);
4796 			data[0] = -(tx2-tx1)/2;  data[1] = 0;
4797 			data[2] = (tx2-tx1)/2;   data[3] = 0;
4798 			ni = newnodeinst(art_openedpolygonprim, tx1, tx2, ty1, ty2, 0, 0, plotnp);
4799 			if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4800 			(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)data,
4801 				VINTEGER|VISARRAY|(4<<VLENGTHSH));
4802 			(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, tr->color, VINTEGER);
4803 			endobjectchange((INTBIG)ni, VNODEINST);
4804 		}
4805 
4806 		/* write busses */
4807 		if ((tr->flags&TRACETYPE) == TRACEISBUS ||
4808 			(tr->flags&TRACETYPE) == TRACEISOPENBUS)
4809 		{
4810 			/* enumerate signals on the bus and make sure the global array has room */
4811 			sigcount = sim_window_ensurespace(tr);
4812 
4813 			/* find starting time */
4814 			firstinbus = TRUE;
4815 			for(bustr = sim_window_firstrace; bustr != NOTRACE; bustr = bustr->nexttrace)
4816 			{
4817 				if (bustr->buschannel != tr) continue;
4818 
4819 				/* LINTED "time" used in proper order */
4820 				if (firstinbus || bustr->timearray[0] < time)
4821 					time = bustr->timearray[0];
4822 				firstinbus = FALSE;
4823 			}
4824 
4825 			/* draw the waveform */
4826 			x_min = sim_window_wavexsigstart;
4827 			for(;;)
4828 			{
4829 				/* compute signal value at time "time" */
4830 				for(bustr = sim_window_firstrace; bustr != NOTRACE; bustr = bustr->nexttrace)
4831 				{
4832 					if (bustr->buschannel != tr) continue;
4833 					for(j=0; j<bustr->numsteps; j++)
4834 						if (time < bustr->timearray[j]) break;
4835 					if (j > 0) j--;
4836 					sim_window_sigvalues[bustr->busindex] = bustr->statearray[j] >> 8;
4837 				}
4838 
4839 				/* draw the value */
4840 				x_max = sim_window_timetoxpos(time);
4841 				if (x_max < sim_window_wavexsigstart) x_max = sim_window_wavexsigstart;
4842 				if (x_max > WAVEXSIGEND) break;
4843 				if (x_max > x_min)
4844 				{
4845 					tx1 = x_min;   ty1 = y_min;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4846 					tx2 = x_max;   ty2 = y_max;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4847 					cx = (tx1 + tx2) / 2;   cy = (ty1 + ty2) / 2;
4848 					ni = newnodeinst(art_closedpolygonprim, tx1, tx2, ty1, ty2, 0, 0, plotnp);
4849 					if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4850 					busdescr[0] = x_min;           busdescr[1] = (y_min+y_max)/2;
4851 					busdescr[2] = x_min+BUSANGLE;  busdescr[3] = y_min;
4852 					busdescr[4] = x_max-BUSANGLE;  busdescr[5] = y_min;
4853 					busdescr[6] = x_max;           busdescr[7] = (y_min+y_max)/2;
4854 					busdescr[8] = x_max-BUSANGLE;  busdescr[9] = y_max;
4855 					busdescr[10] = x_min+BUSANGLE; busdescr[11] = y_max;
4856 					for(j=0; j<12; j += 2)
4857 					{
4858 						sim_window_mapcoord(wavewin, &busdescr[j], &busdescr[j+1]);
4859 						busdescr[j] -= cx;
4860 						busdescr[j+1] -= cy;
4861 					}
4862 					(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)busdescr,
4863 						VINTEGER|VISARRAY|(12<<VLENGTHSH));
4864 					endobjectchange((INTBIG)ni, VNODEINST);
4865 
4866 					/* draw the value string */
4867 					estrcpy(s2, sim_window_makewidevalue(sigcount, sim_window_sigvalues));
4868 					tx1 = x_max+BUSANGLE/2;   ty1 = (y_min+y_max)/2;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4869 					ni = newnodeinst(gen_invispinprim, tx1, tx1, ty1, ty1, 0, 0, plotnp);
4870 					if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4871 					var = setvalkey((INTBIG)ni, VNODEINST, art_messagekey, (INTBIG)s2, VSTRING|VDISPLAY);
4872 					if (var != NOVARIABLE)
4873 					{
4874 						TDSETSIZE(var->textdescript, TXTSETPOINTS(10));
4875 						TDSETPOS(var->textdescript, VTPOSRIGHT);
4876 					}
4877 					endobjectchange((INTBIG)ni, VNODEINST);
4878 					x_min = x_max;
4879 				}
4880 
4881 				/* advance to the next time */
4882 				nexttime = time;
4883 				for(bustr = sim_window_firstrace; bustr != NOTRACE; bustr = bustr->nexttrace)
4884 				{
4885 					if (bustr->buschannel != tr) continue;
4886 					for(j=0; j<bustr->numsteps; j++)
4887 						if (bustr->timearray[j] > time) break;
4888 					if (j < bustr->numsteps)
4889 					{
4890 						if (nexttime == time || bustr->timearray[j] < nexttime)
4891 							nexttime = bustr->timearray[j];
4892 					}
4893 				}
4894 				if (nexttime == time) break;
4895 				time = nexttime;
4896 			}
4897 			if (x_min < WAVEXSIGEND)
4898 			{
4899 				x_max = WAVEXSIGEND;
4900 				tx1 = x_min;   ty1 = y_min;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4901 				tx2 = x_max;   ty2 = y_max;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4902 				cx = (tx1 + tx2) / 2;   cy = (ty1 + ty2) / 2;
4903 				ni = newnodeinst(art_closedpolygonprim, tx1, tx2, ty1, ty2, 0, 0, plotnp);
4904 				if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4905 				busdescr[0] = x_min;           busdescr[1] = (y_min+y_max)/2;
4906 				busdescr[2] = x_min+BUSANGLE;  busdescr[3] = y_min;
4907 				busdescr[4] = x_max-BUSANGLE;  busdescr[5] = y_min;
4908 				busdescr[6] = x_max;           busdescr[7] = (y_min+y_max)/2;
4909 				busdescr[8] = x_max-BUSANGLE;  busdescr[9] = y_max;
4910 				busdescr[10] = x_min+BUSANGLE; busdescr[11] = y_max;
4911 				for(j=0; j<12; j += 2)
4912 				{
4913 					sim_window_mapcoord(wavewin, &busdescr[j], &busdescr[j+1]);
4914 					busdescr[j] -= cx;
4915 					busdescr[j+1] -= cy;
4916 				}
4917 				(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)busdescr,
4918 					VINTEGER|VISARRAY|(12<<VLENGTHSH));
4919 				endobjectchange((INTBIG)ni, VNODEINST);
4920 			}
4921 			continue;
4922 		}
4923 
4924 		first = 1;
4925 		datapos = 0;
4926 		lastcolor = ALLOFF;
4927 		fx = fy = 0;
4928 		laststate = -1;
4929 		for(j=0; j<tr->numsteps; j++)
4930 		{
4931 			time = tr->timearray[j];
4932 			if ((tr->flags&TRACETYPE) == TRACEISDIGITAL)
4933 			{
4934 				/* digital waveform */
4935 				if (j == tr->numsteps-1) x_max = WAVEXSIGEND; else
4936 				{
4937 					x_max = sim_window_timetoxpos(tr->timearray[j+1]);
4938 					if (x_max < sim_window_wavexsigstart) continue;
4939 				}
4940 				x_min = sim_window_timetoxpos(time);
4941 				if (x_min < sim_window_wavexsigstart) x_min = sim_window_wavexsigstart;
4942 				if (x_min > WAVEXSIGEND) continue;
4943 
4944 				strength = tr->statearray[j] & 0377;
4945 				if (strength == 0) color = sim_colorstrengthoff; else
4946 					if (strength <= NODE_STRENGTH) color = sim_colorstrengthnode; else
4947 						if (strength <= GATE_STRENGTH) color = sim_colorstrengthgate; else
4948 							color = sim_colorstrengthpower;
4949 
4950 				/* LINTED "lastcolor" used in proper order */
4951 				if (datapos > 0 && color != lastcolor)
4952 				{
4953 					/* strength has changed, dump out data so far */
4954 					tx1 = sim_window_wavexsigstart;   ty1 = WAVEYSIGBOT;    sim_window_mapcoord(wavewin, &tx1, &ty1);
4955 					tx2 = WAVEXSIGEND;                ty2 = WAVEYCURSTOP;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4956 					ni = newnodeinst(art_openedpolygonprim, tx1, tx2, ty1, ty2, 0, 0, plotnp);
4957 					if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4958 					(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)data,
4959 						VINTEGER|VISARRAY|(datapos<<VLENGTHSH));
4960 					(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, lastcolor, VINTEGER);
4961 					endobjectchange((INTBIG)ni, VNODEINST);
4962 					datapos = 0;
4963 				}
4964 				lastcolor = color;
4965 
4966 				state = tr->statearray[j] >> 8;
4967 				switch (state)
4968 				{
4969 					case LOGIC_LOW:
4970 						if (laststate == LOGIC_HIGH)
4971 							sim_window_addsegment(wavewin, data, &datapos, x_min, y_max, x_min, y_min);
4972 						sim_window_addsegment(wavewin, data, &datapos, x_min, y_min, x_max, y_min);
4973 						break;
4974 					case LOGIC_HIGH:
4975 						if (laststate == LOGIC_LOW)
4976 							sim_window_addsegment(wavewin, data, &datapos, x_min, y_min, x_min, y_max);
4977 						sim_window_addsegment(wavewin, data, &datapos, x_min, y_max, x_max, y_max);
4978 						break;
4979 					default:
4980 						if (datapos > 0)
4981 						{
4982 							/* doing unknown block, dump out any line data */
4983 							tx1 = sim_window_wavexsigstart;   ty1 = WAVEYSIGBOT;    sim_window_mapcoord(wavewin, &tx1, &ty1);
4984 							tx2 = WAVEXSIGEND;                ty2 = WAVEYCURSTOP;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4985 							ni = newnodeinst(art_openedpolygonprim, tx1, tx2, ty1, ty2, 0, 0, plotnp);
4986 							if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4987 							(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)data,
4988 								VINTEGER|VISARRAY|(datapos<<VLENGTHSH));
4989 							(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, lastcolor,
4990 								VINTEGER);
4991 							endobjectchange((INTBIG)ni, VNODEINST);
4992 						}
4993 						datapos = 0;
4994 						tx1 = x_min;   ty1 = y_min;   sim_window_mapcoord(wavewin, &tx1, &ty1);
4995 						tx2 = x_max;   ty2 = y_max;   sim_window_mapcoord(wavewin, &tx2, &ty2);
4996 						ni = newnodeinst(art_filledboxprim, tx1, tx2, ty1, ty2, 0, 0, plotnp);
4997 						if (ni == NONODEINST) { efree((CHAR *)data);  return; }
4998 						(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, lastcolor, VINTEGER);
4999 						endobjectchange((INTBIG)ni, VNODEINST);
5000 						break;
5001 				}
5002 				laststate = state;
5003 				first = 0;
5004 			} else
5005 			{
5006 				/* analog waveform */
5007 				tx = sim_window_timetoxpos(time);
5008 				position = (double)(y_max - y_min);
5009 				position *= (tr->valuearray[j] - sim_window_get_analow(tr->frameno)) / sim_window_get_anarange(tr->frameno);
5010 				ty = (INTBIG)position + y_min;
5011 				if (j != 0 && tx >= sim_window_wavexsigstart)
5012 				{
5013 					if (tx > WAVEXSIGEND)
5014 					{
5015 						/* "to" data point off the screen: interpolate */
5016 						/* LINTED "fx" and "fy" used in proper order */
5017 						ty = (ty-fy) * (WAVEXSIGEND-fx) / (tx-fx) + fy;
5018 						tx = WAVEXSIGEND;
5019 					}
5020 
5021 					if (first != 0 && fx < sim_window_wavexsigstart)
5022 					{
5023 						/* "from" data point off the screen: interpolate */
5024 						fy = (ty-fy) * (sim_window_wavexsigstart-fx) / (tx-fx) + fy;
5025 						fx = sim_window_wavexsigstart;
5026 					}
5027 					first = 0;
5028 					if (fy >= y_min && fy <= y_max &&
5029 						ty >= y_min && ty <= y_max)
5030 					{
5031 						sim_window_addsegment(wavewin, data, &datapos, fx, fy, tx, ty);
5032 					} else
5033 					{
5034 						cfx = fx;   cfy = fy;
5035 						ctx = tx;   cty = ty;
5036 						if (!clipline(&cfx, &cfy, &ctx, &cty, sim_window_wavexsigstart, WAVEXSIGEND, y_min, y_max))
5037 						{
5038 							sim_window_addsegment(wavewin, data, &datapos, cfx, cfy, ctx, cty);
5039 						}
5040 					}
5041 				}
5042 				fx = tx;   fy = ty;
5043 				if (fx >= WAVEXSIGEND) break;
5044 			}
5045 		}
5046 		if (datapos > 0)
5047 		{
5048 			tx1 = sim_window_wavexsigstart;   ty1 = WAVEYSIGBOT;    sim_window_mapcoord(wavewin, &tx1, &ty1);
5049 			tx2 = WAVEXSIGEND;                ty2 = WAVEYCURSTOP;   sim_window_mapcoord(wavewin, &tx2, &ty2);
5050 			ni = newnodeinst(art_openedpolygonprim, tx1, tx2, ty1, ty2, 0, 0, plotnp);
5051 			if (ni == NONODEINST) { efree((CHAR *)data);  return; }
5052 			(void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)data,
5053 				VINTEGER|VISARRAY|(datapos<<VLENGTHSH));
5054 			if ((tr->flags&TRACETYPE) == TRACEISANALOG)
5055 				(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, tr->color, VINTEGER); else
5056 					(void)setvalkey((INTBIG)ni, VNODEINST, art_colorkey, lastcolor, VINTEGER);
5057 			endobjectchange((INTBIG)ni, VNODEINST);
5058 		}
5059 	}
5060 
5061 	/* ensure that the cell has the right size */
5062 	(*el_curconstraint->solve)(plotnp);
5063 
5064 	/* clean up */
5065 	ttyputmsg(x_("Created cell %s"), describenodeproto(plotnp));
5066 	efree((CHAR *)data);
5067 }
5068 
5069 /*
5070  * Set the display color for strength "strength" to "color".
5071  */
sim_window_setdisplaycolor(INTBIG strength,INTBIG color)5072 void sim_window_setdisplaycolor(INTBIG strength, INTBIG color)
5073 {
5074 	if (strength == LOGIC_LOW)
5075 	{
5076 		if (color != sim_colorlevellow)
5077 			(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorlevellow_key, color, VINTEGER);
5078 	} else if (strength == LOGIC_HIGH)
5079 	{
5080 		if (color != sim_colorlevelhigh)
5081 			(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorlevelhigh_key, color, VINTEGER);
5082 	} else if (strength == LOGIC_X)
5083 	{
5084 		if (color != sim_colorlevelundef)
5085 			(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorlevelundef_key, color, VINTEGER);
5086 	} else if (strength == LOGIC_Z)
5087 	{
5088 		if (color != sim_colorlevelzdef)
5089 			(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorlevelzdef_key, color, VINTEGER);
5090 	} else if (strength == OFF_STRENGTH)
5091 	{
5092 		if (color != sim_colorstrengthoff)
5093 			(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorstrengthoff_key, color, VINTEGER);
5094 	} else if (strength <= NODE_STRENGTH)
5095 	{
5096 		if (color != sim_colorstrengthnode)
5097 			(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorstrengthnode_key, color, VINTEGER);
5098 	} else if (strength <= GATE_STRENGTH)
5099 	{
5100 		if (color != sim_colorstrengthgate)
5101 			(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorstrengthgate_key, color, VINTEGER);
5102 	} else if (strength <= VDD_STRENGTH)
5103 	{
5104 		if (color != sim_colorstrengthpower)
5105 			(void)setvalkey((INTBIG)sim_tool, VTOOL, sim_colorstrengthpower_key, color, VINTEGER);
5106 	}
5107 }
5108 
5109 /*
5110  * Returns the display color for strength "strength".
5111  */
sim_window_getdisplaycolor(INTBIG strength)5112 INTBIG sim_window_getdisplaycolor(INTBIG strength)
5113 {
5114 	if (strength == LOGIC_LOW) return(sim_colorlevellow);
5115 	if (strength == LOGIC_HIGH) return(sim_colorlevelhigh);
5116 	if (strength == LOGIC_X) return(sim_colorlevelundef);
5117 	if (strength == LOGIC_Z) return(sim_colorlevelzdef);
5118 	if (strength == OFF_STRENGTH) return(sim_colorstrengthoff);
5119 	if (strength <= NODE_STRENGTH) return(sim_colorstrengthnode);
5120 	if (strength <= GATE_STRENGTH) return(sim_colorstrengthgate);
5121 	if (strength <= VDD_STRENGTH) return(sim_colorstrengthpower);
5122 	return(0);
5123 }
5124 
sim_window_addsegment(WINDOWPART * wavewin,INTBIG * data,INTBIG * datapos,INTBIG fx,INTBIG fy,INTBIG tx,INTBIG ty)5125 void sim_window_addsegment(WINDOWPART *wavewin, INTBIG *data, INTBIG *datapos, INTBIG fx, INTBIG fy,
5126 	INTBIG tx, INTBIG ty)
5127 {
5128 	REGISTER INTBIG truefx, truefy, pos;
5129 	INTBIG x, y;
5130 
5131 	x = fx;   y = fy;   sim_window_mapcoord(wavewin, &x, &y);
5132 	truefx = (x-sim_window_basex) - sim_window_offx;
5133 	truefy = (y-sim_window_basey) - sim_window_offy;
5134 
5135 	pos = *datapos;
5136 	if (pos < 2 || data[pos-2] != truefx || data[pos-1] != truefy)
5137 	{
5138 		data[pos++] = truefx;
5139 		data[pos++] = truefy;
5140 	}
5141 
5142 	x = tx;   y = ty;   sim_window_mapcoord(wavewin, &x, &y);
5143 	data[pos++] = (x-sim_window_basex) - sim_window_offx;
5144 	data[pos++] = (y-sim_window_basey) - sim_window_offy;
5145 	*datapos = pos;
5146 }
5147 
5148 #define SIMSTEPSIZE 1e-11f
5149 #define EDGERATE    3e-11f
5150 #define SUPPLY      1.8
5151 
5152 /*
5153  * Routine to dump vectors in SPICE format.
5154  */
sim_window_writespicecmd(void)5155 void sim_window_writespicecmd(void)
5156 {
5157 	FILE *fptr;
5158 	int j, state, prevstate;
5159 	double simDuration;
5160 	CHAR hvar[80], *pt;
5161 	REGISTER TRACE *tr;
5162 	REGISTER NETWORK *net, **netlist;
5163 	REGISTER PORTPROTO *pp;
5164 	REGISTER NODEPROTO *cell, *simnt;
5165 	REGISTER WINDOWPART *schemwin;
5166 
5167 	/* get cell being saved */
5168 	cell = getcurcell();
5169 	if (cell == NONODEPROTO) return;
5170 	schemwin = sim_window_findschematics();
5171 	if (schemwin == NOWINDOWPART)
5172 	{
5173 		ttyputerr(_("Must have original schematics or layout circuit as well as waveform"));
5174 		return;
5175 	}
5176 	simnt = schemwin->curnodeproto;
5177 
5178 	/* SPICE command file named fname.cmd.sp */
5179 	fptr = xcreate(cell->protoname, sim_filetypespicecmd, _("SPICE Command File"), &pt);
5180 	if (fptr == NULL) return;
5181 	ttyputmsg(_("Writing %s"), pt);
5182 
5183 	/* Initialize variables */
5184 	simDuration = 0.0;
5185 
5186 	/* Create the SPICE command file */
5187 	efprintf(fptr, x_("* %s\n"), pt);
5188 	efprintf(fptr, x_("* SPICE command file for cell %s from library %s\n"),
5189 		describenodeproto(cell), cell->lib->libname);
5190 	us_emitcopyright(fptr, x_("* "), x_(""));
5191 	if ((us_useroptions&NODATEORVERSION) == 0)
5192 	{
5193 		(void)esnprintf(hvar, 80, x_("%s"), timetostring(getcurrenttime()));
5194 		efprintf(fptr, x_("* Written on %s by Electric VLSI Design System, %s\n\n"),
5195 			hvar, el_version);
5196 	} else
5197 	{
5198 		efprintf(fptr, x_("* Written by Electric VLSI Design System\n\n"));
5199 	}
5200 
5201 	efprintf(fptr, x_(".include %s.spi\n\n"), cell->protoname);
5202 
5203 	efprintf(fptr, x_("* Power Supply\n"));
5204 	efprintf(fptr, x_(".param SUPPLY=%g\n"), SUPPLY);
5205 	efprintf(fptr, x_("VVDD VDD GND SUPPLY\n\n"));
5206 
5207 	efprintf(fptr, x_("* Inputs\n"));
5208 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
5209 	{
5210 		/* only interested in digital traces with information on them */
5211 		if ((tr->flags&TRACETYPE) != TRACEISDIGITAL) continue;
5212 		if (tr->numsteps <= 0) continue;
5213 
5214 		/* find the export associated with this signal */
5215 		netlist = getcomplexnetworks(tr->name, simnt);
5216 		net = netlist[0];
5217 		if (net == NONETWORK || netlist[1] != NONETWORK) continue;
5218 		for(pp = simnt->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
5219 			if (pp->network == net) break;
5220 		if (pp == NOPORTPROTO) continue;
5221 
5222 		/* dump information for input and bidirectional exports */
5223 		if ((pp->userbits&STATEBITS) == INPORT ||
5224 			(pp->userbits&STATEBITS) == BIDIRPORT)
5225 		{
5226 			efprintf(fptr, x_("V%s %s GND PWL "), tr->name, tr->name);
5227 			for(j=0; j<tr->numsteps; j++)
5228 			{
5229 				state = tr->statearray[j] >> 8;
5230 				if (j == 0)
5231 				{
5232 					efprintf(fptr, x_("0 %s "), (state==LOGIC_HIGH) ? x_("SUPPLY") : x_("0"));
5233 				} else
5234 				{
5235 					pt = displayedunits((float)tr->timearray[j], VTUNITSTIME, INTTIMEUNITNSEC);
5236 					efprintf(fptr, x_("%s %s "), pt, (prevstate==LOGIC_HIGH) ? x_("SUPPLY") : x_("0"));
5237 				}
5238 				if (tr->timearray[j] > 0)
5239 				{
5240 					pt = displayedunits((float)tr->timearray[j]+EDGERATE, VTUNITSTIME, INTTIMEUNITNSEC);
5241 					efprintf(fptr, x_("%s %s "), pt, (state==LOGIC_HIGH) ? x_("SUPPLY") : x_("0"));
5242 				}
5243 				prevstate = state;
5244 				if (tr->timearray[j] > simDuration) simDuration = tr->timearray[j];
5245 			}
5246 			efprintf(fptr, x_("\n"));
5247 		}
5248 		efprintf(fptr, x_("R%s %s GND 1G\n"), tr->name, tr->name);
5249 	}
5250 	efprintf(fptr, x_("\n"));
5251 
5252 	efprintf(fptr, x_("* Simulation Commands\n"));
5253 	efprintf(fptr, x_(".options post\n"));
5254 	estrcpy(hvar, displayedunits(SIMSTEPSIZE, VTUNITSTIME, INTTIMEUNITNSEC));
5255 	pt = displayedunits((float)simDuration+30.0f*EDGERATE, VTUNITSTIME, INTTIMEUNITNSEC);
5256 	efprintf(fptr, x_(".tran %s %s\n"), hvar, pt);
5257 	efprintf(fptr, x_(".end\n"));
5258 	xclose(fptr);
5259 }
5260 
5261 /*
5262  * Routine to remove trace "tr" from the waveform window's linked list.
5263  */
sim_window_removetrace(TRACE * tr)5264 void sim_window_removetrace(TRACE *tr)
5265 {
5266 	TRACE *lasttr, *otr;
5267 
5268 	lasttr = NOTRACE;
5269 	for(otr = sim_window_firstrace; otr != NOTRACE; otr = otr->nexttrace)
5270 	{
5271 		if (otr == tr) break;
5272 		lasttr = otr;
5273 	}
5274 	if (lasttr == NOTRACE) sim_window_firstrace = tr->nexttrace; else
5275 		lasttr->nexttrace = tr->nexttrace;
5276 }
5277 
5278 /*
5279  * Routine to renumber the traces in the window.
5280  */
sim_window_renumberlines(void)5281 void sim_window_renumberlines(void)
5282 {
5283 	REGISTER INTBIG i, lastframeno;
5284 	REGISTER TRACE *tr, *otr;
5285 
5286 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
5287 		tr->flags &= ~TRACEMARK;
5288 	i = 0;
5289 	for(tr = sim_window_firstrace; tr != NOTRACE; tr = tr->nexttrace)
5290 	{
5291 		if ((tr->flags&TRACENOTDRAWN) != 0) {tr->frameno = -1;   continue; }
5292 		if ((tr->flags&TRACEMARK) != 0) continue;
5293 		lastframeno = tr->frameno;
5294 		tr->frameno = i;
5295 		tr->flags |= TRACEMARK;
5296 		for(otr = tr->nexttrace; otr != NOTRACE; otr = otr->nexttrace)
5297 		{
5298 			if ((otr->flags&TRACENOTDRAWN) != 0) {otr->frameno = -1;   continue; }
5299 			if (otr->frameno != lastframeno) continue;
5300 			otr->frameno = i;
5301 			otr->flags |= TRACEMARK;
5302 		}
5303 		i++;
5304 	}
5305 
5306 	(void)sim_window_set_frames(i);
5307 	sim_window_auto_anarange();
5308 }
5309 
5310 /*
5311  * Routine to insert trace "tr" after "aftertr" in the waveform window's linked list.
5312  */
sim_window_addtrace(TRACE * tr,TRACE * aftertr)5313 void sim_window_addtrace(TRACE *tr, TRACE *aftertr)
5314 {
5315 	if (aftertr == NOTRACE)
5316 	{
5317 		tr->nexttrace = sim_window_firstrace;
5318 		sim_window_firstrace = tr;
5319 	} else
5320 	{
5321 		tr->nexttrace = aftertr->nexttrace;
5322 		aftertr->nexttrace = tr;
5323 	}
5324 }
5325 
sim_window_alloctrace(void)5326 TRACE *sim_window_alloctrace(void)
5327 {
5328 	REGISTER TRACE *tr;
5329 
5330 	if (sim_window_tracefree == NOTRACE)
5331 	{
5332 		tr = (TRACE *)emalloc(sizeof (TRACE), sim_tool->cluster);
5333 		if (tr == 0) return(0);
5334 	} else
5335 	{
5336 		tr = sim_window_tracefree;
5337 		sim_window_tracefree = tr->nexttrace;
5338 	}
5339 	tr->flags = 0;
5340 	tr->timelimit = 0;
5341 	tr->statelimit = 0;
5342 	tr->valuelimit = 0;
5343 	tr->numsteps = 0;
5344 	tr->nameoff = 0;
5345 	tr->statearray = 0;
5346 	tr->buschannel = NOTRACE;
5347 	return(tr);
5348 }
5349 
5350 /********************************* LOW LEVEL GRAPHICS *********************************/
5351 
sim_window_setviewport(WINDOWPART * w)5352 void sim_window_setviewport(WINDOWPART *w)
5353 {
5354 	float scalex, scaley;
5355 	REGISTER INTBIG maxlines;
5356 
5357 	w->screenlx = 0;   w->screenhx = WAVEXSIGEND;
5358 	w->screenly = 0;   w->screenhy = WAVEYTEXTTOP;
5359 	computewindowscale(w);
5360 
5361 	scalex = (w->usehx - w->uselx) / (float)WAVEXSIGEND;
5362 	scaley = ((w->usehy-20) - w->usely) / (float)WAVEYTEXTTOP;
5363 	if (scalex > 2.0 && scaley > 2.0) sim_window_textsize = 0; else
5364 		if (scalex > 1.0 && scaley > 1.0) sim_window_textsize = 16; else
5365 			sim_window_textsize = 12;
5366 
5367 	maxlines = ((w->usehy - w->usely) * WAVEYSIGRANGE / WAVEYTEXTTOP) / 25;
5368 	if (maxlines != sim_window_visframes)
5369 	{
5370 		if (sim_window_lines > sim_window_visframes)
5371 			sim_window_visframes = sim_window_lines;
5372 		if (sim_window_visframes > maxlines)
5373 			sim_window_visframes = maxlines;
5374 	}
5375 }
5376 
5377 /*
5378  * Routine to return the WINDOWPART that has the waveform display
5379  */
sim_window_findwaveform(void)5380 WINDOWPART *sim_window_findwaveform(void)
5381 {
5382 	WINDOWPART *w;
5383 
5384 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
5385 		if ((w->state & WINDOWTYPE) == WAVEFORMWINDOW)
5386 			return(w);
5387 	return(NOWINDOWPART);
5388 }
5389 
5390 /*
5391  * Routine to return the WINDOWPART that has the schematics/layout being simulated
5392  */
sim_window_findschematics(void)5393 WINDOWPART *sim_window_findschematics(void)
5394 {
5395 	WINDOWPART *w;
5396 	INTBIG state;
5397 
5398 	for(w = el_topwindowpart; w != NOWINDOWPART; w = w->nextwindowpart)
5399 	{
5400 		state = w->state & (WINDOWTYPE|WINDOWSIMMODE);
5401 		if (state == (DISPWINDOW|WINDOWSIMMODE) ||
5402 			state == (DISP3DWINDOW|WINDOWSIMMODE))
5403 				return(w);
5404 	}
5405 	return(NOWINDOWPART);
5406 }
5407 
sim_window_mapcoord(WINDOWPART * w,INTBIG * x,INTBIG * y)5408 void sim_window_mapcoord(WINDOWPART *w, INTBIG *x, INTBIG *y)
5409 {
5410 	REGISTER INTBIG newx, newy;
5411 
5412 	newx = w->uselx + applyxscale(w, *x - w->screenlx);
5413 	newy = w->usely + (*y - w->screenly) *
5414 		((w->usehy-20) - (w->usely)) / (w->screenhy - w->screenly);
5415 	*x = newx;   *y = newy;
5416 }
5417 
sim_window_scaletowindow(WINDOWPART * w,INTBIG * x,INTBIG * y)5418 void sim_window_scaletowindow(WINDOWPART *w, INTBIG *x, INTBIG *y)
5419 {
5420 	*x = muldiv(*x - w->uselx, w->screenhx - w->screenlx,
5421 		w->usehx - w->uselx) + w->screenlx;
5422 	*y = muldiv(*y - w->usely, w->screenhy - w->screenly,
5423 		(w->usehy-20) - w->usely) + w->screenly;
5424 }
5425 
5426 /* Some Control Sequences for the graphics terminal */
sim_window_setcolor(INTBIG color)5427 void sim_window_setcolor(INTBIG color)
5428 {
5429 	sim_window_desc.col = color;
5430 }
5431 
sim_window_setmask(INTBIG mask)5432 void sim_window_setmask(INTBIG mask)
5433 {
5434 	sim_window_desc.bits = mask;
5435 }
5436 
5437 /* Graphics Commands */
sim_window_moveto(INTBIG x,INTBIG y)5438 void sim_window_moveto(INTBIG x, INTBIG y)
5439 {
5440 	sim_window_curx = x;
5441 	sim_window_cury = y;
5442 }
5443 
sim_window_drawto(WINDOWPART * w,INTBIG x,INTBIG y,INTBIG texture)5444 void sim_window_drawto(WINDOWPART *w, INTBIG x, INTBIG y, INTBIG texture)
5445 {
5446 	INTBIG fx, fy, tx, ty, cfx, cfy, ctx, cty;
5447 
5448 	fx = sim_window_curx;   fy = sim_window_cury;
5449 	tx = x;   ty = y;
5450 	sim_window_mapcoord(w, &fx, &fy);
5451 	sim_window_mapcoord(w, &tx, &ty);
5452 	cfx = fx;   cfy = fy;
5453 	ctx = tx;   cty = ty;
5454 	if (!clipline(&cfx, &cfy, &ctx, &cty, w->uselx, w->usehx, w->usely, w->usehy))
5455 	{
5456 		fx = cfx;   fy = cfy;
5457 		tx = ctx;   ty = cty;
5458 		screendrawline(w, fx, fy, tx, ty, &sim_window_desc, texture);
5459 	}
5460 	sim_window_curx = x;
5461 	sim_window_cury = y;
5462 }
5463 
5464 /*
5465  * Routine to draw from "xll" to "xur" and from "yll" to "yur" in window "w".  "style" is:
5466  *  0 to draw solid
5467  *  1 to draw texture
5468  *  2 to draw solid but expand the Y values by 1 pixel
5469  */
sim_window_drawbox(WINDOWPART * w,INTBIG xll,INTBIG yll,INTBIG xur,INTBIG yur,INTBIG style)5470 void sim_window_drawbox(WINDOWPART *w, INTBIG xll, INTBIG yll, INTBIG xur, INTBIG yur, INTBIG style)
5471 {
5472 	INTBIG lx, ly, hx, hy, swap;
5473 
5474 	lx = xll;   ly = yll;
5475 	hx = xur;   hy = yur;
5476 	sim_window_mapcoord(w, &lx, &ly);
5477 	sim_window_mapcoord(w, &hx, &hy);
5478 	if (lx > hx) { swap = lx;   lx = hx;   hx = swap; }
5479 	if (ly > hy) { swap = ly;   ly = hy;   hy = swap; }
5480 	if (style == 1)
5481 	{
5482 		sim_window_udesc.bits = sim_window_desc.bits;
5483 		sim_window_udesc.col = sim_window_desc.col;
5484 		screendrawbox(w, lx, hx, ly, hy, &sim_window_udesc);
5485 	} else
5486 	{
5487 		if (style == 2)
5488 		{
5489 			ly--;   hy++;
5490 		}
5491 		screendrawbox(w, lx, hx, ly, hy, &sim_window_desc);
5492 	}
5493 }
5494 
5495 /*
5496  * Routine to draw string "s" in window "w" with highlighting and by erasing what
5497  * is underneath first
5498  */
sim_window_drawhcstring(WINDOWPART * w,CHAR * s)5499 void sim_window_drawhcstring(WINDOWPART *w, CHAR *s)
5500 {
5501 	INTBIG xw, yw, oldcol, oldmask;
5502 	INTBIG px, py;
5503 	UINTBIG descript[TEXTDESCRIPTSIZE];
5504 
5505 	px = sim_window_curx;   py = sim_window_cury;
5506 	sim_window_mapcoord(w, &px, &py);
5507 
5508 	TDCLEAR(descript);
5509 	TDSETSIZE(descript, TXTSETPOINTS(sim_window_textsize));
5510 	screensettextinfo(w, NOTECHNOLOGY, descript);
5511 	screengettextsize(w, s, &xw, &yw);
5512 	py -= yw/2;
5513 
5514 	/* erase the area underneath */
5515 	oldcol = sim_window_desc.col;
5516 	oldmask = sim_window_desc.bits;
5517 	sim_window_desc.col = ALLOFF;
5518 	sim_window_desc.bits = LAYERA;
5519 	screendrawbox(w, px, px+xw, py, py+yw, &sim_window_desc);
5520 	sim_window_desc.col = oldcol;
5521 	sim_window_desc.bits = oldmask;
5522 
5523 	/* draw the text */
5524 	screendrawtext(w, px, py, s, &sim_window_desc);
5525 }
5526 
sim_window_drawcstring(WINDOWPART * w,CHAR * s)5527 void sim_window_drawcstring(WINDOWPART *w, CHAR *s)
5528 {
5529 	INTBIG wid, hei;
5530 	INTBIG px, py;
5531 	UINTBIG descript[TEXTDESCRIPTSIZE];
5532 
5533 	px = sim_window_curx;   py = sim_window_cury;
5534 	sim_window_mapcoord(w, &px, &py);
5535 	TDCLEAR(descript);
5536 	TDSETSIZE(descript, TXTSETPOINTS(sim_window_textsize));
5537 	screensettextinfo(w, NOTECHNOLOGY, descript);
5538 	screengettextsize(w, s, &wid, &hei);
5539 	screendrawtext(w, px-wid/2, py, s, &sim_window_desc);
5540 }
5541 
sim_window_drawulstring(WINDOWPART * w,CHAR * s)5542 void sim_window_drawulstring(WINDOWPART *w, CHAR *s)
5543 {
5544 	INTBIG wid, hei;
5545 	INTBIG px, py;
5546 	UINTBIG descript[TEXTDESCRIPTSIZE];
5547 
5548 	px = sim_window_curx;   py = sim_window_cury;
5549 	sim_window_mapcoord(w, &px, &py);
5550 	TDCLEAR(descript);
5551 	TDSETSIZE(descript, TXTSETPOINTS(sim_window_textsize));
5552 	screensettextinfo(w, NOTECHNOLOGY, descript);
5553 	screengettextsize(w, s, &wid, &hei);
5554 	screendrawtext(w, px, py-hei, s, &sim_window_desc);
5555 }
5556 
5557 /*
5558  * Name: sim_windowconvertengineeringnotation
5559  *
5560  * Description:
5561  *	This procedure converts a floating point number and represents time
5562  * in engineering units such as pico, micro, milli, etc.
5563  *
5564  * Calling Arguments:
5565  *	time = floating point value to be converted to Engineering notation
5566  *	s1   = pointer to a string that will be used to print the converted value
5567  */
sim_windowconvertengineeringnotation(double time)5568 CHAR *sim_windowconvertengineeringnotation(double time)
5569 {
5570 	REGISTER INTBIG timeleft, timeright;
5571 	double scaled;
5572 	INTBIG inttime;
5573 	CHAR *sectype;
5574 	REGISTER CHAR *negative;
5575 	static CHAR s1[50];
5576 
5577 	negative = x_("");
5578 	if (time < 0.0)
5579 	{
5580 		negative = x_("-");
5581 		time = - time;
5582 	}
5583 	if (doublesequal(time, 0.0))
5584 	{
5585 		(void)esnprintf(s1, 50, x_("0 %s"), _("s"));
5586 		return(s1);
5587 	}
5588 	if (time < 1.0E-15 || time >= 1000.0)
5589 	{
5590 		(void)esnprintf(s1, 50, x_("%s%g%s"), negative, time, _("s"));
5591 		return(s1);
5592 	}
5593 
5594 	/* get proper time unit to use */
5595 	scaled = time * 1.0E17;   inttime = rounddouble(scaled);
5596 	if (scaled < 200000.0 && inttime < 100000)
5597 	{
5598 		sectype = _("fs");
5599 	} else
5600 	{
5601 		scaled = time * 1.0E14;   inttime = rounddouble(scaled);
5602 		if (scaled < 200000.0 && inttime < 100000)
5603 		{
5604 			sectype = _("ps");
5605 		} else
5606 		{
5607 			scaled = time * 1.0E11;   inttime = rounddouble(scaled);
5608 			if (scaled < 200000.0 && inttime < 100000)
5609 			{
5610 				sectype = _("ns");
5611 			} else
5612 			{
5613 				scaled = time * 1.0E8;   inttime = rounddouble(scaled);
5614 				if (scaled < 200000.0 && inttime < 100000)
5615 				{
5616 					sectype = _("us");
5617 				} else
5618 				{
5619 					scaled = time * 1.0E5;   inttime = rounddouble(scaled);
5620 					if (scaled < 200000.0 && inttime < 100000)
5621 					{
5622 						sectype = _("ms");
5623 					} else
5624 					{
5625 						inttime = rounddouble(time * 1.0E2);
5626 						sectype = _("s");
5627 					}
5628 				}
5629 			}
5630 		}
5631 	}
5632 	timeleft = inttime / 100;
5633 	timeright = inttime % 100;
5634 	if (timeright == 0)
5635 	{
5636 		(void)esnprintf(s1, 50, x_("%s%ld%s"), negative, timeleft, sectype);
5637 	} else
5638 	{
5639 		if ((timeright%10) == 0)
5640 		{
5641 			(void)esnprintf(s1, 50, x_("%s%ld.%ld%s"), negative, timeleft, timeright/10, sectype);
5642 		} else
5643 		{
5644 			(void)esnprintf(s1, 50, x_("%s%ld.%02ld%s"), negative, timeleft, timeright, sectype);
5645 		}
5646 	}
5647 	return(s1);
5648 }
5649 
5650 /*
5651  * Name: sim_windowconvertengineeringnotation2
5652  *
5653  * Description:
5654  *	This procedure converts a floating point number and represents time
5655  * in engineering units such as pico, micro, milli, etc.
5656  *
5657  * Calling Arguments:
5658  *	time = floating point value to be converted to Engineering notation
5659  *  precpower = decimal power of necessary time precision
5660  *	s1   = pointer to a string that will be used to print the converted value
5661  */
sim_windowconvertengineeringnotation2(double time,INTBIG precpower)5662 CHAR *sim_windowconvertengineeringnotation2(double time, INTBIG precpower)
5663 {
5664 	REGISTER INTBIG timeleft, timeright;
5665 	double scaled;
5666 	INTBIG inttime;
5667 	CHAR *sectype;
5668 	REGISTER CHAR *negative;
5669 	INTBIG scalepower;
5670 	static CHAR s1[50];
5671 
5672 	negative = x_("");
5673 	if (time < 0.0)
5674 	{
5675 		negative = x_("-");
5676 		time = - time;
5677 	}
5678 	if (doublesequal(time, 0.0))
5679 	{
5680 		(void)esnprintf(s1, 50, x_("0 %s"), _("s"));
5681 		return(s1);
5682 	}
5683 	if (time < 1.0E-15 || time >= 1000.0)
5684 	{
5685 		(void)esnprintf(s1, 50, x_("%s%g%s"), negative, time, _("s"));
5686 		return(s1);
5687 	}
5688 
5689 	/* get proper time unit to use */
5690 	scaled = time * 1.0E17;   inttime = rounddouble(scaled);
5691 	if (scaled < 200000.0 && inttime < 100000)
5692 	{
5693 		sectype = _("fs");
5694 		scalepower = -15;
5695 	} else
5696 	{
5697 		scaled = time * 1.0E14;   inttime = rounddouble(scaled);
5698 		if (scaled < 200000.0 && inttime < 100000)
5699 		{
5700 			sectype = _("ps");
5701 			scalepower = -12;
5702 		} else
5703 		{
5704 			scaled = time * 1.0E11;   inttime = rounddouble(scaled);
5705 			if (scaled < 200000.0 && inttime < 100000)
5706 			{
5707 				sectype = _("ns");
5708 				scalepower = -9;
5709 			} else
5710 			{
5711 				scaled = time * 1.0E8;   inttime = rounddouble(scaled);
5712 				if (scaled < 200000.0 && inttime < 100000)
5713 				{
5714 					sectype = _("us");
5715 					scalepower = -6;
5716 				} else
5717 				{
5718 					scaled = time * 1.0E5;   inttime = rounddouble(scaled);
5719 					if (scaled < 200000.0 && inttime < 100000)
5720 					{
5721 						sectype = _("ms");
5722 						scalepower = -3;
5723 					} else
5724 					{
5725 						scaled = time * 1.0E2;  inttime = rounddouble(scaled);
5726 						sectype = _("s");
5727 						scalepower = 0;
5728 					}
5729 				}
5730 			}
5731 		}
5732 	}
5733 	if (precpower < scalepower)
5734 	{
5735 		scaled /= 1.0E2;
5736 		esnprintf(s1, 50, x_("%s%.*f%s"), negative, (int)(scalepower - precpower), scaled, sectype);
5737 	} else
5738 	{
5739 		timeleft = inttime / 100;
5740 		timeright = inttime % 100;
5741 		if (timeright == 0)
5742 		{
5743 			(void)esnprintf(s1, 50, x_("%s%ld%s"), negative, timeleft, sectype);
5744 		} else
5745 		{
5746 			if ((timeright%10) == 0)
5747 			{
5748 				(void)esnprintf(s1, 50, x_("%s%ld.%ld%s"), negative, timeleft, timeright/10, sectype);
5749 			} else
5750 			{
5751 				(void)esnprintf(s1, 50, x_("%s%ld.%02ld%s"), negative, timeleft, timeright, sectype);
5752 			}
5753 		}
5754 	}
5755 	return(s1);
5756 }
5757 
5758 /*
5759  * Routine to look at the "count" signal values in "value" and convert them to a readable
5760  * value in the current simulation display base.
5761  */
sim_window_makewidevalue(INTBIG count,INTBIG * value)5762 CHAR *sim_window_makewidevalue(INTBIG count, INTBIG *value)
5763 {
5764 	REGISTER INTBIG i, j, k, val, base, groupsize;
5765 	INTHUGE bigval;
5766 	static CHAR s2[MAXSIMWINDOWBUSWIDTH+3];
5767 	static CHAR *hexstring = x_("0123456789ABCDEF");
5768 
5769 	/* if any values are undefined, the result is "XX" */
5770 	for(i=0; i<count; i++)
5771 		if (value[i] != LOGIC_LOW && value[i] != LOGIC_HIGH) return(x_("XX"));
5772 
5773 	/* bases 2, 8 and 16 are simple */
5774 	base = sim_window_state & BUSBASEBITS;
5775 	if (base == BUSBASE10 && count > 64) base = BUSBASE16;
5776 	if (base == BUSBASE2 || base == BUSBASE8 || base == BUSBASE16)
5777 	{
5778 		switch (base)
5779 		{
5780 			case BUSBASE2:  groupsize = 1;   break;
5781 			case BUSBASE8:  groupsize = 3;   break;
5782 			case BUSBASE16: groupsize = 4;   break;
5783 			default: return(0);
5784 		}
5785 		j = MAXSIMWINDOWBUSWIDTH+3;
5786 		s2[--j] = 0;
5787 		for(i = count-1; i >= 0; i -= groupsize)
5788 		{
5789 			val = 0;
5790 			for(k=0; k<groupsize; k++)
5791 			{
5792 				if (i-k < 0) break;
5793 				if (value[i-k] == LOGIC_HIGH) val |= (1<<k);
5794 			}
5795 			s2[--j] = hexstring[val];
5796 		}
5797 		switch (base)
5798 		{
5799 			case BUSBASE2:  s2[--j] = 'b';  s2[--j] = '0';   break;
5800 			case BUSBASE8:  s2[--j] = '0';                   break;
5801 			case BUSBASE16: s2[--j] = 'x';  s2[--j] = '0';   break;
5802 		}
5803 		return(&s2[j]);
5804 	}
5805 
5806 	bigval = 0;
5807 	for(i=0; i<count; i++)
5808 	{
5809 		bigval <<= 1;
5810 		if (value[i] == LOGIC_HIGH) bigval |= 1;
5811 	}
5812 	return(hugeinttoa(bigval));
5813 }
5814 
5815 /* Simulation: Wide Value */
5816 static DIALOGITEM sim_widedialogitems[] =
5817 {
5818  /*  1 */ {0, {48,188,72,268}, BUTTON, N_("OK")},
5819  /*  2 */ {0, {12,188,36,268}, BUTTON, N_("Cancel")},
5820  /*  3 */ {0, {8,8,24,168}, MESSAGE, N_("Value to set on bus:")},
5821  /*  4 */ {0, {32,8,48,168}, EDITTEXT, x_("")},
5822  /*  5 */ {0, {56,8,72,72}, MESSAGE, N_("Base:")},
5823  /*  6 */ {0, {56,76,72,144}, POPUP, x_("")}
5824 };
5825 static DIALOG sim_widedialog = {{75,75,156,352}, N_("Set Wide Value"), 0, 6, sim_widedialogitems, 0, 0};
5826 
5827 /* special items for the "wide value" dialog: */
5828 #define DSWV_VALUE     4		/* value (edit text) */
5829 #define DSWV_BASE      6		/* base (popup) */
5830 
5831 /*
5832  * Routine to prompt for a wide value and return the number of bits.
5833  * The bit values are stored in "bits".
5834  * Returns negative on abort/error.
5835  */
sim_window_getwidevalue(INTBIG ** bits)5836 INTBIG sim_window_getwidevalue(INTBIG **bits)
5837 {
5838 	REGISTER INTBIG i, j, itemHit, groupsize, testbit, val;
5839 	REGISTER UINTHUGE bigval, bigtestbit;
5840 	REGISTER CHAR *pt, chr;
5841 	REGISTER void *dia;
5842 	static INTBIG theBits[MAXSIMWINDOWBUSWIDTH];
5843 	static INTBIG lastbase = 2;
5844 	static CHAR *base[4] = {x_("2"), x_("8"), x_("10"), x_("16")};
5845 
5846 	dia = DiaInitDialog(&sim_widedialog);
5847 	if (dia == 0) return(-1);
5848 	DiaSetPopup(dia, DSWV_BASE, 4, base);
5849 	DiaSetPopupEntry(dia, DSWV_BASE, lastbase);
5850 	DiaSetText(dia, -DSWV_VALUE, x_("0"));
5851 	for(;;)
5852 	{
5853 		itemHit = DiaNextHit(dia);
5854 		if (itemHit == OK || itemHit == CANCEL) break;
5855 	}
5856 	lastbase = DiaGetPopupEntry(dia, DSWV_BASE);
5857 	if (lastbase == 2)
5858 	{
5859 		/* base 10 is special */
5860 		bigval = 0;
5861 		for(pt = DiaGetText(dia, DSWV_VALUE); *pt != 0; pt++)
5862 		{
5863 			if (!isdigit(*pt)) break;
5864 			bigval = bigval * 10 + (*pt - '0');
5865 		}
5866 		bigtestbit = INTHUGECONST(0x8000000000000000);
5867 		for(i=0; i<64; i++)
5868 		{
5869 			if ((bigval & bigtestbit) != 0) theBits[i] = 1; else
5870 				theBits[i] = 0;
5871 			bigtestbit >>= 1;
5872 		}
5873 		DiaDoneDialog(dia);
5874 		*bits = theBits;
5875 		return(64);
5876 	}
5877 
5878 	/* bases 2, 8, and 16 are simpler */
5879 	switch (lastbase)
5880 	{
5881 		case 0: groupsize = 1;   break;		/* base 2 */
5882 		case 1: groupsize = 3;   break;		/* base 8 */
5883 		case 3: groupsize = 4;   break;		/* base 16 */
5884 		default: return(-1);
5885 	}
5886 	j = 0;
5887 	for(pt = DiaGetText(dia, DSWV_VALUE); *pt != 0; pt++)
5888 	{
5889 		chr = tolower(*pt);
5890 		if (chr >= '0' && chr <= '9') val = chr - '0'; else
5891 			if (chr >= 'a' && chr <= 'f') val = chr - 'a' + 10; else
5892 				val = 100;
5893 		if (val >= (1 << groupsize))
5894 		{
5895 			DiaMessageInDialog(_("Invalid base %s value"), base[lastbase]);
5896 			break;
5897 		}
5898 		testbit = 1 << (groupsize-1);
5899 		for(i=0; i<groupsize; i++)
5900 		{
5901 			if ((val&testbit) != 0) theBits[j] = 1; else
5902 				theBits[j] = 0;
5903 			j++;
5904 			testbit >>= 1;
5905 		}
5906 	}
5907 	DiaDoneDialog(dia);
5908 	*bits = theBits;
5909 	return(j);
5910 }
5911 
sim_window_auto_anarange(void)5912 void sim_window_auto_anarange(void)
5913 {
5914 	TRACE *tr;
5915 	int i, *t;
5916 	double l, h;
5917 
5918 	if (sim_window_lines > 0)
5919 		t = (int *)emalloc(sim_window_lines*sizeof(int), sim_tool->cluster);
5920 	else
5921 		t = NULL;
5922 	for(i=0; i < sim_window_lines; i++) t[i] = 0;
5923 
5924 	l = 0;   h = 1;
5925 	for(i=0, tr = sim_window_firstrace; tr != NOTRACE; ++i, tr = tr->nexttrace) {
5926 
5927 		if (i == 0 ) {
5928 			l  = tr->anadislow;
5929 			h = tr->anadishigh;
5930 		} else {
5931 			if ( tr->anadislow  < l ) l = tr->anadislow;
5932 			if ( tr->anadishigh > h ) h = tr->anadishigh;
5933 		}
5934 
5935 		if (tr->frameno < sim_window_lines && tr->frameno >=0 ) {
5936 			if (t[tr->frameno] == 0) {
5937 				sim_window_frame_analow[tr->frameno] = tr->anadislow;
5938 				sim_window_frame_anahigh[tr->frameno] = tr->anadishigh;
5939 				t[tr->frameno] = 1;
5940 			} else {
5941 				if (sim_window_frame_analow[tr->frameno] > tr->anadislow)
5942 					sim_window_frame_analow[tr->frameno] = tr->anadislow;
5943 
5944 				if (sim_window_frame_anahigh[tr->frameno] < tr->anadishigh)
5945 					sim_window_frame_anahigh[tr->frameno] = tr->anadishigh;
5946 			}
5947 		}
5948 	}
5949 
5950 	if (t) efree((CHAR *)t);
5951 
5952 	sim_window_analow = (float)l;
5953 	sim_window_anahigh = (float)h;
5954 	sim_window_anarange = (float)(h - l);
5955 
5956 }
5957 
sim_window_trace_range(INTBIG tri)5958 void sim_window_trace_range(INTBIG tri)
5959 {
5960 	TRACE *tr;
5961 	int j;
5962 	float h, l;
5963 
5964 	tr = (TRACE *)tri;
5965 
5966 	if (tr->numsteps >0) {
5967 		h = tr->valuearray[0];
5968 		l = tr->valuearray[0];
5969 	}
5970 
5971 	for (j=1; j<tr->numsteps; ++j) {
5972 		if ( tr->valuearray[j] < l ) l = tr->valuearray[j];
5973 		if ( tr->valuearray[j] > h ) h = tr->valuearray[j];
5974 	}
5975 
5976 /*
5977 	d = fabs(h-l);
5978 	if (d/(h+l)<DBL_EPSILON) d = 0.5;
5979 	double m = 1.0;
5980 	while ( d > 10.0 ) { d/=10.0; m*=10.0; }
5981 	while ( d < 1.0  ) { d*=10.0; m/=10.0; }
5982 
5983 	int li = (int)(l/m);
5984 	int hi = (int)(h/m);
5985 	if (li < 0) --li;
5986 	if (hi > 0) ++hi;
5987 	l = li * m;
5988 	h = hi * m;
5989  */
5990 
5991 #if 1
5992 	if (l == h)
5993 	{
5994 		l -= 0.5;
5995 		h += 0.5;
5996 	}
5997 #endif
5998 	tr->anadislow   = l;
5999 	tr->anadishigh  = h;
6000 	tr->anadisrange = h-l;
6001 }
6002 
sim_window_set_frames(int n)6003 int sim_window_set_frames(int n)
6004 {
6005 	int i;
6006 	INTBIG newlimit;
6007 	float *newanalow, *newanahigh, *newtopval, *newbotval;
6008 
6009 	if (n > sim_window_lines_limit)
6010 	{
6011 		newlimit = (sim_window_lines_limit < 16 ? 16 : sim_window_lines_limit);
6012 		while(newlimit < n) newlimit *= 2;
6013 		newanalow = (float *)emalloc(newlimit*sizeof(float), sim_tool->cluster);
6014 		newanahigh = (float *)emalloc(newlimit*sizeof(float), sim_tool->cluster);
6015 		newtopval = (float *)emalloc(newlimit*sizeof(float), sim_tool->cluster);
6016 		newbotval = (float *)emalloc(newlimit*sizeof(float), sim_tool->cluster);
6017 		if(newanalow == NULL || newanahigh == NULL || newtopval == NULL || newbotval == NULL)
6018 		{
6019 			if(newanalow != NULL) efree((CHAR *)newanalow);
6020 			if(newanahigh != NULL) efree((CHAR *)newanahigh);
6021 			if(newtopval != NULL) efree((CHAR *)newtopval);
6022 			if(newbotval != NULL) efree((CHAR *)newbotval);
6023 			return 0;
6024 		}
6025 		for (i=0; i<sim_window_lines; ++i) {
6026 			newanalow[i] = sim_window_frame_analow[i];
6027 			newanahigh[i] = sim_window_frame_anahigh[i];
6028 			newtopval[i] = sim_window_frame_topval[i];
6029 			newbotval[i] = sim_window_frame_botval[i];
6030 		}
6031 		if (sim_window_lines_limit > 0)
6032 		{
6033 			efree((CHAR *)sim_window_frame_analow);
6034 			efree((CHAR *)sim_window_frame_anahigh);
6035 			efree((CHAR *)sim_window_frame_topval);
6036 			efree((CHAR *)sim_window_frame_botval);
6037 		}
6038 		sim_window_frame_analow = newanalow;
6039 		sim_window_frame_anahigh = newanahigh;
6040 		sim_window_frame_topval = newtopval;
6041 		sim_window_frame_botval = newbotval;
6042 		sim_window_lines_limit = newlimit;
6043 	}
6044 
6045 	for (i=sim_window_lines; i<n; ++i) {
6046 		sim_window_frame_analow[i]  = sim_window_analow;
6047 		sim_window_frame_anahigh[i] = sim_window_anahigh;
6048 		sim_window_frame_topval[i] = sim_window_analow;
6049 		sim_window_frame_botval[i] = sim_window_anahigh;
6050 	}
6051 
6052 	sim_window_lines = n;
6053 	return 1;
6054 }
6055 
sim_window_get_analow(int frameno)6056 float sim_window_get_analow(int frameno)
6057 {
6058 	if (frameno >=0 && frameno < sim_window_lines)
6059 		return sim_window_frame_analow[frameno];
6060 	else
6061 		return sim_window_analow;
6062 }
6063 
sim_window_get_anahigh(int frameno)6064 float sim_window_get_anahigh(int frameno)
6065 {
6066 	if (frameno >=0 && frameno < sim_window_lines)
6067 		return sim_window_frame_anahigh[frameno];
6068 	else
6069 		return sim_window_anahigh;
6070 }
6071 
sim_window_get_topval(int frameno)6072 float sim_window_get_topval(int frameno)
6073 {
6074 	if (frameno >=0 && frameno < sim_window_lines)
6075 		return sim_window_frame_topval[frameno];
6076 	else
6077 		return sim_window_anahigh;
6078 }
6079 
sim_window_get_botval(int frameno)6080 float sim_window_get_botval(int frameno)
6081 {
6082 	if (frameno >=0 && frameno < sim_window_lines)
6083 		return sim_window_frame_botval[frameno];
6084 	else
6085 		return sim_window_analow;
6086 }
6087 
sim_window_set_anahigh(int frameno,float value)6088 void sim_window_set_anahigh(int frameno, float value)
6089 {
6090 	if (frameno >=0 && frameno < sim_window_lines)
6091 		sim_window_frame_anahigh[frameno] = value;
6092 }
6093 
sim_window_set_analow(int frameno,float value)6094 void sim_window_set_analow(int frameno, float value)
6095 {
6096 	if (frameno >=0 && frameno < sim_window_lines)
6097 		sim_window_frame_analow[frameno] = value;
6098 }
6099 
sim_window_set_topval(int frameno,float value)6100 void sim_window_set_topval(int frameno, float value)
6101 {
6102 	if (frameno >=0 && frameno < sim_window_lines)
6103 		sim_window_frame_topval[frameno] = value;
6104 }
6105 
sim_window_set_botval(int frameno,float value)6106 void sim_window_set_botval(int frameno, float value)
6107 {
6108 	if (frameno >=0 && frameno < sim_window_lines)
6109 		sim_window_frame_botval[frameno] = value;
6110 }
6111 
sim_window_get_anarange(int frameno)6112 float sim_window_get_anarange(int frameno)
6113 {
6114 	if (frameno >=0 && frameno < sim_window_lines)
6115 		return sim_window_frame_anahigh[frameno] - sim_window_frame_analow[frameno];
6116 	else
6117 		return sim_window_anarange;
6118 }
6119 
sim_window_get_extanarange(int frameno)6120 float sim_window_get_extanarange(int frameno)
6121 {
6122 	if (frameno >=0 && frameno < sim_window_lines)
6123 	{
6124 		float diff;
6125 		diff = sim_window_frame_topval[frameno] - sim_window_frame_botval[frameno];
6126 		if (!floatsequal(diff, 0.0)) return(diff);
6127 		return(sim_window_frame_anahigh[frameno] - sim_window_frame_analow[frameno]);
6128 	}
6129 	else
6130 		return sim_window_anarange;
6131 }
6132 
sim_window_zoom_frame(INTBIG frameno)6133 void sim_window_zoom_frame(INTBIG frameno)
6134 {
6135 	float v;
6136 	if (frameno >=0 && frameno < sim_window_lines) {
6137 		v = sim_window_get_anarange(frameno);
6138 		v /= 4.0f;
6139 		sim_window_frame_anahigh[frameno] -=v;
6140 		sim_window_frame_analow[frameno] +=v;
6141 	}
6142 }
6143 
sim_window_zoomout_frame(INTBIG frameno)6144 void sim_window_zoomout_frame(INTBIG frameno)
6145 {
6146 	float v;
6147 	if (frameno >=0 && frameno < sim_window_lines) {
6148 		v = sim_window_get_anarange(frameno);
6149 		v /= 2.0f;
6150 		sim_window_frame_anahigh[frameno] +=v;
6151 		sim_window_frame_analow[frameno] -=v;
6152 	}
6153 }
6154 
sim_window_shiftup_frame(INTBIG frameno)6155 void sim_window_shiftup_frame(INTBIG frameno)
6156 {
6157 	float v;
6158 	if (frameno >=0 && frameno < sim_window_lines) {
6159 		v = sim_window_get_anarange(frameno);
6160 		v /= 4.0f;
6161 		sim_window_frame_anahigh[frameno] +=v;
6162 		sim_window_frame_analow[frameno] +=v;
6163 	}
6164 }
6165 
sim_window_shiftdown_frame(INTBIG frameno)6166 void sim_window_shiftdown_frame(INTBIG frameno)
6167 {
6168 	float v;
6169 	if (frameno >=0 && frameno < sim_window_lines) {
6170 		v = sim_window_get_anarange(frameno);
6171 		v /= 4.0f;
6172 		sim_window_frame_anahigh[frameno] -=v;
6173 		sim_window_frame_analow[frameno] -=v;
6174 	}
6175 }
6176 
6177 /* This function takes a high value h, a low value l, chops the interval between
6178 h and l in n bits, and rounds the high, low and the interval to a 1,2,5
6179 range.  The integers i1 and i2 are the powers of 10 that belong to the
6180 largest value in the interval and the step size.  These integers can be
6181 used for printing the scale. */
6182 
sim_window_sensible_value(float * h,float * l,INTBIG * i1,INTBIG * i2,INTBIG n)6183 float sim_window_sensible_value(float *h, float *l, INTBIG *i1, INTBIG *i2, INTBIG n)
6184 {
6185 	float d, m, max;
6186 	int di, hi, li;
6187 
6188 	if (fabs(*h) > fabs(*l)) max = (float)fabs(*h); else max = (float)fabs(*l);
6189 	*i1 = *i2 = 0;
6190 	if (max == 0.0) return(0.0);
6191 
6192 	while ( max >= 10.0 ) { max/=10.0; ++*i1; }
6193 	while ( max <= 1.0  ) { max*=10.0; --*i1; }
6194 
6195 	d = (float)fabs(*h - *l)/(float)n;
6196 
6197 	if ((float)fabs(d/(*h+*l))<FLT_EPSILON) d = 0.1f;
6198 	m=1.0;
6199 	while ( d >= 10.0 ) { d/=10.0; m*=10.0; ++*i2; }
6200 	while ( d <= 1.0  ) { d*=10.0; m/=10.0; --*i2; }
6201 
6202 	di = (int)d;
6203 
6204 	if (di > 2 && di <= 5) di=5;
6205 	else
6206 		if (di > 5) di = 10;
6207 
6208 	li = (int)(*l/m);
6209 	hi = (int)(*h/m);
6210 	li = (li/di)*di;
6211 	hi = (hi/di)*di;
6212 	if (li<0) li-=di;
6213 	if (hi>0) hi+=di;
6214 	*l = (float)((double)li*m);
6215 	*h = (float)((double)hi*m);
6216 
6217 	return (float)di*m;
6218 }
6219 
sim_window_prettyprint(float v,int i1,int i2)6220 CHAR *sim_window_prettyprint(float v, int i1, int i2)
6221 {
6222 	double d;
6223 	int i, p;
6224 	static CHAR s[20];
6225 
6226 	d = 1.0;
6227 	if (i2 > 0)
6228 		for (i = 0; i < i2; ++i) d *= 10.0;
6229 	if (i2 < 0)
6230 		for (i = 0; i > i2; --i) d /= 10.0;
6231 
6232 	if (fabs((double)v)*100.0 < d)
6233 	{
6234 		esnprintf(s, 20, x_("0"));
6235 	} else
6236 	{
6237 		if (i1 <= 4 && i1 >=0 && i2 >=0)
6238 		{
6239 			esnprintf(s, 20, x_("%.0f"), v);
6240 		} else
6241 		{
6242 			if (i1 <= 4 && i1 >= -2 && i2 < 0)
6243 			{
6244 				esnprintf(s, 20, x_("%.*f"), (-i2), v);
6245 			} else
6246 			{
6247 				p = i1-12-1;
6248 				if (p < 0) p=0;
6249 				esnprintf(s, 20, x_("%.*fe%+2d"), p, (double)v/d, i2);
6250 			}
6251 		}
6252 	}
6253 	return(s);
6254 }
6255 
6256 #endif  /* SIMTOOL - at top */
6257