11 #include <netinet/in.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
;
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
79 void usage(char *program
)
83 if (strchr(program
, '/')) {
84 program
= strrchr(program
, '/') + 1;
88 "YARI ISA Simulator\n"
90 "Usage: %s [options] <mips-elf-files ...>\n"
92 " where options can be one or more of\n"
96 for (i
= 0; long_options
[i
].name
; ++i
) {
97 fprintf(stderr
, " --%s\n", long_options
[i
].name
);
101 " -i serialtty/file\n"
102 " -s serialtty/file\n"
104 "Comments to <tommy-git@thorn.ws>\n");
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
);
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
) {
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: %12llu (%5.2f%%)\n", stat_gen_load_hazard
,
135 stat_gen_load_hazard
* 100.0 / n_issue
);
137 printf("Load use hazards, rs: %12llu (%5.2f%%)\n", stat_load_use_hazard_rs
,
138 stat_load_use_hazard_rs
* 100.0 / n_issue
);
140 printf(" rt: %12llu (%5.2f%%)\n", stat_load_use_hazard_rt
,
141 stat_load_use_hazard_rt
* 100.0 / n_issue
);
143 printf("LW use hazards: %12llu (%5.2f%%)\n", stat_load32_use_hazard
,
144 stat_load32_use_hazard
* 100.0 / n_issue
);
145 printf("Shift use hazards: %12llu (%5.2f%%)\n", stat_shift_use_hazard
,
146 stat_shift_use_hazard
* 100.0 / n_issue
);
147 printf("Nops: %12llu (%5.2f%%)\n", stat_nop
,
148 stat_nop
* 100.0 / n_issue
);
149 printf("Nops in delay slots: %12llu (%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 " %12llu (%5.2f%%)\n", stat_nop_useless
,
153 stat_nop_useless
* 100.0 / n_issue
);
158 unsigned last_generation
= 0;
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);*/
170 case SDL_MOUSEBUTTONDOWN
:
171 /*printf("Mouse button %d pressed at (%d,%d)\n",
172 event.button.button, event.button.x, event.button.y);*/
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;
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;
212 //printf("Unknown event: %d\n", event.type);
217 /* Only update the screen if the framebuffer has been written
219 if (last_generation
!= framebuffer_generation
) {
220 last_generation
= framebuffer_generation
;
221 memcpy(screen
->pixels
, addr2phys(framebuffer_start
),
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
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());
244 screen
= SDL_SetVideoMode(1024, 768, 8, SDL_SWSURFACE
);
245 if (screen
== NULL
) {
246 fprintf(stderr
, "Unable to set video: %s\n", SDL_GetError());
250 /* Set the window caption */
251 SDL_WM_SetCaption("Yarisim framebuffer", "YARISIM");
253 /* Populate the palette */
254 SDL_Color colors
[256];
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);
265 if (!SDL_SetColors(screen
, colors
, 0, 256)) {
266 fprintf(stderr
, "Unable to create framebuffer palette: %s\n",
268 screen
= 0; //XXX should free it
273 int main(int argc
, char **argv
)
275 /* The Global MIPS State */
276 MIPS_state_t mips_state
;
278 rs232in_fd
= rs232out_fd
= -1;
279 char *serial_input_file
= NULL
;
280 char *serial_output_file
= NULL
;
284 int option_index
= 0;
286 c
= getopt_long(argc
, argv
, "tf:i:o:",
287 long_options
, &option_index
);
296 printf("file %s\n", filename
= optarg
);
299 case 'i': serial_input_file
= optarg
; break;
300 case 'o': serial_output_file
= optarg
; break;
305 case 1000: icache_way_lines_log2
= atoi(optarg
); break;
306 case 1001: icache_words_in_line_log2
= atoi(optarg
); break;
307 case 1002: dcache_way_lines_log2
= atoi(optarg
); break;
308 case 1003: dcache_words_in_line_log2
= atoi(optarg
); break;
311 printf ("?? getopt returned character code 0%o ??\n", c
);
315 if (optind
>= argc
) {
319 while (optind
< argc
) {
320 readelf(argv
[optind
++]);
323 int is_bidir
= serial_output_file
&& serial_input_file
&&
324 strcmp(serial_input_file
, serial_output_file
) == 0;
326 if (serial_input_file
) {
327 printf("serial input %s\n", serial_input_file
);
328 rs232in_fd
= open(serial_input_file
, (is_bidir
? O_RDWR
: O_RDONLY
) | O_NONBLOCK
);
330 perror(optarg
), exit(1);
335 if (tcgetattr(rs232in_fd
, &t
))
336 /*perror("getattr")*/;
338 t
.c_lflag
&= ~(ECHO
|ECHOE
|ECHOK
);
339 if (tcsetattr(rs232in_fd
, TCSANOW
, &t
))
345 if (serial_output_file
&& !is_bidir
) {
346 printf("serial output %s\n", serial_output_file
);
347 rs232out_fd
= open(serial_output_file
, O_WRONLY
| O_NONBLOCK
);
349 perror(optarg
), exit(1);
353 rs232out_fd
= rs232in_fd
;
355 gettimeofday(&stat_start_time
, NULL
);
362 signal(SIGINT
, exit
);
363 mips_state
.pc
= program_entry
;
367 SDL_CreateThread((int (*)(void *))run_simple
, &mips_state
);
370 run_simple(&mips_state
);
377 if (icache_way_lines_log2
== 0) {
378 printf("Please provide log2 of the number of I$ lines pr way with --icache_way_lines_log2\n");
382 if (dcache_way_lines_log2
== 0) {
383 printf("Please provide log2 of the number of D$ lines pr way with --dcache_way_lines_log2\n");
387 if (icache_words_in_line_log2
== 0) {
388 printf("Please provide log2 of the number of words in I$ lines --icache-words-in-line-log2");
392 if (dcache_words_in_line_log2
== 0) {
393 printf("Please provide log2 of the number of words in D$ lines --dcache-words-in-line-log2");
398 uint32_t data_start
= 0x400e0000; // XXX Ough
399 uint32_t num_icache_lines
= 1 << icache_way_lines_log2
;
400 uint32_t icache_line_size
= 4 << icache_words_in_line_log2
;
401 uint32_t icache_way_size
= icache_line_size
* num_icache_lines
;
402 uint32_t icache_size
= 4 * icache_way_size
;
403 uint32_t num_dcache_lines
= 1 << dcache_way_lines_log2
;
404 uint32_t dcache_line_size
= 4 << dcache_words_in_line_log2
;
405 uint32_t dcache_way_size
= dcache_line_size
* num_dcache_lines
;
406 uint32_t dcache_size
= 4 * dcache_way_size
;
413 printf("%2d KiB 4-way I$, organized as %d cache lines, each line being %d bytes\n",
414 icache_size
/ 1024, 1 << icache_way_lines_log2
, icache_line_size
);
415 printf("%2d KiB 4-way D$, organized as %d cache lines, each line being %d bytes\n",
416 dcache_size
/ 1024, 1 << dcache_way_lines_log2
, dcache_line_size
);
419 for (way
= 0, start
= text_start
; way
< 4; ++way
, start
+= icache_way_size
) {
420 snprintf(filename
, sizeof filename
, "icache_ram%d.mif", way
);
421 dump(filename
, run
, NULL
, start
, icache_way_size
);
425 for (way
= 0, start
= data_start
; way
< 4; ++way
, start
+= dcache_way_size
) {
426 snprintf(filename
, sizeof filename
, "dcache_ram%d.mif", way
);
427 dump(filename
, run
, NULL
, start
, dcache_way_size
);
431 tags
= malloc(num_icache_lines
* sizeof tags
[0]);
434 /* This is the tricky part: the tag identifies
435 the non-index part of the physical address,
436 thus all but the way index */
437 tag
= text_start
>> (2 + icache_words_in_line_log2
+ icache_way_lines_log2
);
438 for (way
= 0, start
= text_start
; way
< 4; ++way
, start
+= icache_line_size
* 4, ++tag
) {
439 for (i
= 0; i
< 1 << icache_way_lines_log2
; ++i
)
441 snprintf(filename
, sizeof filename
, "icache_tag%d.mif", way
);
442 dump(filename
, run
, tags
, 0, num_icache_lines
* sizeof tags
[0]);
448 tags
= malloc(num_dcache_lines
* sizeof tags
[0]);
451 /* This is the tricky part: the tag identifies
452 the non-index part of the physical address,
453 thus all but the way index */
454 tag
= data_start
>> (2 + dcache_words_in_line_log2
+ dcache_way_lines_log2
);
455 for (way
= 0, start
= data_start
; way
< 4; ++way
, start
+= dcache_line_size
* 4, ++tag
) {
456 for (i
= 0; i
< 1 << dcache_way_lines_log2
; ++i
)
458 snprintf(filename
, sizeof filename
, "dcache_tag%d.mif", way
);
459 dump(filename
, run
, tags
, 0, num_dcache_lines
* sizeof tags
[0]);
473 printf("No XX-run option given\n");
477 if (enable_testcases
) {
479 if (mips_state
.r
[7] == 0x1729) {
480 printf("SUCCEED!\n");
483 printf("FAILED! r7 = 0x%08x != 0x1729\n", mips_state
.r
[7]);
493 // c-style-variables-are-local-p: t
494 // c-file-style: "linux"