YARISIM: Simulate a framebuffer
[yari.git] / yarisim / sim.c
blobc786f1531aae3826c06d117f7a37017026aaab69
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;
28 int endian_is_big = 0;
29 struct timeval stat_start_time, stat_stop_time;
31 void *memory_segment[NSEGMENT];
32 unsigned memory_segment_size[NSEGMENT];
34 unsigned program_entry = 0;
35 static SDL_Surface *screen;
38 * struct option {
39 * const char *name;
40 * int has_arg;
41 * int *flag;
42 * int val;
43 * };
46 static int run = '1';
47 static char *filename = 0;
50 static struct option long_options[] = {
51 {"help", 0, NULL, '?'},
52 {"data-generation",0, &run, 'd'}, // for Icarus Verilog simulation
53 {"hex-generation", 0, &run, 'h'}, // for Quartus (HEX)
54 {"mif-generation", 0, &run, 'm'}, // for Quartus (MIF)
55 {"tinymon-generation", 0, &run, 't'}, // for Tinymon
56 {"forward-values", 0, &enable_forwarding, 1},
57 {"fast-branch", 0, &enable_fastbranch, 1},
58 {"verbose", 0, &enable_disass, 1},
59 {"disass-usercode",0, &enable_disass_user, 1},
60 {"elf-header", 0, &enable_verb_elf, 1},
61 {"testcases", 0, &enable_testcases, 1},
62 {"regwrites", 0, &enable_regwrites, 1},
63 {"firmware", 0, &enable_firmware_mode, 1}, // load only .text
64 {"cosimulation", 0, &enable_cosimulation, 1},
65 // {"file", 1, 0, 'f'}, // 1 = required arg
66 // {"serial_in", 1, 0, 'i'}, // 1 = required arg
67 // {"serial_out", 1, 0, 'o'}, // 1 = required arg
68 {0, 0, 0, 0}
72 void usage(char *program)
74 int i;
76 if (strchr(program, '/')) {
77 program = strrchr(program, '/') + 1;
80 fprintf(stderr,
81 "YARI ISA Simulator\n"
82 "\n"
83 "Usage: %s [options] <mips-elf-files ...>\n"
84 "\n"
85 " where options can be one or more of\n"
86 "\n",
87 program);
89 for (i = 0; long_options[i].name; ++i) {
90 fprintf(stderr, " --%s\n", long_options[i].name);
93 fprintf(stderr,
94 " -i serialtty/file\n"
95 " -s serialtty/file\n"
96 "\n"
97 "Comments to <tommy-git@thorn.ws>\n");
99 exit(1);
102 void print_stats(void)
104 gettimeofday(&stat_stop_time, NULL);
106 double delta = stat_stop_time.tv_sec - stat_start_time.tv_sec
107 + 1e-6 * (stat_stop_time.tv_usec - stat_start_time.tv_usec);
109 putchar('\n');
110 printf("Simulation of %llu instructions in %4.2fs ~= %4.6f MIPS \n",
111 n_issue, delta, n_issue / (1e6 * delta));
113 // printf("%4.2f%% jal\n", 100.0 * n_call / n_issue);
114 printf("I$ %llu hits / %llu misses = %4.2f%% miss rate\n",
115 n_icache_hits, n_icache_misses,
116 100.0 * n_icache_misses / (n_icache_hits + n_icache_misses));
118 if (enable_cosimulation) {
119 double freq = 25.0;
121 printf("RTL stalls %llu\n", n_stall);
122 printf("RTL CPI: %4.2f ", (double) n_cycle / (double) n_issue);
123 printf("Cosim speed %4.2fX slower than realtime (assuming %g MHz)\n",
124 freq * 1e6 / (n_cycle / delta), freq);
127 printf("Gen load hazards: %12llu (%5.2f%%)\n", stat_gen_load_hazard,
128 stat_gen_load_hazard * 100.0 / n_issue);
130 printf("Load use hazards, rs: %12llu (%5.2f%%)\n", stat_load_use_hazard_rs,
131 stat_load_use_hazard_rs * 100.0 / n_issue);
133 printf(" rt: %12llu (%5.2f%%)\n", stat_load_use_hazard_rt,
134 stat_load_use_hazard_rt * 100.0 / n_issue);
136 printf("LW use hazards: %12llu (%5.2f%%)\n", stat_load32_use_hazard,
137 stat_load32_use_hazard * 100.0 / n_issue);
138 printf("Shift use hazards: %12llu (%5.2f%%)\n", stat_shift_use_hazard,
139 stat_shift_use_hazard * 100.0 / n_issue);
140 printf("Nops: %12llu (%5.2f%%)\n", stat_nop,
141 stat_nop * 100.0 / n_issue);
142 printf("Nops in delay slots: %12llu (%5.2f%%)\n", stat_nop_delay_slots,
143 stat_nop_delay_slots * 100.0 / n_issue);
144 printf("Nops after loads that aren't needed:\n"
145 " %12llu (%5.2f%%)\n", stat_nop_useless,
146 stat_nop_useless * 100.0 / n_issue);
149 void mainloop(void)
151 unsigned last_generation = 0;
153 for (;;) {
154 SDL_Event event;
156 while (SDL_PollEvent(&event)) {
157 switch (event.type) {
158 case SDL_MOUSEMOTION:
159 /*printf("Mouse moved by %d,%d to (%d,%d)\n",
160 event.motion.xrel, event.motion.yrel,
161 event.motion.x, event.motion.y);*/
162 break;
163 case SDL_MOUSEBUTTONDOWN:
164 /*printf("Mouse button %d pressed at (%d,%d)\n",
165 event.button.button, event.button.x, event.button.y);*/
166 break;
167 case SDL_KEYDOWN:
168 //printf("Key down: %s\n", SDL_GetKeyName(event.key.keysym.sym));
169 if (event.key.keysym.sym == SDLK_ESCAPE)
170 return;
171 break;
172 case SDL_KEYUP:
173 //printf("Key down: %s\n", SDL_GetKeyName(event.key.keysym.sym));
174 break;
175 case SDL_QUIT:
176 printf("Quit\n");
177 return;
178 default:
179 //printf("Unknown event: %d\n", event.type);
180 break;
184 /* Only update the screen if the framebuffer has been written
185 since last update */
186 if (last_generation != framebuffer_generation) {
187 last_generation = framebuffer_generation;
188 memcpy(screen->pixels, addr2phys(framebuffer_start),
189 framebuffer_size);
191 SDL_UpdateRect(screen, 0, 0, screen->w, screen->h);
192 // SDL_Flip(screen); either seem to work
195 SDL_Delay(1000 / 30); // 30 fps
199 void start_sdl(void)
201 framebuffer_start = 0x40000000 + 1024*1024;
202 framebuffer_size = 1024*768;
204 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
205 fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
206 return;
209 atexit(SDL_Quit);
211 screen = SDL_SetVideoMode(1024, 768, 8, SDL_SWSURFACE);
212 if (screen == NULL) {
213 fprintf(stderr, "Unable to set video: %s\n", SDL_GetError());
214 return;
217 /* Set the window caption */
218 SDL_WM_SetCaption("Yarisim framebuffer", "YARISIM");
220 /* Populate the palette */
221 SDL_Color colors[256];
222 int i;
224 /* Fill colors with color information RGB332 */
225 for (i = 0; i < 256; ++i) {
226 colors[i].r = (i >> 5) * (255 / 7.0);
227 colors[i].g = ((i >> 2) & 7) * (255 / 7.0);
228 colors[i].b = (i & 3) * (255 / 3.0);
231 /* Set palette */
232 if (!SDL_SetColors(screen, colors, 0, 256)) {
233 fprintf(stderr, "Unable to create framebuffer palette: %s\n",
234 SDL_GetError());
235 screen = 0; //XXX should free it
236 return;
240 int main(int argc, char **argv)
242 /* The Global MIPS State */
243 MIPS_state_t mips_state;
245 rs232in_fd = rs232out_fd = -1;
246 char *serial_input_file = NULL;
247 char *serial_output_file = NULL;
249 for (;;) {
250 int c;
251 int option_index = 0;
253 c = getopt_long(argc, argv, "tf:i:o:",
254 long_options, &option_index);
255 if (c == -1)
256 break;
258 switch (c) {
259 case 0:
260 break;
262 case 'f':
263 printf("file %s\n", filename = optarg);
264 break;
266 case 'i': serial_input_file = optarg; break;
267 case 'o': serial_output_file = optarg; break;
268 case '?':
269 usage(argv[0]);
270 break;
272 default:
273 printf ("?? getopt returned character code 0%o ??\n", c);
277 if (optind >= argc) {
278 usage(argv[0]);
281 while (optind < argc) {
282 readelf(argv[optind++]);
285 if (serial_input_file) {
286 printf("serial input %s\n", serial_input_file);
287 rs232in_fd = open(serial_input_file, O_RDONLY | O_NONBLOCK);
288 if (rs232in_fd < 0)
289 perror(optarg), exit(1);
292 /* Turn off echo */
293 struct termios t;
294 if (tcgetattr(rs232in_fd, &t))
295 /*perror("getattr")*/;
296 else {
297 t.c_lflag &= ~(ECHO|ECHOE|ECHOK);
298 if (tcsetattr(rs232in_fd, TCSANOW, &t))
299 perror("setattr");
304 if (serial_output_file) {
305 printf("serial output %s\n", serial_output_file);
306 rs232out_fd = open(serial_output_file, O_WRONLY | O_NONBLOCK);
307 if (rs232out_fd < 0)
308 perror(optarg), exit(1);
311 gettimeofday(&stat_start_time, NULL);
313 switch (run) {
314 case '1':
315 start_sdl();
316 atexit(print_stats);
317 signal(SIGINT, exit);
318 mips_state.pc = program_entry;
319 init_reg_use_map();
321 if (screen) {
322 SDL_CreateThread((int (*)(void *))run_simple, &mips_state);
323 mainloop();
324 } else
325 run_simple(&mips_state);
326 break;
328 case 'r':
329 case 'd':
330 case 'm':
331 dump(run);
332 exit(0);
334 case 't':
335 dump_tinymon();
336 exit(0);
338 default:
339 printf("No XX-run option given\n");
340 exit(1);
343 if (enable_testcases) {
344 printf("Test ");
345 if (mips_state.r[7] == 0x1729) {
346 printf("SUCCEED!\n");
347 exit(0);
348 } else {
349 printf("FAILED! r7 = 0x%08x != 0x1729\n", mips_state.r[7]);
350 exit(1);
354 exit(0);
357 // Local Variables:
358 // mode: C
359 // c-style-variables-are-local-p: t
360 // c-file-style: "linux"
361 // End: