1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Last edit by hansen on Mon Feb 2 17:03:26 2009
19 ****************************************************************************/
20 /*
21 Postscript generator for tkgate.
22 */
23
24 #ifdef __cplusplus
25 #include <cstdlib>
26 #include <cstdio>
27 #include <cstring>
28 #include <cassert>
29 #include <cmath>
30 #else
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <assert.h>
35 #include <math.h>
36 #endif
37
38 #include <unistd.h>
39 #include <pwd.h>
40 #include <sys/time.h>
41
42 #include "tkgate.h"
43 #include "print.h"
44
45 /***********************************************************************/
46
47
choose_trace_interval(simtime_t * e_per_l,simtime_t * e_inter)48 static void choose_trace_interval(simtime_t *e_per_l,simtime_t *e_inter)
49 {
50 double n,m;
51 int l,h;
52
53 /*
54 * Power of ten >= to e_per_l
55 */
56 n = pow(10.0,ceil(log((double)*e_per_l)/log(10.0)));
57
58 m = (n-*e_per_l)/n;
59
60 if (m >= 0.8)
61 m = 0.02;
62 else if (m >= 0.6)
63 m = 0.05;
64 else
65 m = 0.1;
66
67 n = m*n;
68
69 *e_inter = (int)n;
70
71 l = (*e_per_l / *e_inter)* *e_inter;
72 h = l + *e_inter;
73
74 if (*e_per_l-l < h-*e_per_l)
75 *e_per_l = l;
76 else
77 *e_per_l = h;
78 }
79
80
GPrint_setupTracePages(GPrint * P)81 void GPrint_setupTracePages(GPrint *P)
82 {
83 extern GScope *Scope; /* The scope trace */
84 int hspace; /* Horizontal space for traces on page */
85 int vspace; /* Vertical space for traces on page */
86 int tsheight; /* Height of a full trace set and scale */
87 int pg; /* Page # */
88 int e_start; /* Starting epoch # on a page */
89
90 pg = 0;
91
92 /*
93 * If no traces, output an empty page.
94 */
95 if (!Scope || Scope->NumTraces <= 0 || P->p_trace.ti_start >= P->p_trace.ti_end) {
96 P->p_numPages = 1;
97 P->p_pages = (GPage**) ob_malloc(sizeof(GPage*),"GPage*");
98 assert(P->p_pages);
99 P->p_pages[0] = new_GPage(PT_TRACE,1);
100 return;
101 }
102
103 vspace = P->p_uHeight-PTRC_TMARGIN-PTRC_BMARGIN; /* Max usable vert. space*/
104 hspace = P->p_uWidth-PTRC_LMARGIN-PTRC_RMARGIN; /* Max usable horz. space*/
105 tsheight = Scope->NumTraces*PTRC_TRHEIGHT+PTRC_SCHEIGHT; /* Ver. space per trace set */
106
107 P->p_trace.ti_simEnd = Scope->s_time;
108
109 /*
110 * Choose an interval and adjust epochs per line to be a multiple of the interval
111 */
112 choose_trace_interval(&P->p_trace.ti_scaleLength,&P->p_trace.ti_interval);
113
114 /*
115 * Compute translation from epochs to points.
116 */
117 P->p_trace.ti_pointsPerEpoch = (double)hspace/(double)P->p_trace.ti_scaleLength;
118
119 /*
120 * Round start down and end up to a multiple of the interval
121 */
122 P->p_trace.ti_istart = (P->p_trace.ti_start/P->p_trace.ti_interval)*P->p_trace.ti_interval;
123 P->p_trace.ti_iend = ((P->p_trace.ti_end+P->p_trace.ti_interval-1)/P->p_trace.ti_interval)*P->p_trace.ti_interval;
124
125 if (tsheight <= vspace) { /* 1 or more trace sets on a page */
126
127 /*
128 * Compute the number of trace sets on a page, the number of epochs on a page and the
129 * number of pages in the document. The number of pages per trace set is one.
130 */
131 P->p_trace.ti_tracesPerPage = (vspace/tsheight);
132 P->p_trace.ti_epochsPerPage = P->p_trace.ti_scaleLength*P->p_trace.ti_tracesPerPage;
133 P->p_numPages = (P->p_trace.ti_iend-P->p_trace.ti_istart+P->p_trace.ti_epochsPerPage-1)/P->p_trace.ti_epochsPerPage;
134 P->p_trace.ti_pagesPerTrace = 1;
135
136 P->p_pages = (GPage**) ob_malloc(P->p_numPages*sizeof(GPage*),"GPage*[]");
137 assert(P->p_pages);
138
139 for (e_start = P->p_trace.ti_istart;e_start < P->p_trace.ti_iend;e_start += P->p_trace.ti_epochsPerPage) {
140 GPage *G;
141
142 assert(pg < P->p_numPages);
143
144 G = new_GPage(PT_TRACE,pg+1);
145 P->p_pages[pg++] = G;
146
147 G->pg_traceNum = 0;
148 G->pg_traceStart = e_start;
149 G->pg_traceEnd = e_start + P->p_trace.ti_epochsPerPage - 1;
150 if (G->pg_traceEnd > P->p_trace.ti_iend)
151 G->pg_traceEnd = P->p_trace.ti_iend;
152 }
153 } else { /* multiple pages per trace set */
154 int maxtr = (vspace-PTRC_SCHEIGHT)/PTRC_TRHEIGHT; /* Maximum number of traces per page */
155 int j;
156
157 P->p_trace.ti_pagesPerTrace = (Scope->NumTraces+maxtr-1)/maxtr;
158 P->p_trace.ti_epochsPerPage = P->p_trace.ti_scaleLength;
159 P->p_numPages = ((P->p_trace.ti_iend-P->p_trace.ti_istart+P->p_trace.ti_epochsPerPage-1)/P->p_trace.ti_epochsPerPage);
160 P->p_numPages *= P->p_trace.ti_pagesPerTrace;
161 P->p_trace.ti_tracesPerPage = 1;
162
163 P->p_pages = (GPage**) ob_malloc(P->p_numPages*sizeof(GPage*),"GPage*[]");
164 assert(P->p_pages);
165
166 pg = 0;
167 for (e_start = P->p_trace.ti_istart;e_start < P->p_trace.ti_iend;e_start += P->p_trace.ti_epochsPerPage) {
168 for (j = 0;j < P->p_trace.ti_pagesPerTrace;j++) {
169 GPage *G;
170
171 assert(pg < P->p_numPages);
172
173 G = new_GPage(PT_TRACE,pg);
174 P->p_pages[pg++] = G;
175
176 G->pg_traceNum = j*maxtr;
177 G->pg_traceStart = e_start;
178 G->pg_traceEnd = e_start + P->p_trace.ti_epochsPerPage - 1;
179 if (G->pg_traceEnd > P->p_trace.ti_iend)
180 G->pg_traceEnd = P->p_trace.ti_iend;
181
182 }
183 }
184 }
185
186 #if 0
187 printf("actual pages (p=%d (%gx%g) s=%d r=[%d..%d] ---> %d\n",(P->p_size-paperSizes),P->p_uWidth,P->p_uHeight,P->p_trace.scale,P->p_trace.ti_start,P->p_trace.ti_end,P->p_numPages);
188 #endif
189 }
190
191 /*****************************************************************************
192 *
193 * Format a time value for printing
194 *
195 *****************************************************************************/
GPrint_formatTime(GPrint * P,char * buf,simtime_t t)196 char *GPrint_formatTime(GPrint *P,char *buf,simtime_t t)
197 {
198 SimInterface *si = &TkGate.circuit->simulator;
199 double n = t*si->si_tsmult/(double)si->si_precision;
200 double interval = P->p_trace.ti_interval*si->si_tsmult/(double)si->si_precision;
201 int units = si->si_units;
202
203
204 while (interval > 1000) {
205 interval /= 1000;
206 n /= 1000;
207 units--;
208 }
209
210 switch (si->si_precision) {
211 case 1 :
212 sprintf(buf,"%0.0f%s",n,SimInterface_unitsToStr(units));
213 break;
214 case 10 :
215 sprintf(buf,"%0.1f%s",n,SimInterface_unitsToStr(units));
216 break;
217 case 100 :
218 sprintf(buf,"%0.2f%s",n,SimInterface_unitsToStr(units));
219 break;
220 default :
221 sprintf(buf,"%0.3f%s",n,SimInterface_unitsToStr(units));
222 break;
223 }
224
225
226 return buf;
227 }
228
229 /*
230 * Print a scope trace document
231 */
GPrintOpt_tracePrint(GPrintOpt * PO)232 void GPrintOpt_tracePrint(GPrintOpt *PO)
233 {
234 GPrint *P = new_GPrint(PO);
235
236 if (!P) return;
237
238 GPrint_setupTracePages(P);
239 GPrint_outputPreamble(P,0);
240 GPrint_outputPages(P);
241 GPrint_outputTrailer(P);
242
243 delete_GPrint(P);
244 }
245
246
247 /*****************************************************************************
248 *
249 * Returns an estimate of the number of lines of trace groups that can
250 * fit on a page. If more than one page is needed, a value less than one
251 * will be returned.
252 *
253 * Parameters
254 * orient Page orientation
255 * paper Paper type
256 *
257 *****************************************************************************/
traceLinesPerPage(const char * orient,const char * paper)258 double traceLinesPerPage(const char *orient,const char *paper)
259 {
260 extern GScope *Scope; /* The scope trace */
261 PaperSize *size = 0;
262 /** @TODO to remove */
263 double uHeight/*, uWidth*/;
264 double vspace,tsheight;
265 int i;
266
267 /*
268 * If no active scope, return 1 page.
269 */
270 if (!Scope || Scope->NumTraces <= 0)
271 return 1.0;
272
273 /*
274 * Search for the paper size
275 */
276 for (i = 0;paperSizes[i].ps_size;i++) {
277 if (strcmp(paperSizes[i].ps_size,paper) == 0) {
278 size = &paperSizes[i];
279 break;
280 }
281 }
282 if (!size) size = &paperSizes[0];
283
284 /*
285 * Figure out height and width from paper size and orientation.
286 */
287 if (strcmp(orient,"landscape") == 0) {
288 /** @TODO uWidth = size->ps_height - PAGE_LMARGIN - PAGE_RMARGIN; */
289 uHeight = size->ps_width - PAGE_TMARGIN - PAGE_BMARGIN - PAGE_LBLOCK;;
290 } else {
291 /** @TODO uWidth = size->ps_width - PAGE_LMARGIN - PAGE_RMARGIN; */
292 uHeight = size->ps_height- PAGE_TMARGIN - PAGE_BMARGIN - PAGE_LBLOCK;
293 }
294
295 vspace = uHeight-PTRC_TMARGIN-PTRC_BMARGIN; /* Max usable vert. space*/
296 tsheight = Scope->NumTraces*PTRC_TRHEIGHT+PTRC_SCHEIGHT; /* Ver. space per trace set */
297
298 if (tsheight <= vspace) {
299 return floor(vspace/tsheight); /* One or more trace groups fit on a page */
300 } else {
301 return 1.0/ceil(tsheight/vspace); /* More than one page needed for a trace group */
302 }
303 }
304
305 /*
306 * Output a single line of trace data for a single signal.
307 *
308 * Parameters:
309 * P Page on which to print
310 * T Trace data to print
311 * y y position of page of trace
312 * pg_tstart time value at left edge of page.
313 */
GPrint_outputTrace(GPrint * P,GTrace * T,int y,int pg_tstart)314 static void GPrint_outputTrace(GPrint *P,GTrace *T,int y,int pg_tstart)
315 {
316 simtime_t tend = imin(pg_tstart + P->p_trace.ti_scaleLength,P->p_trace.ti_end);
317 simtime_t tstart = imax(pg_tstart,P->p_trace.ti_start);
318 char buf[STRMAX];
319 GateValue *pV,*V;
320 const char *name;
321
322 name = strchr(T->t_name,'.');
323 if (name)
324 name++;
325 else
326 name = T->t_name;
327
328 fprintf(P->p_f,"%d %d %f %d gline\n",PTRC_TXTMARGIN,y,P->p_uWidth-PTRC_RMARGIN,y);
329 fprintf(P->p_f,"%d bfont\n",PTRC_FONTSIZE);
330 fprintf(P->p_f,"(%s) %d %d prshow\n",filterParen(buf,name),
331 PTRC_TXTMARGIN,y+PTRC_TRHEIGHT/2-PTRC_FONTSIZE/2);
332 fprintf(P->p_f,"%d rfont\n",PTRC_FONTSIZE);
333
334 /*
335 * Scan for first value
336 */
337 pV = 0;
338 for (V = T->t_first;V->v_next && V->v_next->v_time < tstart;pV = V, V = V->v_next);
339
340 fprintf(P->p_f,"%d %d %d %d BT\n",
341 PTRC_LMARGIN-1,y,(int)P->p_uWidth-PTRC_LMARGIN-PTRC_RMARGIN+2,PTRC_TRHEIGHT);
342
343 for (;V && V->v_time <= tend;pV = V, V = V->v_next) {
344 simtime_t seg_start,seg_end;
345 simtime_t subseg_start, subseg_end;
346 double x1,x2;
347
348 seg_start = V->v_time;
349 seg_end = V->v_next ? V->v_next->v_time : imin(tend,P->p_trace.ti_simEnd);
350 subseg_start = imax(imax(seg_start,pg_tstart),tstart);
351 subseg_end = imin(seg_end,tend);
352
353 x1 = PTRC_LMARGIN+(subseg_start-pg_tstart)*P->p_trace.ti_pointsPerEpoch;
354 x2 = PTRC_LMARGIN+(subseg_end-pg_tstart)*P->p_trace.ti_pointsPerEpoch;
355
356 if (V->v_hexValue) {
357 if (pV && (seg_start == subseg_start || pV->v_time > pg_tstart))
358 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRHIGH,x1,y+PTRC_TRLOW);
359 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRLOW,x2,y+PTRC_TRLOW);
360 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRHIGH,x2,y+PTRC_TRHIGH);
361
362 fprintf(P->p_f,"(%s) %g %d %g trshow\n",V->v_hexValue,x1+PTRC_HEXPOS,y+PTRC_TRLOW+3,x2-x1-PTRC_HEXPOS);
363 } else {
364 if (pV && (seg_start == subseg_start || pV->v_time > pg_tstart)) {
365 unsigned tt = (T->t_nBits == 1) ? transition_type(pV->v_code,V->v_code) : 0x3;
366 switch (tt) {
367 case 0x1 :
368 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRLOW,x1,y+PTRC_TRMID);
369 break;
370 case 0x2 :
371 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRHIGH,x1,y+PTRC_TRMID);
372 break;
373 case 0x3 :
374 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRHIGH,x1,y+PTRC_TRLOW);
375 break;
376 }
377 }
378
379 switch (V->v_code) {
380 case VC_ZERO :
381 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRLOW,x2,y+PTRC_TRLOW);
382 break;
383 case VC_ONE :
384 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRHIGH,x2,y+PTRC_TRHIGH);
385 break;
386 case VC_UNKNOWN :
387 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRLOW,x2,y+PTRC_TRLOW);
388 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRHIGH,x2,y+PTRC_TRHIGH);
389 break;
390 case VC_FLOAT :
391 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRMID,x2,y+PTRC_TRMID);
392 break;
393 case VC_HIGH :
394 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRHIGH,x2,y+PTRC_TRHIGH);
395 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRMID,x2,y+PTRC_TRMID);
396 break;
397 case VC_LOW :
398 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRLOW,x2,y+PTRC_TRLOW);
399 fprintf(P->p_f,"%g %d %g %d line\n",x1,y+PTRC_TRMID,x2,y+PTRC_TRMID);
400 break;
401 }
402 }
403 }
404
405 fprintf(P->p_f,"ET\n");
406 }
407
GPrint_outputTraceScale(GPrint * P,int y,simtime_t tstart)408 static void GPrint_outputTraceScale(GPrint *P,int y,simtime_t tstart)
409 {
410 simtime_t tend = tstart + P->p_trace.ti_scaleLength;
411 simtime_t t;
412 char buf[STRMAX];
413
414 fprintf(P->p_f,"%d bfont\n",PTRC_FONTSIZE);
415 for (t = tstart;t <= tend;t += P->p_trace.ti_interval) {
416 double x = PTRC_LMARGIN + (t-tstart)*P->p_trace.ti_pointsPerEpoch;
417 fprintf(P->p_f,"%g %d %g %d line\n",x,y,x,y-PTRC_SCTICK);
418
419 if (t + P->p_trace.ti_interval <= tend)
420 fprintf(P->p_f,"(%s) %g %d rCT\n",GPrint_formatTime(P,buf,t),x,y-PTRC_SCLABPOS);
421 }
422 }
423
424
GPrint_printTracePage(GPrint * P,GPage * PG)425 void GPrint_printTracePage(GPrint *P,GPage *PG)
426 {
427 extern GScope *Scope;
428 int t,ts,top_y,y;
429 char buf1[STRMAX],buf2[STRMAX];
430
431 fprintf(P->p_f,"(%d of %d) (%s-%s) BP_T\n",
432 PG->pg_num,P->p_numPages,
433 GPrint_formatTime(P,buf1,imax(PG->pg_traceStart,P->p_trace.ti_start)),
434 GPrint_formatTime(P,buf2,imin(PG->pg_traceEnd,P->p_trace.ti_end)));
435
436 y = P->p_uHeight - PTRC_TMARGIN;
437
438 for (ts = 0;ts < P->p_trace.ti_tracesPerPage;ts++) {
439 simtime_t l_start = PG->pg_traceStart+ts*P->p_trace.ti_scaleLength;
440
441 if (l_start >= PG->pg_traceEnd) break;
442
443 top_y = y;
444 for (t = PG->pg_traceNum;t < Scope->NumTraces;t++) {
445 GTrace *T = Scope->Traces[t]; /* Trace to display */
446 y -= PTRC_TRHEIGHT; /* Position of trace baseline */
447 if (y - PTRC_SCHEIGHT < 0) break; /* Page is full */
448
449 GPrint_outputTrace(P,T,y,l_start);
450 }
451
452 fprintf(P->p_f,"%d %d %d %d bold_box\n",0,y-PTRC_SCBXHEIGHT,(int)P->p_uWidth,top_y-y+PTRC_SCBXHEIGHT);
453
454 GPrint_outputTraceScale(P,y,l_start);
455
456 y -= PTRC_SCHEIGHT;
457 }
458
459 fprintf(P->p_f,"EP\n");
460 }
461