YARISIM: fix the --data-generation etc regression (file extensions
[yari.git] / shared / yarisim / sim.c
blobeee4901c2d02b9360c28ce838b7ad8cbd45c1524
1 #include <SDL.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <assert.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <termios.h>
11 #include <netinet/in.h>
12 #include <signal.h>
13 #include "elf.h"
14 #include <getopt.h>
15 #include "mips32.h"
16 #include "runmips.h"
18 int enable_disass = 0;
19 int enable_disass_user= 0; // Enable disass once we reach user code (0x4...)
20 int enable_verb_elf = 0;
21 int enable_forwarding = 0;
22 int enable_fastbranch = 0;
23 int enable_testcases = 0;
24 int enable_regwrites = 1; // XXX
25 int enable_firmware_mode = 0;
26 int enable_cosimulation = 0;
27 int enable_graphics = 0;
29 int endian_is_big = 0;
30 struct timeval stat_start_time, stat_stop_time;
32 void *memory_segment[NSEGMENT];
33 unsigned memory_segment_size[NSEGMENT];
35 unsigned program_entry = 0;
36 static SDL_Surface *screen;
39 * struct option {
40 * const char *name;
41 * int has_arg;
42 * int *flag;
43 * int val;
44 * };
47 static int run = '1';
48 static char *filename = 0;
51 static struct option long_options[] = {
52 {"help", 0, NULL, '?'},
53 {"bin-generation", 0, &run, 'b'}, // for Terasic Control panel
54 {"data-generation",0, &run, 'd'}, // for Icarus Verilog simulation
55 {"hex-generation", 0, &run, 'h'}, // for Quartus (HEX)
56 {"mif-generation", 0, &run, 'm'}, // for Quartus (MIF)
57 {"tinymon-generation", 0, &run, 't'}, // for Tinymon
58 {"forward-values", 0, &enable_forwarding, 1},
59 {"fast-branch", 0, &enable_fastbranch, 1},
60 {"verbose", 0, &enable_disass, 1},
61 {"disass-usercode",0, &enable_disass_user, 1},
62 {"elf-header", 0, &enable_verb_elf, 1},
63 {"testcases", 0, &enable_testcases, 1},
64 {"regwrites", 0, &enable_regwrites, 1},
65 {"firmware", 0, &enable_firmware_mode, 1}, // load only .text
66 {"cosimulation", 0, &enable_cosimulation, 1},
67 {"graphics", 0, &enable_graphics, 1},
68 {"icache-way-lines-log2", 1, 0, 1000},
69 {"icache-words-in-line-log2", 1, 0, 1001},
70 {"dcache-way-lines-log2", 1, 0, 1002},
71 {"dcache-words-in-line-log2", 1, 0, 1003},
72 // {"file", 1, 0, 'f'}, // 1 = required arg
73 // {"serial_in", 1, 0, 'i'}, // 1 = required arg
74 // {"serial_out", 1, 0, 'o'}, // 1 = required arg
75 {0, 0, 0, 0}
79 void usage(char *program)
81 int i;
83 if (strchr(program, '/')) {
84 program = strrchr(program, '/') + 1;
87 fprintf(stderr,
88 "YARI ISA Simulator\n"
89 "\n"
90 "Usage: %s [options] <mips-elf-files ...>\n"
91 "\n"
92 " where options can be one or more of\n"
93 "\n",
94 program);
96 for (i = 0; long_options[i].name; ++i) {
97 fprintf(stderr, " --%s\n", long_options[i].name);
100 fprintf(stderr,
101 " -i serialtty/file\n"
102 " -s serialtty/file\n"
103 "\n"
104 "Comments to <tommy-git@thorn.ws>\n");
106 exit(1);
109 void print_stats(void)
111 gettimeofday(&stat_stop_time, NULL);
113 double delta = stat_stop_time.tv_sec - stat_start_time.tv_sec
114 + 1e-6 * (stat_stop_time.tv_usec - stat_start_time.tv_usec);
116 putchar('\n');
117 printf("Simulation of %llu instructions in %4.2fs ~= %4.6f MIPS \n",
118 n_issue, delta, n_issue / (1e6 * delta));
120 // printf("%4.2f%% jal\n", 100.0 * n_call / n_issue);
121 printf("I$ %llu hits / %llu misses = %4.2f%% miss rate\n",
122 n_icache_hits, n_icache_misses,
123 100.0 * n_icache_misses / (n_icache_hits + n_icache_misses));
125 if (enable_cosimulation) {
126 double freq = 25.0;
128 printf("RTL stalls %llu\n", n_stall);
129 printf("RTL CPI: %4.2f ", (double) n_cycle / (double) n_issue);
130 printf("Cosim speed %4.2fX slower than realtime (assuming %g MHz)\n",
131 freq * 1e6 / (n_cycle / delta), freq);
134 printf("Gen load hazards: %12"PRIu64" (%5.2f%%)\n", stat_gen_load_hazard,
135 stat_gen_load_hazard * 100.0 / n_issue);
137 printf("Load use hazards, rs: %12"PRIu64" (%5.2f%%)\n", stat_load_use_hazard_rs,
138 stat_load_use_hazard_rs * 100.0 / n_issue);
140 printf(" rt: %12"PRIu64" (%5.2f%%)\n", stat_load_use_hazard_rt,
141 stat_load_use_hazard_rt * 100.0 / n_issue);
143 printf("LW use hazards: %12"PRIu64" (%5.2f%%)\n", stat_load32_use_hazard,
144 stat_load32_use_hazard * 100.0 / n_issue);
145 printf("Shift use hazards: %12"PRIu64" (%5.2f%%)\n", stat_shift_use_hazard,
146 stat_shift_use_hazard * 100.0 / n_issue);
147 printf("Nops: %12"PRIu64" (%5.2f%%)\n", stat_nop,
148 stat_nop * 100.0 / n_issue);
149 printf("Nops in delay slots: %12"PRIu64" (%5.2f%%)\n", stat_nop_delay_slots,
150 stat_nop_delay_slots * 100.0 / n_issue);
151 printf("Nops after loads that aren't needed:\n"
152 " %12"PRIu64" (%5.2f%%)\n", stat_nop_useless,
153 stat_nop_useless * 100.0 / n_issue);
156 void mainloop(void)
158 unsigned last_generation = 0;
160 for (;;) {
161 SDL_Event event;
163 while (SDL_PollEvent(&event)) {
164 switch (event.type) {
165 case SDL_MOUSEMOTION:
166 /*printf("Mouse moved by %d,%d to (%d,%d)\n",
167 event.motion.xrel, event.motion.yrel,
168 event.motion.x, event.motion.y);*/
169 break;
170 case SDL_MOUSEBUTTONDOWN:
171 /*printf("Mouse button %d pressed at (%d,%d)\n",
172 event.button.button, event.button.x, event.button.y);*/
173 break;
174 case SDL_KEYDOWN:
175 //printf("Key down: %s\n", SDL_GetKeyName(event.key.keysym.sym));
176 switch (event.key.keysym.sym) {
177 case SDLK_ESCAPE: return;
178 case SDLK_0: keys |= 1 << 0; break;
179 case SDLK_1: keys |= 1 << 1; break;
180 case SDLK_2: keys |= 1 << 2; break;
181 case SDLK_3: keys |= 1 << 3; break;
182 case SDLK_4: keys |= 1 << 4; break;
183 case SDLK_5: keys |= 1 << 5; break;
184 case SDLK_6: keys |= 1 << 6; break;
185 case SDLK_7: keys |= 1 << 7; break;
186 case SDLK_8: keys |= 1 << 8; break;
187 case SDLK_9: keys |= 1 << 9; break;
188 default: break;
190 break;
191 case SDL_KEYUP:
192 //printf("Key down: %s\n", SDL_GetKeyName(event.key.keysym.sym));
193 switch (event.key.keysym.sym) {
194 case SDLK_ESCAPE: return;
195 case SDLK_0: keys &= ~(1 << 0); break;
196 case SDLK_1: keys &= ~(1 << 1); break;
197 case SDLK_2: keys &= ~(1 << 2); break;
198 case SDLK_3: keys &= ~(1 << 3); break;
199 case SDLK_4: keys &= ~(1 << 4); break;
200 case SDLK_5: keys &= ~(1 << 5); break;
201 case SDLK_6: keys &= ~(1 << 6); break;
202 case SDLK_7: keys &= ~(1 << 7); break;
203 case SDLK_8: keys &= ~(1 << 8); break;
204 case SDLK_9: keys &= ~(1 << 9); break;
205 default: break;
207 break;
208 case SDL_QUIT:
209 //printf("Quit\n");
210 return;
211 default:
212 //printf("Unknown event: %d\n", event.type);
213 break;
217 /* Only update the screen if the framebuffer has been written
218 since last update */
219 if (last_generation != framebuffer_generation) {
220 last_generation = framebuffer_generation;
221 memcpy(screen->pixels, addr2phys(framebuffer_start),
222 framebuffer_size);
224 SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
225 // SDL_Flip(screen); either seem to work
228 SDL_Delay(1000 / 30); // 30 fps
232 void start_sdl(void)
234 framebuffer_start = 0x40000000 + 1024*1024;
235 framebuffer_size = 1024*768;
237 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
238 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
239 return;
242 atexit(SDL_Quit);
244 screen = SDL_SetVideoMode(1024, 768, 8, SDL_SWSURFACE);
245 if (screen == NULL) {
246 fprintf(stderr, "Unable to set video: %s\n", SDL_GetError());
247 return;
250 /* Set the window caption */
251 SDL_WM_SetCaption("Yarisim framebuffer", "YARISIM");
253 /* Populate the palette */
254 SDL_Color colors[256];
255 int i;
257 /* Fill colors with color information RGB332 */
258 for (i = 0; i < 256; ++i) {
259 colors[i].r = (i >> 5) * (255 / 7.0);
260 colors[i].g = ((i >> 2) & 7) * (255 / 7.0);
261 colors[i].b = (i & 3) * (255 / 3.0);
264 /* Set palette */
265 if (!SDL_SetColors(screen, colors, 0, 256)) {
266 fprintf(stderr, "Unable to create framebuffer palette: %s\n",
267 SDL_GetError());
268 screen = 0; //XXX should free it
269 return;
273 static void
274 dump_cache_init_files(void)
276 const char *ext = (run == 'm' ? "mif" :
277 run == 'h' ? "hex" :
278 run == 'b' ? "bin" :
279 "data");
281 if (icache_way_lines_log2 == 0) {
282 printf("Please provide log2 of the number of I$ lines pr way with --icache_way_lines_log2\n");
283 exit(1);
286 if (dcache_way_lines_log2 == 0) {
287 printf("Please provide log2 of the number of D$ lines pr way with --dcache_way_lines_log2\n");
288 exit(1);
291 if (icache_words_in_line_log2 == 0) {
292 printf("Please provide log2 of the number of words in I$ lines --icache-words-in-line-log2");
293 exit(1);
296 if (dcache_words_in_line_log2 == 0) {
297 printf("Please provide log2 of the number of words in D$ lines --dcache-words-in-line-log2");
298 exit(1);
301 uint32_t data_start = 0x400e0000; // XXX Ough
302 uint32_t num_icache_lines = 1 << icache_way_lines_log2;
303 uint32_t icache_line_size = 4 << icache_words_in_line_log2;
304 uint32_t icache_way_size = icache_line_size * num_icache_lines;
305 uint32_t icache_size = 4 * icache_way_size;
306 uint32_t icache_tag_width = 32 - icache_way_lines_log2 - icache_words_in_line_log2 - 2;
308 uint32_t num_dcache_lines = 1 << dcache_way_lines_log2;
309 uint32_t dcache_line_size = 4 << dcache_words_in_line_log2;
310 uint32_t dcache_way_size = dcache_line_size * num_dcache_lines;
311 uint32_t dcache_size = 4 * dcache_way_size;
312 uint32_t dcache_tag_width = 32 - dcache_way_lines_log2 - dcache_words_in_line_log2 - 2;
314 uint32_t start, tag;
315 char filename[99];
316 int way, i;
317 uint32_t *tags;
319 printf("%2d KiB 4-way I$, organized as %d cache lines, each line being %d bytes\n",
320 icache_size / 1024, 1 << icache_way_lines_log2, icache_line_size);
321 printf("%2d KiB 4-way D$, organized as %d cache lines, each line being %d bytes\n",
322 dcache_size / 1024, 1 << dcache_way_lines_log2, dcache_line_size);
324 /* I$ data */
325 for (way = 0, start = text_start; way < 4; ++way, start += icache_way_size) {
326 snprintf(filename, sizeof filename, "icache_ram%d.%s", way, ext);
327 dump(filename, run, 32, NULL, start, icache_way_size);
330 /* D$ data */
331 for (way = 0, start = data_start; way < 4; ++way, start += dcache_way_size) {
332 snprintf(filename, sizeof filename, "dcache_ram%d.%s", way, ext);
333 dump(filename, run, 32, NULL, start, dcache_way_size);
336 /* I$ tags. */
337 tags = malloc(num_icache_lines * sizeof tags[0]);
338 assert(tags);
340 /* This is the tricky part: the tag identifies
341 the non-index part of the physical address,
342 thus all but the way index */
343 tag = text_start >> (2 + icache_words_in_line_log2 + icache_way_lines_log2);
344 for (way = 0, start = text_start; way < 4; ++way, start += icache_line_size * 4, ++tag) {
345 for (i = 0; i < 1 << icache_way_lines_log2; ++i)
346 tags[i] = tag;
347 snprintf(filename, sizeof filename, "icache_tag%d.%s", way, ext);
348 dump(filename, run, icache_tag_width, tags, 0, num_icache_lines * sizeof tags[0]);
350 free(tags);
353 /* D$ tags. */
354 tags = malloc(num_dcache_lines * sizeof tags[0]);
355 assert(tags);
357 /* This is the tricky part: the tag identifies
358 the non-index part of the physical address,
359 thus all but the way index */
360 tag = data_start >> (2 + dcache_words_in_line_log2 + dcache_way_lines_log2);
361 for (way = 0, start = data_start; way < 4; ++way, start += dcache_line_size * 4, ++tag) {
362 for (i = 0; i < 1 << dcache_way_lines_log2; ++i)
363 tags[i] = tag;
364 snprintf(filename, sizeof filename, "dcache_tag%d.%s", way, ext);
365 dump(filename, run, dcache_tag_width, tags, 0, num_dcache_lines * sizeof tags[0]);
367 free(tags);
370 exit(0);
374 int main(int argc, char **argv)
376 /* The Global MIPS State */
377 MIPS_state_t mips_state;
379 rs232in_fd = rs232out_fd = -1;
380 char *serial_input_file = NULL;
381 char *serial_output_file = NULL;
383 for (;;) {
384 int c;
385 int option_index = 0;
387 c = getopt_long(argc, argv, "tf:i:o:",
388 long_options, &option_index);
389 if (c == -1)
390 break;
392 switch (c) {
393 case 0:
394 break;
396 case 'f':
397 printf("file %s\n", filename = optarg);
398 break;
400 case 'i': serial_input_file = optarg; break;
401 case 'o': serial_output_file = optarg; break;
402 case '?':
403 usage(argv[0]);
404 break;
406 case 1000: icache_way_lines_log2 = atoi(optarg); break;
407 case 1001: icache_words_in_line_log2 = atoi(optarg); break;
408 case 1002: dcache_way_lines_log2 = atoi(optarg); break;
409 case 1003: dcache_words_in_line_log2 = atoi(optarg); break;
411 default:
412 printf ("?? getopt returned character code 0%o ??\n", c);
416 if (optind >= argc) {
417 usage(argv[0]);
420 while (optind < argc) {
421 readelf(argv[optind++]);
424 int is_bidir = serial_output_file && serial_input_file &&
425 strcmp(serial_input_file, serial_output_file) == 0;
427 if (serial_input_file) {
428 printf("serial input %s\n", serial_input_file);
429 rs232in_fd = open(serial_input_file, (is_bidir ? O_RDWR : O_RDONLY) | O_NONBLOCK);
430 if (rs232in_fd < 0)
431 perror(optarg), exit(1);
434 /* Turn off echo */
435 struct termios t;
436 if (tcgetattr(rs232in_fd, &t))
437 /*perror("getattr")*/;
438 else {
439 t.c_lflag &= ~(ECHO|ECHOE|ECHOK);
440 if (tcsetattr(rs232in_fd, TCSANOW, &t))
441 perror("setattr");
446 if (serial_output_file && !is_bidir) {
447 printf("serial output %s\n", serial_output_file);
448 rs232out_fd = open(serial_output_file, O_WRONLY | O_NONBLOCK);
449 if (rs232out_fd < 0)
450 perror(optarg), exit(1);
453 if (is_bidir)
454 rs232out_fd = rs232in_fd;
456 gettimeofday(&stat_start_time, NULL);
458 switch (run) {
459 case '1':
460 if (enable_graphics)
461 start_sdl();
462 atexit(print_stats);
463 signal(SIGINT, exit);
464 mips_state.pc = program_entry;
465 init_reg_use_map();
467 if (screen) {
468 SDL_CreateThread((int (*)(void *))run_simple, &mips_state);
469 mainloop();
470 } else
471 run_simple(&mips_state);
472 break;
474 case 'b':
475 case 'r':
476 case 'd':
477 case 'm':
478 dump_cache_init_files();
479 break;
481 case 't':
482 dump_tinymon();
483 exit(0);
485 default:
486 printf("No XX-run option given\n");
487 exit(1);
490 if (enable_testcases) {
491 printf("Test ");
492 if (mips_state.r[7] == 0x1729) {
493 printf("SUCCEED!\n");
494 exit(0);
495 } else {
496 printf("FAILED! r7 = 0x%08x != 0x1729\n", mips_state.r[7]);
497 exit(1);
501 exit(0);
504 // Local Variables:
505 // mode: C
506 // c-style-variables-are-local-p: t
507 // c-file-style: "linux"
508 // End: