Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / rst / rstf / rstf.c
CommitLineData
920dae64
AT
1/*
2* ========== Copyright Header Begin ==========================================
3*
4* OpenSPARC T2 Processor File: rstf.c
5* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
6* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
7*
8* The above named program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public
10* License version 2 as published by the Free Software Foundation.
11*
12* The above named program is distributed in the hope that it will be
13* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15* General Public License for more details.
16*
17* You should have received a copy of the GNU General Public
18* License along with this work; if not, write to the Free Software
19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
20*
21* ========== Copyright Header End ============================================
22*/
23#pragma ident "@(#) rstf.c 1.3: 03/05/03 16:59:47 @(#)"
24//
25// This is C code, not C++
26//
27
28#include <stdarg.h> // ??
29#include <stdio.h> // fopen()
30#include <string.h> // strncmp()
31#include <stdlib.h> // putenv()
32
33#include <sys/types.h> // time_t
34#include <sys/stat.h> // struct stat
35#include <time.h> // time_t
36
37#include "rstf.h"
38#include "vercheck.c"
39
40#ifndef true
41 #define true 1
42 #define false 0
43 typedef int boolean;
44#endif
45
46static int numbad = 0; // number of bad RST recs
47// static int dummy = RSTF_ATRACE_NO_PC;
48
49#define print_type_size(out,type) \
50 check(out, #type, sizeof(type), want);
51
52static int streq (const char* a, const char* b) {
53 return (strcmp(a, b) == 0);
54}
55
56static int endsWith (const char* str, const char* suffix) {
57 int slen = strlen(str);
58 int sufflen = strlen(suffix);
59 return (sufflen <= slen) &&
60 (strncmp(str+slen-sufflen, suffix, sufflen) == 0);
61} /* endsWith */
62
63//
64// Version handling code
65//
66
67 // Set of triples (AA,BB,CC), where
68 // Versions in the range [AA,BB) are compatiable.
69 // Versions with the same CC value are considered semi-compatible.
70 // Versions with different CC values are incompatible.
71 // The last entry should have AA = BB = CC = -1 .
72 // Thus for this table:
73 // 1.00 vs. 1.04 => compatible.
74 // 1.04 vs. 1.06 => semi-compatible.
75 // 1.07 vs. 1.09 => semi-compatible.
76 // 1.10 vs. 2.02 => compatible.
77double rst_vequivtab [][3] = {
78 { 0.00, 1.00, 0.0 },
79 { 1.00, 1.04, 1.0 },
80 { 1.04, 1.06, 2.0 },
81 { 1.06, 1.08, 2.0 },
82 { 1.08, 1.10, 2.0 },
83 { 1.10, 2.09, 3.0 },
84 { -1, -1.0, -1.0 },
85};
86
87static double rstver2double (const char * str) {
88 int x, y;
89 int ni = sscanf(str, "%d.%d", &x, &y);
90 double d = x*100 + y;
91 return d / 100;
92} /* rstver2double */
93
94int rst_verCheck (
95 const char* ct_str, const char* rt_str, double vt[][3], const char* modname
96) {
97 double ct_ver = rstver2double(ct_str);
98 double rt_ver = rstver2double(rt_str);
99 return ver_check_dbl(ct_ver, rt_ver, vt, modname);
100} /* generic_verCheck */
101
102int rstf_version_check_fn (const char* ct_version) {
103 const char* rt_str = RSTF_VERSION_STR;
104 return rst_verCheck(ct_version, rt_str, rst_vequivtab, "RST");
105} /* rstf_version_check_fn */
106
107int rstf_checkheader (const char* compile_time_ver, rstf_headerT *rec) {
108 double ct_ver = rstver2double(compile_time_ver);
109 if (rec->rtype == RSTHEADER_T) {
110 double trace_ver = (100 * rec->majorVer) + rec->minorVer;
111 trace_ver /= 100;
112
113 if (rec->percent != '%') {
114 fprintf(stderr, "Non-compliant RST header: compile-on=%% got=%c\n",
115 rec->percent);
116 }
117 return ver_check_dbl(ct_ver, trace_ver, rst_vequivtab, "RST trace");
118 }
119 return VERCHECK_ERROR;
120} /* rstf_checkheader */
121
122typedef struct {
123 FILE * f;
124 int isCompressed;
125} fileinfo_t;
126
127static int nfileinfo = 0;
128static fileinfo_t fileinfo[64];
129
130static void printfi () {
131 int i= 0;
132 for (i=0; i<nfileinfo; i++) {
133 fileinfo_t * pp = & fileinfo[i];
134 fprintf(stderr,
135 "[%d]->f=0x%0x iscompressed=%d\n", i, pp->f, pp->isCompressed);
136 }
137} /* printfi */
138
139FILE * openRST (const char* filename) {
140 FILE * f = NULL;
141 int decompress =
142 endsWith(filename, ".rsz") ||
143 endsWith(filename, ".rz.gz") ||
144 endsWith(filename, ".rsz.gz") ||
145 endsWith(filename, ".rzgz");
146 int decompress2 = endsWith(filename, ".rz2.gz");
147 if (decompress) {
148 char command [2048];
149 putenv("PATH=/import/archperf/bin:/usr/bin:/bin");
150 sprintf(command, "rstzip -d -gz %s", filename);
151 f = popen(command, "r");
152 } else if (decompress2) {
153 char command [2048];
154 putenv("PATH=/import/archperf/bin:/usr/bin:/bin");
155 sprintf(command, "rstunzip2 %s", filename);
156 f = popen(command, "r");
157 } else {
158 f = fopen(filename, "r");
159 }
160 if (f != NULL) {
161 fileinfo[nfileinfo].f = f;
162 fileinfo[nfileinfo].isCompressed = decompress || decompress2;
163 nfileinfo ++;
164 }
165 return f;
166} /* openRST */
167
168void closeRST (FILE* f) {
169 int i= 0;
170 for (i=0; i<nfileinfo; i++) {
171 fileinfo_t * pp = & fileinfo[i];
172 if (pp->f == f) {
173 if (pp->isCompressed) {
174 pclose(f);
175 } else {
176 fclose(f);
177 }
178 pp->f = NULL;
179 f = NULL; /* we found it */
180 *pp = fileinfo[nfileinfo-1];
181 nfileinfo --;
182 break;
183 }
184 }
185 /* guess the type of the file */
186 if (f != NULL) {
187 char* ftype = "unknown";
188 if (isPipeRST(f)) {
189 pclose(f);
190 ftype = "pipe from popen";
191 } else {
192 fclose(f);
193 ftype = "regular file";
194 }
195 fprintf(stderr, "closeRST(f=%x), guessed f is %s\n", f, ftype);
196 }
197} /* closeRST */
198
199int isPipeRST (FILE* f) {
200 struct stat statbuf;
201 int fd = fileno(f);
202 fstat(fd, &statbuf);
203 return ((statbuf.st_mode & S_IFIFO) == S_IFIFO);
204}
205
206int isCompressedRSZ (char * buff, int bufflen) {
207 // from running "od -x trace.rz.gz"
208 static short want [] = {
209 0x1f, 0x8b, 0x08, 0x00, -1, -1, -1, -1
210 };
211 int i;
212 for (i=0; i<sizeof(want)/sizeof(want[0]) ; i++) {
213 if (buff[i] != want[i] && want[i] != -1) {
214 return false;
215 }
216 }
217 return true;
218} /* isCompressedRSZ */
219
220void check (FILE* out, const char* type, int tsize, int want) {
221 fprintf(out, "sizeof(%18s) = %4d\n", type, tsize);
222 if (tsize != want) {
223 numbad ++;
224 fprintf(out, "ERROR on (%s) field.\n", type, sizeof(type));
225 fflush(out);
226 }
227} /* check */
228
229static void initrec (void* ptr, uint8_t rtype) {
230 INIT_RST_REC(ptr,rtype);
231} /* initrec */
232
233#define INIT_RST_REC_DBG(rstf_ptr,rtype_val) \
234 do { \
235 rstf_uint64T * p = (rstf_uint64T*) (rstf_ptr); \
236 p->arr64[0] = (rtype_val); \
237 p->arr64[0] <<= (64-8); \
238 p->arr64[1] = 0; \
239 p->arr64[2] = 0; \
240 } while (0==1)
241
242void testSizes () {
243 FILE* out = stdout;
244 rstf_protoT rec;
245 rstf_protoT * p = &rec;
246 int want = sizeof(rstf_unionT);
247
248 print_type_size(out,rstf_unionT);
249 print_type_size(out,rstf_protoT);
250 print_type_size(out,rstf_whatT);
251 print_type_size(out,rstf_instrT);
252 print_type_size(out,rstf_tlbT);
253 print_type_size(out,rstf_threadT);
254 print_type_size(out,rstf_processT);
255 print_type_size(out,rstf_pregT);
256 print_type_size(out,rstf_trapT);
257 print_type_size(out,rstf_cpuT);
258 print_type_size(out,rstf_trapT);
259 print_type_size(out,rstf_stringT);
260 print_type_size(out,rstf_physaddrT);
261 print_type_size(out,rstf_pavadiffT);
262 print_type_size(out,rstf_memval64T);
263 print_type_size(out,rstf_memval128T);
264 print_type_size(out,rstf_bustraceT);
265 print_type_size(out,rstf_filemarkerT);
266 print_type_size(out,rstf_recnumT);
267 print_type_size(out,rstf_hwinfoT);
268 print_type_size(out,rstf_statusT);
269 print_type_size(out,rstf_patchT);
270 print_type_size(out,rstf_dmaT);
271 printf("================\n");
272 print_type_size(out,rstf_uint8T);
273 print_type_size(out,rstf_uint16T);
274 print_type_size(out,rstf_uint32T);
275 print_type_size(out,rstf_uint64T);
276 if (numbad == 0) {
277 fprintf(out, "Good. All records in rstf are the same size.\n");
278 }
279
280 initrec(&rec, INSTR_T);
281 fprintf(out, "OK rtype=%d want=%d\n", rec.rtype, INSTR_T); fflush(out);
282 initrec(&rec, TLB_T);
283 fprintf(out, "OK rtype=%d want=%d\n", rec.rtype, TLB_T); fflush(out);
284// INIT_RST_REC_DBG( p , INSTR_T);
285// fprintf(out, "OK rtype=%d want=%d\n", rec.rtype, INSTR_T); fflush(out);
286 INIT_RST_REC( p , INSTR_T);
287 fprintf(out, "OK rtype=%d want=%d\n", rec.rtype, INSTR_T); fflush(out);
288}
289
290static void strcopy (char* dest, const char* src, int destsize) {
291 strncpy(dest, src, destsize);
292 dest[destsize-1] = '\0';
293} /* strcopy */
294
295int rstf_strncpy (void * dest_rstp, const char *str) {
296 rstf_unionT * up = (rstf_unionT *) dest_rstp;
297 rstf_headerT * hp = &(up->header);
298 switch (up->string.rtype) {
299 case RSTHEADER_T:
300 strncpy(hp->header_str, str, sizeof(hp->header_str));
301 break;
302 default:
303 ;
304 }
305 return 0;
306} /* rstf_strncpy */
307
308 // initialize a header record with the current RST major/minor number.
309 // The string
310int init_rstf_header (rstf_headerT * hp) {
311 char buff[80];
312 INIT_RST_REC(hp, RSTHEADER_T);
313 hp->majorVer = RSTF_MAJOR_VERSION;
314 hp->minorVer = RSTF_MINOR_VERSION;
315 hp->percent = '%';
316 sprintf(buff, "%s v%s", RSTF_MAGIC, RSTF_VERSION_STR);
317 rstf_strncpy(hp, buff);
318 return 0;
319}
320
321int init_rstf_traceinfo_level (rstf_traceinfo_levelT * ti, int level) {
322 INIT_RST_REC(ti, TRACEINFO_T);
323 ti->rtype2 = RSTT2_NLEVEL_T;
324 ti->level = level;
325 ti->time64 = (uint64_t) time(NULL);
326 return 0;
327}
328
329int init_rstf_string (rstf_stringT * strp, const char *str) {
330 int len = strlen(str) + 1; // null char adds 1
331 int recsize = sizeof(strp->string);
332 INIT_RST_REC(strp, STRDESC_T);
333 if (recsize >= len) {
334 strncpy(strp->string, str, recsize);
335 } else {
336 strncpy(strp->string, str, recsize-1);
337 strp->string[recsize-1] = '\0';
338 }
339 return 0;
340} /* init_rstf_string */
341
342 // get the next string
343const char* get_rstf_longstr (const rstf_stringT * p, int nrec, int *nrread) {
344 static char buff [2048];
345 char* end = buff; //
346 int nr = 0;
347 const int strcontsize = sizeof(p->string);
348 while (nr < nrec) {
349 const rstf_stringT * strp = & (p[nr]);
350 int rem = buff + sizeof(buff) - end; // remaining room
351 if (rem < strcontsize) {
352 break;
353 }
354 if (strp->rtype == STRCONT_T) {
355 strncpy(end, strp->string, strcontsize);
356 end += strcontsize;
357 nr ++;
358 } else if (strp->rtype == STRDESC_T) {
359 strcpy(end, strp->string);
360 end += strlen(strp->string);
361 nr ++;
362 break;
363 } else {
364 break;
365 }
366 }
367 if (nrread != NULL) {
368 *nrread = nr;
369 }
370 *end = '\0';
371 return buff;
372} /* get_rstf_long_string */
373
374#define min(x,y) ((x)<(y) ? (x) : (y))
375
376 // Initialize upto MAXREC records with the string STR, using
377 // STRDESC_T and STRCONT_T records. Handles strings of any length.
378 // Returns the number of RST records used.
379int init_rstf_strbuff (rstf_stringT * strp, const char *str, int maxrec) {
380 int len = strlen(str) + 1; // null char adds 1
381 int recsize = sizeof(strp->string);
382 int nrneeded = ((len) + (recsize-1))/ recsize;
383 int canuse = min(maxrec, nrneeded); // RST records we can use
384 const char* ss = str;
385 int i;
386 for (i=0; i<canuse; i++) {
387 if (i == (canuse-1) ) {
388 init_rstf_string( &strp[i], ss );
389 } else {
390 strp[i].rtype = STRCONT_T;
391 strncpy(strp[i].string, ss, recsize);
392 ss += recsize;
393 }
394 }
395 return canuse;
396} /* init_rstf_strbuff */
397
398 // Convenience fn to generate a RST_STRDESC record.
399int rstf_sprintf (rstf_stringT * strp, const char* fmt, ...) {
400 #define BUFFLEN 1024
401 char buff[BUFFLEN];
402 va_list ap;
403 va_start(ap, fmt);
404 vsnprintf(buff, BUFFLEN, fmt, ap);
405 #undef BUFFLEN
406 init_rstf_string(strp, buff);
407 va_end(ap);
408 return 0;
409} /* rst_sprintf */
410
411 // Convenience fn to generate a RST_STRDESC record.
412int rstf_snprintf (rstf_stringT * strp, int maxrec, const char* fmt, ...) {
413 #define BUFFLEN 8192
414 char buff[BUFFLEN];
415 int nr = 0;
416 va_list ap;
417 va_start(ap, fmt);
418 vsnprintf(buff, 8192, fmt, ap);
419 #undef BUFFLEN
420 nr = init_rstf_strbuff(strp, buff, maxrec);
421 va_end(ap);
422 return nr;
423} /* rst_sprintf */
424
425void printIfBadAddr (uint64_t xaddr) {
426 if (RSTF_IS_BADADDR(xaddr)) {
427 printf("Addr 0x%08llx is a known bad RST addr\n", xaddr);
428 }
429}
430
431void checkRSTmacro () {
432 uint64_t x = RSTF_ATRACE_NO_PC;
433
434 printIfBadAddr(x);
435 x = 0x314159ff;
436 printIfBadAddr(x);
437 x = 0x314159fe;
438 printIfBadAddr(x);
439 x = 0x1234567;;
440 printIfBadAddr(x);
441}
442
443#define RCBUFFSIZE 8192
444char* unixcommand (const char * command, int nl, int * statusptr) {
445 static char charbuff[RCBUFFSIZE];
446 FILE *ptr = popen(command, "r");
447 char *buf = charbuff;
448 char *result = NULL;
449
450 if (ptr != NULL) {
451 int status;
452 while (fgets(buf, RCBUFFSIZE - (buf-charbuff), ptr) != NULL) {
453 int len = strlen(buf);
454 if (buf[len-1] == '\n') {
455 // remove '\n', terminate string, in case last line of input
456 buf[len] = '\0';
457 result = charbuff;
458 if (nl <= 1) {
459 buf[len-1] = '\0'; // discard last newline
460 break;
461 }
462 nl --;
463 buf += len;
464 }
465 }
466 status = pclose(ptr);
467 if (statusptr != NULL) {
468 *statusptr = status;
469 }
470 }
471 return result;
472} /* unixcommand */
473
474static void genTestTrace (const char* str) {
475 rstf_unionT uuu[256];
476 rstf_stringT * buff = & (uuu[1].string); // [1] == skip past header
477 int nr , nr2;
478 char* now = unixcommand("date", 1, NULL);
479 char* df = NULL;
480 init_rstf_header(& uuu[0].header);
481 rstf_sprintf(buff, "BEGIN it is %s", now);
482 nr = rstf_snprintf(buff+1, 88, "it is now %s", now);
483 df = unixcommand("df -lk", 44, NULL);
484 nr2 = rstf_snprintf(buff+1+nr, 88, "Local mounted disks %s", df);
485 rstf_sprintf(buff+1+nr+nr2, "END. argv[0]=(%s)", str);
486 fwrite(&uuu, sizeof(buff[0]), 3+nr+nr2, stdout);
487 fflush(stdout);
488} /* genTestTrace */
489
490#if defined(TEST_RSTF)
491
492static void usage (char* argv0) {
493 printf("usage: %s [-tvf]\n", argv0);
494 printf(" -f FILE = read 16K recs from FILE openRST(), send to stdout\n");
495 printf(" -t = generate a test trace to stdout\n");
496 printf(" -v = run version check code\n");
497 printf(" Eg. %s -t | trconv\n", argv0);
498} /* usage */
499
500 // check a
501static void checkVer () {
502 const char* strArr [] =
503 { "1.00", "1.4", "1.7", "1.8", "1.10", "2.0", "2.02", "4.8" };
504 int len = sizeof(strArr) / sizeof(strArr[0]);
505 int i = 0;
506 for (i=0; i<len; i++) {
507 int j;
508 const char * ct = strArr[i];
509 for (j=i; j<len; j++) {
510 const char * rt = strArr[j];
511 int status = generic_verCheck(ct, rt, rst_vequivtab, "XYZ");
512 int status2 = rst_verCheck(ct, rt, rst_vequivtab, "RST");
513
514 printf("%d = verCheck(%s, %s)\n", status, ct, rt);
515 printf("%d = rst_verCheck(%s, %s)\n", status2, ct, rt);
516 }
517 }
518} /* checkVer */
519
520int main (int argc, char* argv []) {
521 if (argc == 1) {
522 testSizes();
523 checkRSTmacro();
524 usage(argv[0]);
525 } else {
526 int i;
527 for (i=1; i<argc; i++) {
528 if ( streq(argv[1], "-f") ) {
529 i++;
530 if (i<argc) {
531 FILE * f = openRST(argv[i]);
532 if (f != NULL) {
533 rstf_unionT ru [128];
534 int nr = -1;
535 int tot = 0;
536 while ((nr=fread(ru, sizeof(ru[0]), 128, f)) > 0) {
537 fwrite(ru, sizeof(ru[0]), nr, stdout);
538 tot += nr;
539 if (tot > 16384) {
540 break;
541 }
542 }
543 closeRST(f);
544 }
545 }
546 } else if ( streq(argv[1], "-v") ) {
547 checkVer();
548 } else if ( streq(argv[1], "-v") ) {
549 checkVer();
550 } else if ( streq(argv[1], "-t") ) {
551 genTestTrace(argv[0]);
552 }
553 }
554 }
555}
556
557#endif /* defined() */