Commit | Line | Data |
---|---|---|
92fa4579 FCE |
1 | /* GX target-independent functions for block translation. |
2 | Copyright (C) 1998 Cygnus Solutions. */ | |
3 | ||
4 | ||
5 | #include "sim-main.h" | |
6 | #include "sim-assert.h" | |
7 | #include "sim-gx.h" | |
8 | ||
9 | #include "config.h" | |
92fa4579 FCE |
10 | |
11 | /* shared object functions */ | |
12 | #ifdef HAVE_DLFCN_H | |
13 | #include <dlfcn.h> | |
14 | #else | |
15 | #error "need dlfcn.h" | |
16 | #endif | |
17 | ||
18 | #ifdef HAVE_ERRNO_H | |
19 | #include <errno.h> | |
20 | #else | |
21 | #error "need errno.h" | |
22 | #endif | |
23 | ||
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <limits.h> | |
27 | #ifdef HAVE_TIME_H | |
28 | #include <time.h> | |
29 | #endif | |
30 | #ifdef HAVE_UNISTD_H | |
31 | #include <unistd.h> | |
32 | #endif | |
33 | #ifdef HAVE_FCNTL_H | |
34 | #include <fcntl.h> | |
35 | #endif | |
36 | #ifdef HAVE_SYS_STAT_H | |
37 | #include <sys/stat.h> | |
38 | #endif | |
39 | ||
40 | #include "bfd.h" | |
41 | ||
42 | ||
43 | ||
44 | ||
45 | /* Load the object file with given gx block. Return pointer to GX | |
46 | function or NULL on failure. */ | |
47 | ||
48 | sim_gx_function | |
49 | sim_gx_compiled_block_f(sim_gx_compiled_block* gx) | |
50 | { | |
51 | sim_gx_function f = gx->function_dlhandle; | |
52 | SIM_DESC sd = current_state; | |
6402c01c | 53 | static int dlopened_main = 0; |
92fa4579 FCE |
54 | |
55 | if(f == NULL) | |
56 | { | |
92fa4579 FCE |
57 | /* load object */ |
58 | if(gx->object_dlhandle == NULL && gx->object_name != NULL) | |
59 | { | |
6402c01c FCE |
60 | if(! dlopened_main) |
61 | { | |
62 | /* dlopen executable itself first to share symbols with shared library */ | |
63 | void* exec_handle = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); | |
64 | if(exec_handle == NULL) | |
65 | { | |
66 | sim_io_error(sd, "Load error for executable: %s", | |
67 | dlerror()); | |
68 | } | |
69 | ||
70 | dlopened_main = 1; | |
71 | } | |
72 | ||
73 | /* dlopen the gx block dso itself */ | |
92fa4579 FCE |
74 | gx->object_dlhandle = dlopen(gx->object_name, RTLD_NOW); |
75 | if(gx->object_dlhandle == NULL) | |
76 | { | |
77 | sim_io_error(sd, "Load error for GX object %s: %s", | |
78 | gx->object_name, | |
79 | dlerror()); | |
80 | } | |
81 | } | |
82 | ||
83 | /* locate function */ | |
84 | if(gx->function_dlhandle == NULL && gx->object_dlhandle != NULL && gx->symbol_name != NULL) | |
85 | { | |
86 | f = gx->function_dlhandle = dlsym(gx->object_dlhandle, gx->symbol_name); | |
87 | if(f == NULL) | |
88 | { | |
89 | sim_io_error(sd, "Resolve error for GX object %s symbol %s: %s", | |
90 | gx->object_name, | |
91 | gx->symbol_name, | |
92 | dlerror()); | |
93 | } | |
94 | } | |
95 | } /* f == NULL */ | |
96 | ||
97 | return f; | |
98 | } | |
99 | ||
100 | ||
101 | ||
102 | /* Forget about given GX block. Remove its source/object; unload it | |
103 | from memory. */ | |
104 | void | |
105 | sim_gx_compiled_block_dispose(sim_gx_compiled_block* gx) | |
106 | { | |
107 | SIM_DESC sd = current_state; | |
108 | int rc; | |
3d7075f5 FCE |
109 | char compile_command[2000]; |
110 | char la_name[2000]; | |
92fa4579 FCE |
111 | |
112 | /* forget dl information */ | |
113 | gx->function_dlhandle = NULL; | |
114 | ||
115 | /* unload shared library */ | |
116 | if(gx->object_dlhandle != NULL) | |
117 | { | |
118 | rc = dlclose(gx->object_dlhandle); | |
119 | if(rc != 0) | |
120 | { | |
121 | sim_io_error(sd, "dlclose() error for GX object %s: %s", | |
122 | gx->object_name, | |
123 | dlerror()); | |
124 | } | |
125 | gx->object_dlhandle = NULL; | |
126 | } | |
127 | ||
3d7075f5 FCE |
128 | /* uninstall shared object */ |
129 | ||
130 | strcpy(la_name, gx->object_name); | |
131 | strcpy(strstr(la_name, ".so.0"), ".la"); | |
81271391 | 132 | sprintf(compile_command, "gxtool --silent --mode=uninstall rm -f %s", la_name); |
3d7075f5 FCE |
133 | |
134 | rc = system(compile_command); | |
135 | if(rc != 0) | |
136 | { | |
137 | sim_io_error(sd, "Error during finish: `%s' rc %d", | |
138 | compile_command, rc); | |
139 | } | |
140 | ||
141 | ||
142 | /* erase source */ | |
143 | /* sprintf(compile_command, "rm -f %s", block->source_name); */ | |
144 | ||
92fa4579 FCE |
145 | /* final gasps */ |
146 | zfree(gx->source_name); | |
147 | zfree(gx->object_name); | |
148 | zfree(gx->symbol_name); | |
149 | zfree(gx); | |
150 | } | |
151 | ||
152 | ||
153 | ||
154 | /* Translate a piece of the code segment around given PC, in given mode. */ | |
155 | sim_gx_block* | |
156 | sim_gx_block_create(sim_cia cia) | |
157 | { | |
158 | sim_gx_block* block; | |
159 | ||
160 | /* allocate emtpy block */ | |
161 | block = zalloc(sizeof(sim_gx_block)); | |
162 | ||
163 | /* initialize block bounds, callback struct etc. */ | |
164 | tgx_block_ctor(block, cia); | |
165 | ||
166 | /* create learning mode translation */ | |
167 | sim_gx_block_translate(block, 0 /* learning mode */); | |
168 | ||
169 | /* add block to block list */ | |
170 | sim_gx_block_add(block); | |
171 | ||
172 | return block; | |
173 | } | |
174 | ||
175 | ||
176 | ||
177 | /* Write the current block list to the state file */ | |
178 | void | |
179 | sim_gx_write_block_list() | |
180 | { | |
181 | int i; | |
182 | SIM_DESC sd = current_state; | |
183 | sim_gx_block_list* blocks = STATE_BLOCKS(sd); | |
184 | FILE* f; | |
185 | char state_file_name[PATH_MAX]; | |
186 | char *exec_name; | |
187 | ||
188 | /* get base of executable name */ | |
189 | exec_name = bfd_get_filename(STATE_PROG_BFD(sd)); | |
190 | if(strrchr(exec_name, '/') != NULL) | |
191 | exec_name = strrchr(exec_name, '/') + 1; | |
192 | ||
193 | /* generate base name */ | |
194 | sprintf(state_file_name, "%s/%s.gx", | |
195 | GX_DIR, | |
196 | exec_name); | |
197 | ||
198 | f = fopen(state_file_name, "w"); | |
199 | if(f == NULL) | |
200 | { | |
201 | sim_io_error(sd, "Error: cannot write to state file %s, errno %d", | |
202 | state_file_name, errno); | |
203 | } | |
204 | ||
205 | fprintf(f, "# This file was automatically generated. Do not edit.\n"); | |
206 | ||
207 | /* write block descriptors into state file */ | |
208 | for(i=0; i<blocks->gx_blocks_used; i++) | |
209 | { | |
210 | sim_gx_block* gx = blocks->gx_blocks[i]; | |
211 | sim_gx_compiled_block* block; | |
212 | int j; | |
213 | int age; | |
214 | ||
215 | age = time(NULL) - gx->learn_last_change; /* store interval */ | |
6402c01c | 216 | fprintf(f, "BLOCK 0x%x 0x%x %u %u\n", (unsigned)gx->origin, (unsigned)gx->length, gx->divisor, age); |
92fa4579 FCE |
217 | fprintf(f, "FLAGS "); |
218 | for(j=0; j<GX_PC_FLAGS_INDEX(gx, gx->origin + gx->length); j++) | |
219 | { | |
220 | fprintf(f, "%2x ", gx->pc_flags[j]); | |
221 | } | |
222 | fprintf(f, "\n"); | |
223 | ||
224 | /* write learning mode names */ | |
225 | block = gx->learning_block; | |
226 | fprintf(f, "LEARNING %s %s %s %lu %u\n", | |
227 | block->source_name, block->object_name, block->symbol_name, | |
228 | gx->compile_time, gx->opt_compile_count); | |
229 | ||
230 | /* write optimized mode names */ | |
231 | block = gx->optimized_block; | |
232 | if(block) | |
233 | fprintf(f, "OPTIMIZED %s %s %s\n", | |
234 | block->source_name, block->object_name, block->symbol_name); | |
235 | ||
236 | /* NB: other fields will be filled in with freshly guessed values */ | |
237 | } | |
238 | ||
239 | (void) fclose(f); | |
240 | } | |
241 | ||
242 | ||
243 | ||
244 | void | |
245 | print_gx_blocks(sim_gx_block_list* blocks, char* where) | |
246 | { | |
247 | printf("print_gx_blocks: %s\n", where); | |
248 | ||
249 | if(blocks == NULL) | |
250 | printf("(null)\n"); | |
251 | else | |
252 | { | |
253 | int i; | |
254 | printf("size: %d, used: %d\n", | |
255 | blocks->gx_blocks_size, blocks->gx_blocks_used); | |
256 | ||
257 | /* linear search */ | |
258 | for(i=0; i<blocks->gx_blocks_used; i++) | |
259 | { | |
260 | sim_gx_block* gx = blocks->gx_blocks[i]; | |
261 | printf("block %d: %p\n", i, (void*) gx); | |
262 | if(gx == NULL) | |
263 | printf("** NULL!\n"); | |
264 | else | |
265 | printf(" begin 0x%08x length 0x%08x [opt %d%s]\n", | |
266 | (unsigned)gx->origin, (unsigned)gx->length, | |
267 | gx->opt_compile_count, | |
268 | (gx->optimized_block ? " loaded" : " discarded")); | |
269 | } | |
270 | ||
271 | } | |
272 | } | |
273 | ||
274 | ||
275 | ||
276 | /* Read the current block list from the cache */ | |
277 | void | |
278 | sim_gx_read_block_list() | |
279 | { | |
280 | SIM_DESC sd = current_state; | |
281 | FILE* f; | |
282 | char state_file_name[PATH_MAX]; | |
6402c01c | 283 | const char *exec_name; |
92fa4579 FCE |
284 | |
285 | /* check for block */ | |
286 | if(STATE_PROG_BFD(sd) == NULL) | |
287 | return; | |
288 | ||
289 | /* get base of executable name */ | |
290 | exec_name = bfd_get_filename(STATE_PROG_BFD(sd)); | |
291 | if(strrchr(exec_name, '/') != NULL) | |
292 | exec_name = strrchr(exec_name, '/') + 1; | |
293 | ||
294 | /* generate base name */ | |
295 | sprintf(state_file_name, "%s/%s.gx", | |
296 | GX_DIR, | |
297 | exec_name); | |
298 | ||
299 | f = fopen(state_file_name, "r"); | |
300 | if(f == NULL) | |
301 | { | |
302 | /* XXX: print warning */ | |
303 | return; | |
304 | } | |
305 | ||
306 | fscanf(f, "#%*[^\n]\n"); /* swallow # comment line */ | |
307 | ||
308 | while(1) | |
309 | { | |
310 | unsigned_4 origin, length; | |
311 | unsigned divisor; | |
312 | sim_gx_block* gx; | |
313 | int rc; | |
314 | sim_gx_compiled_block* block; | |
315 | unsigned age; | |
316 | int j; | |
317 | ||
6402c01c | 318 | rc = fscanf(f, "BLOCK 0x%0x 0x%x %u %u\n", (unsigned*)& origin, (unsigned*)& length, & divisor, & age); |
92fa4579 FCE |
319 | if(rc != 4) /* not all fields matched - assume EOF */ |
320 | break; | |
321 | ||
322 | gx = zalloc(sizeof(sim_gx_block)); | |
323 | ||
324 | /* initialize block bounds, callback struct etc. */ | |
325 | tgx_block_ctor2(gx, origin, length, divisor); | |
326 | ||
327 | /* read flags */ | |
328 | fscanf(f, "FLAGS"); | |
329 | for(j=0; j<GX_PC_FLAGS_INDEX(gx, gx->origin + gx->length); j++) | |
330 | { | |
331 | unsigned value; | |
332 | fscanf(f, "%2x ", & value); | |
333 | gx->pc_flags[j] = (unsigned_1) value; | |
334 | } | |
335 | fscanf(f, "\n"); | |
336 | ||
337 | /* read learning mode info */ | |
338 | block = zalloc(sizeof(sim_gx_compiled_block)); | |
339 | gx->learning_block = block; | |
340 | block->source_name = zalloc(PATH_MAX); | |
341 | block->object_name = zalloc(PATH_MAX); | |
342 | block->symbol_name = zalloc(PATH_MAX); | |
6402c01c | 343 | fscanf(f, "LEARNING %s %s %s %u %u\n", |
92fa4579 | 344 | block->source_name, block->object_name, block->symbol_name, |
6402c01c | 345 | (unsigned*) & gx->compile_time, & gx->opt_compile_count); |
92fa4579 FCE |
346 | |
347 | /* read optimized mode info */ | |
348 | block = zalloc(sizeof(sim_gx_compiled_block)); | |
349 | gx->optimized_block = block; | |
350 | block->source_name = zalloc(PATH_MAX); | |
351 | block->object_name = zalloc(PATH_MAX); | |
352 | block->symbol_name = zalloc(PATH_MAX); | |
353 | rc = fscanf(f, "OPTIMIZED %s %s %s\n", | |
354 | block->source_name, block->object_name, block->symbol_name); | |
355 | if(rc != 3) | |
356 | { | |
357 | /* oops, not an optimized block */ | |
358 | zfree(block->source_name); | |
359 | zfree(block->object_name); | |
360 | zfree(block->symbol_name); | |
361 | zfree(block); | |
362 | gx->optimized_block = NULL; | |
363 | } | |
364 | ||
365 | /* fill in remaining fields */ | |
366 | gx->learn_last_change = time(NULL) - age; /* make absolute */ | |
367 | ||
368 | /* store it away */ | |
369 | sim_gx_block_add(gx); | |
370 | } | |
371 | ||
3d7075f5 | 372 | /* print_gx_blocks(STATE_BLOCKS(sd), "after restoring state"); */ |
92fa4579 FCE |
373 | } |
374 | ||
375 | ||
376 | ||
377 | ||
378 | ||
379 | ||
380 | /* Add a gx block to list */ | |
381 | void | |
382 | sim_gx_block_add(sim_gx_block* block) | |
383 | { | |
384 | SIM_DESC sd = current_state; | |
385 | sim_gx_block_list* blocks = STATE_BLOCKS(sd); | |
386 | int i; | |
387 | ||
388 | /* print_gx_blocks(blocks, "pre add"); */ | |
389 | ||
390 | if(blocks == NULL) | |
391 | blocks = STATE_BLOCKS(sd) = zalloc(sizeof(sim_gx_block_list)); | |
392 | ||
393 | /* need to enlarge block vector? */ | |
394 | if(blocks->gx_blocks_used == blocks->gx_blocks_size) | |
395 | { | |
396 | sim_gx_block** new_blocks; | |
397 | int j; | |
398 | ||
399 | blocks->gx_blocks_size += 20; | |
400 | new_blocks = zalloc(blocks->gx_blocks_size * sizeof(sim_gx_block*)); | |
401 | for(j=0; j<blocks->gx_blocks_used; j++) | |
402 | new_blocks[j] = blocks->gx_blocks[j]; | |
403 | if(blocks->gx_blocks) zfree(blocks->gx_blocks); | |
404 | blocks->gx_blocks = new_blocks; | |
405 | } | |
406 | ||
407 | /* insert new block */ | |
408 | for(i=0; i<blocks->gx_blocks_used; i++) | |
409 | { | |
410 | ASSERT(blocks->gx_blocks[i] != NULL); | |
411 | ||
412 | /* insertion point reached? */ | |
413 | if(blocks->gx_blocks[i]->origin > block->origin) | |
414 | { | |
415 | int j; | |
416 | for(j=blocks->gx_blocks_used; j>=i; j--) | |
417 | blocks->gx_blocks[j] = blocks->gx_blocks[j-1]; | |
418 | blocks->gx_blocks[i] = block; | |
419 | blocks->gx_blocks_used ++; | |
420 | break; | |
421 | } | |
422 | } | |
423 | ||
424 | /* end of block vector */ | |
425 | if(i == blocks->gx_blocks_used) | |
426 | { | |
427 | blocks->gx_blocks[blocks->gx_blocks_used ++] = block; | |
428 | } | |
429 | ||
430 | /* print_gx_blocks(blocks, "post add"); */ | |
431 | } | |
432 | ||
433 | ||
434 | ||
435 | /* Remove a gx block from list */ | |
436 | void | |
437 | sim_gx_block_remove(sim_gx_block* block) | |
438 | { | |
439 | SIM_DESC sd = current_state; | |
440 | sim_gx_block_list* blocks = STATE_BLOCKS(sd); | |
441 | int i; | |
442 | ||
443 | /* print_gx_blocks(blocks, "pre remove"); */ | |
444 | ||
445 | /* linear search */ | |
446 | for(i=0; i<blocks->gx_blocks_used; i++) | |
447 | { | |
448 | if(blocks->gx_blocks[i] == block) | |
449 | { | |
450 | /* found it */ | |
451 | while(i < blocks->gx_blocks_used - 1) | |
452 | { | |
453 | blocks->gx_blocks[i] = blocks->gx_blocks[i+1]; | |
454 | i++; | |
455 | } | |
456 | blocks->gx_blocks_used --; | |
457 | break; | |
458 | } | |
459 | } | |
460 | ||
461 | /* print_gx_blocks(blocks, "post remove"); */ | |
462 | } | |
463 | ||
464 | ||
465 | /* Find a gx block from list */ | |
466 | sim_gx_block* | |
467 | sim_gx_block_find(sim_cia cia) | |
468 | { | |
469 | SIM_DESC sd = current_state; | |
470 | sim_gx_block_list* blocks = STATE_BLOCKS(sd); | |
471 | int i; | |
472 | ||
473 | if(blocks == NULL) return NULL; | |
474 | ||
475 | /* print_gx_blocks(blocks, "pre find"); */ | |
476 | ||
477 | /* linear search */ | |
478 | for(i=0; i<blocks->gx_blocks_used; i++) | |
479 | { | |
480 | sim_gx_block* gx = blocks->gx_blocks[i]; | |
481 | ASSERT(gx != NULL); | |
482 | ||
483 | if(GX_PC_INCLUDES(gx,cia)) | |
484 | { | |
485 | return gx; | |
486 | } | |
487 | } | |
488 | ||
489 | return NULL; | |
490 | } | |
491 | ||
492 | ||
493 | ||
494 | /* generate */ | |
495 | void | |
496 | sim_gx_block_translate(sim_gx_block* gx, int optimized) | |
497 | { | |
498 | char pwd_name[PATH_MAX]; | |
499 | char dir_name[PATH_MAX]; | |
500 | char base_name[PATH_MAX]; | |
501 | char compile_command[PATH_MAX*4]; | |
6402c01c | 502 | const char* exec_name; |
92fa4579 FCE |
503 | SIM_DESC sd = current_state; |
504 | int rc; | |
505 | sim_cia gx_cia; | |
506 | sim_gx_compiled_block* block = zalloc(sizeof(sim_gx_compiled_block)); | |
507 | unsigned time_begin, time_end; | |
508 | ||
509 | time_begin = time(NULL); | |
510 | ||
511 | if(optimized) gx->optimized_block = block; | |
512 | else gx->learning_block = block; | |
513 | ||
514 | /* get base of executable name */ | |
515 | exec_name = bfd_get_filename(STATE_PROG_BFD(sd)); | |
516 | if(strrchr(exec_name, '/') != NULL) | |
517 | exec_name = strrchr(exec_name, '/') + 1; | |
518 | ||
519 | /* generate base name */ | |
520 | sprintf(dir_name, "%s/%s", | |
521 | GX_DIR, | |
522 | exec_name); | |
523 | ||
524 | /* generate base name */ | |
525 | getcwd(pwd_name, sizeof(pwd_name)); | |
526 | ||
527 | /* create work directory */ | |
528 | rc = mkdir(GX_DIR, 0777); | |
529 | if(rc != 0 && | |
530 | errno != EEXIST) | |
531 | { | |
532 | sim_io_error(sd, "Error: cannot create directory %s, errno %d", | |
533 | GX_DIR, errno); | |
534 | } | |
535 | ||
536 | rc = mkdir(dir_name, 0777); | |
537 | if(rc != 0 && | |
538 | errno != EEXIST) | |
539 | { | |
540 | sim_io_error(sd, "Error: cannot create directory %s, errno %d", | |
541 | dir_name, errno); | |
542 | } | |
543 | ||
544 | /* compute base name */ | |
545 | if(optimized) | |
6402c01c | 546 | sprintf(base_name, "%08x_opt%d", (unsigned) gx->origin, gx->opt_compile_count); |
92fa4579 | 547 | else |
6402c01c | 548 | sprintf(base_name, "%08x", (unsigned) gx->origin); |
92fa4579 FCE |
549 | |
550 | /* generate source/object file names */ | |
551 | block->source_name = zalloc(PATH_MAX); | |
552 | block->object_name = zalloc(PATH_MAX); | |
553 | sprintf(block->source_name, "%s/%s.c", dir_name, base_name); | |
554 | ||
555 | /* generate symbol name for gx function */ | |
556 | block->symbol_name = zalloc(PATH_MAX); | |
557 | sprintf(block->symbol_name, "gx_%s", base_name); | |
558 | ||
559 | /* open source file */ | |
560 | block->source_file = fopen(block->source_name, "w"); | |
561 | if(block->source_file == NULL) | |
562 | { | |
563 | sim_io_error(sd, "Error: cannot open file %s, errno %d", | |
564 | block->source_name, errno); | |
565 | } | |
566 | ||
567 | /* front matter */ | |
568 | fprintf(block->source_file, "/* sim-gx version %d */\n", GX_VERSION); | |
569 | fprintf(block->source_file, "/* gx block date stamp %lu */\n\n", time(NULL)); | |
570 | ||
571 | /* emit head end of source */ | |
572 | tgx_emit_pre_function(gx, optimized); | |
573 | ||
574 | /* emit function header */ | |
575 | fprintf(block->source_file, "\n\n"); | |
576 | fprintf(block->source_file, "extern int\n"); | |
577 | fprintf(block->source_file, "%s", block->symbol_name); | |
3d7075f5 | 578 | fprintf(block->source_file, "(struct tgx_info* info)\n"); |
92fa4579 FCE |
579 | fprintf(block->source_file, "{\n"); |
580 | fprintf(block->source_file, " int rc = 0;\n"); | |
581 | if(! optimized) | |
582 | fprintf(block->source_file, " unsigned int insn_count = 0;\n"); | |
583 | ||
42647d5b FCE |
584 | /* emit threaded goto vector for __GNUC__ */ |
585 | fprintf(block->source_file, "#ifdef __GNUC__\n"); | |
586 | fprintf(block->source_file, " static void* jump_table[] =\n"); | |
587 | fprintf(block->source_file, " {\n"); | |
588 | gx_cia = gx->origin; | |
589 | while(GX_PC_INCLUDES(gx,gx_cia)) | |
590 | { | |
591 | sim_cia next_gx_cia; | |
592 | if((! optimized) || | |
593 | (GX_PC_FLAGS(gx, gx_cia) & GX_PCF_JUMPTARGET)) | |
594 | { | |
595 | fprintf(block->source_file, " && gx_label_%ld,\n", | |
596 | ((gx_cia - gx->origin) / gx->divisor)); | |
597 | } | |
598 | else | |
599 | { | |
600 | fprintf(block->source_file, " && gx_label_default,\n"); | |
601 | } | |
602 | gx_cia = gx_cia + gx->divisor; | |
603 | } | |
604 | fprintf(block->source_file, " };\n"); | |
605 | fprintf(block->source_file, "#endif /*__GNUC__*/\n"); | |
606 | ||
92fa4579 FCE |
607 | /* pre-block gunk: register load */ |
608 | tgx_emit_load_block(gx, optimized); | |
609 | ||
610 | /* emit intra-block jump label */ | |
611 | fprintf(block->source_file, "\n"); | |
612 | fprintf(block->source_file, "shortjump:\n"); | |
613 | fprintf(block->source_file, " pc = npc;\n"); | |
614 | ||
615 | /* translate jumptarget table */ | |
616 | if(! optimized) | |
617 | { | |
618 | fprintf(block->source_file, " pc_flags[(pc - 0x%08x) / %u] |= %d;\n", | |
619 | (unsigned)gx->origin, gx->divisor, GX_PCF_JUMPTARGET); | |
620 | } | |
621 | ||
622 | /* enforce learning mode run limit */ | |
623 | if(! optimized) | |
624 | { | |
625 | fprintf(block->source_file, " insn_count++;\n"); | |
626 | fprintf(block->source_file, " if (insn_count > %d)\n", GX_LEARN_RUN_LIMIT); | |
627 | fprintf(block->source_file, " {\n"); | |
628 | fprintf(block->source_file, " rc = %d;\n", GX_F_YIELD); | |
629 | fprintf(block->source_file, " npc = pc;\n"); | |
630 | fprintf(block->source_file, " goto save;\n"); | |
631 | fprintf(block->source_file, " }\n"); | |
632 | } | |
633 | ||
634 | /* emit PC switch, use compressed case numbers */ | |
635 | fprintf(block->source_file, "\n"); | |
42647d5b FCE |
636 | fprintf(block->source_file, "#ifdef __GNUC__\n"); |
637 | fprintf(block->source_file, " goto * jump_table[((pc - 0x%08x) / %u)];\n", | |
638 | (unsigned)gx->origin, gx->divisor); | |
639 | fprintf(block->source_file, "#else /* ! __GNUC__*/\n"); | |
92fa4579 FCE |
640 | fprintf(block->source_file, " switch((pc - 0x%08x) / %u)\n", |
641 | (unsigned)gx->origin, gx->divisor); | |
42647d5b | 642 | fprintf(block->source_file, "#endif /*__GNUC__*/\n"); |
92fa4579 FCE |
643 | fprintf(block->source_file, " {\n"); |
644 | ||
645 | /* handle bad-PC event */ | |
646 | fprintf(block->source_file, " /* handle unknown jump target */\n"); | |
42647d5b FCE |
647 | fprintf(block->source_file, "#ifdef __GNUC__\n"); |
648 | fprintf(block->source_file, " gx_label_default:\n"); | |
649 | fprintf(block->source_file, "#else /* ! __GNUC__*/\n"); | |
92fa4579 | 650 | fprintf(block->source_file, " default:\n"); |
42647d5b | 651 | fprintf(block->source_file, "#endif /*__GNUC__*/\n"); |
6402c01c FCE |
652 | fprintf(block->source_file, " pc_flags[%d] |= %d;\n", |
653 | GX_PC_FLAGS_INDEX(gx, gx_cia), GX_PCF_INSTRUCTION); | |
92fa4579 FCE |
654 | fprintf(block->source_file, " rc = %d;\n", GX_F_NONPC); |
655 | fprintf(block->source_file, " npc = pc;\n"); | |
656 | fprintf(block->source_file, " goto save;\n"); | |
657 | ||
658 | /* start translating at the origin */ | |
659 | gx_cia = gx->origin; | |
660 | ||
661 | /* translate instructions in block */ | |
662 | while(GX_PC_INCLUDES(gx,gx_cia)) | |
663 | { | |
664 | sim_cia next_gx_cia; | |
665 | ||
666 | /* translate PC case statement */ | |
667 | fprintf(block->source_file, "\n"); | |
668 | fprintf(block->source_file, " /* PC: 0x%08x, flags %02x */\n", | |
669 | gx_cia, (int) GX_PC_FLAGS(gx, gx_cia)); | |
670 | ||
671 | ||
672 | /* skip over this instruction if it is not executed */ | |
673 | if(optimized && !(GX_PC_FLAGS(gx, gx_cia) & GX_PCF_INSTRUCTION)) | |
674 | { | |
675 | fprintf(block->source_file, " /* (not reached) */\n"); | |
676 | ||
677 | /* prevent fall-through from previous translated insn */ | |
678 | if(gx_cia > gx->origin && | |
679 | GX_PC_FLAGS(gx, (gx_cia - gx->divisor)) & GX_PCF_INSTRUCTION) | |
680 | { | |
681 | fprintf(block->source_file, " /* prevent fall-through */\n"); | |
682 | fprintf(block->source_file, " npc = 0x%08x;\n", gx_cia); | |
6402c01c FCE |
683 | fprintf(block->source_file, " pc_flags[%d] |= %d;\n", |
684 | GX_PC_FLAGS_INDEX(gx, gx_cia), GX_PCF_INSTRUCTION); | |
92fa4579 FCE |
685 | fprintf(block->source_file, " rc = %d;\n", GX_F_NONPC); |
686 | fprintf(block->source_file, " goto save;\n"); | |
687 | } | |
688 | ||
689 | next_gx_cia = gx_cia + gx->divisor; | |
690 | goto skip_instruction; | |
691 | } | |
692 | ||
693 | /* translate PC case statement */ | |
694 | if((! optimized) || | |
695 | (GX_PC_FLAGS(gx, gx_cia) & GX_PCF_JUMPTARGET)) | |
696 | { | |
6402c01c | 697 | fprintf(block->source_file, " gx_label_%d:\n", |
42647d5b | 698 | ((gx_cia - gx->origin) / gx->divisor)); |
3d7075f5 | 699 | fprintf(block->source_file, "#ifndef __GNUC__\n"); |
6402c01c | 700 | fprintf(block->source_file, " case %d:\n", |
92fa4579 | 701 | ((gx_cia - gx->origin) / gx->divisor)); |
3d7075f5 | 702 | fprintf(block->source_file, "#endif /* !__GNUC__ */\n"); |
92fa4579 FCE |
703 | } |
704 | ||
705 | /* translate breakpoint check & exit */ | |
706 | if(GX_PC_FLAGS(gx, gx_cia) & GX_PCF_COND_HALT) | |
707 | { | |
6402c01c | 708 | fprintf(block->source_file, " if(pc_flags[%d] & %d)\n", |
92fa4579 FCE |
709 | GX_PC_FLAGS_INDEX(gx, gx_cia), |
710 | GX_PCF_HALT); | |
711 | fprintf(block->source_file, " {\n"); | |
712 | fprintf(block->source_file, " rc = %d;\n", GX_F_HALT); | |
713 | fprintf(block->source_file, " npc = pc;\n"); | |
714 | fprintf(block->source_file, " goto save;\n"); | |
715 | fprintf(block->source_file, " }\n"); | |
716 | } | |
717 | ||
718 | /* [don't] emit PC-setting */ | |
719 | /* fprintf(block->source_file, " pc = 0x%08x;\n", gx_cia); */ | |
720 | ||
721 | /* mark traversed instructions */ | |
722 | if(! optimized) | |
723 | { | |
6402c01c | 724 | fprintf(block->source_file, " pc_flags[%d] |= %d;\n", |
92fa4579 FCE |
725 | GX_PC_FLAGS_INDEX(gx, gx_cia), |
726 | GX_PCF_INSTRUCTION); | |
727 | } | |
728 | ||
729 | ||
730 | /* translate instruction semantics */ | |
731 | next_gx_cia = tgx_emit_insn(gx, gx_cia, optimized); | |
732 | ||
733 | skip_instruction: | |
734 | ||
735 | /* go to next instruction */ | |
736 | gx_cia = next_gx_cia; | |
737 | } | |
738 | fprintf(block->source_file, " }\n"); | |
739 | ||
740 | /* dropped through last instruction in switch block */ | |
741 | fprintf(block->source_file, "\n"); | |
742 | fprintf(block->source_file, " /* dropped through PC switch */\n"); | |
743 | fprintf(block->source_file, " npc = 0x%08x;\n", gx_cia); | |
744 | fprintf(block->source_file, " rc = %d;\n", GX_F_RANGE); | |
745 | fprintf(block->source_file, " goto save;\n"); | |
746 | ||
747 | /* unknown length jump */ | |
748 | fprintf(block->source_file, "\n"); | |
749 | fprintf(block->source_file, "unknownjump:\n"); | |
6402c01c FCE |
750 | fprintf(block->source_file, " if(npc >= 0x%08x && npc < 0x%08x)\n", |
751 | (unsigned)gx->origin, (unsigned)gx->origin + gx->length); | |
92fa4579 FCE |
752 | fprintf(block->source_file, " goto shortjump;\n"); |
753 | ||
754 | /* long jump */ | |
755 | fprintf(block->source_file, "\n"); | |
756 | fprintf(block->source_file, "longjump:\n"); | |
757 | fprintf(block->source_file, " rc = %d;\n", GX_F_RANGE); | |
758 | ||
759 | /* post-block gunk: SAVE etc. */ | |
760 | fprintf(block->source_file, "\n"); | |
761 | fprintf(block->source_file, "save:\n"); | |
762 | ||
763 | tgx_emit_save_block(gx, optimized); | |
764 | ||
765 | /* emit tail end of function */ | |
766 | fprintf(block->source_file, "\n"); | |
767 | fprintf(block->source_file, " return rc;\n"); | |
768 | fprintf(block->source_file, "}\n"); | |
769 | ||
770 | /* emit tail end of source */ | |
771 | tgx_emit_post_function(gx, optimized); | |
772 | ||
773 | /* close source file */ | |
774 | fclose(block->source_file); | |
775 | block->source_file = NULL; | |
776 | ||
777 | /* compile source & produce shared object */ | |
778 | ||
6402c01c FCE |
779 | { |
780 | char* extra_flags = NULL; | |
781 | #ifdef HAVE_GETENV | |
782 | extra_flags = getenv("GX_FLAGS"); | |
783 | #endif | |
784 | if (extra_flags == NULL) extra_flags = ""; | |
785 | ||
786 | sprintf(compile_command, | |
787 | "gxtool --silent --mode=compile gcc %s %s -c %s", | |
788 | (optimized ? "-O9 -fomit-frame-pointer" : "-O"), | |
789 | extra_flags, | |
790 | block->source_name); | |
791 | ||
792 | rc = system(compile_command); | |
793 | if(rc != 0) | |
794 | { | |
795 | sim_io_error(sd, "Error during compiling: `%s' rc %d", | |
796 | compile_command, rc); | |
797 | } | |
798 | ||
799 | /* link source */ | |
800 | ||
801 | sprintf(compile_command, | |
802 | "gxtool --silent --mode=link gcc -export-dynamic -rpath %s %s -o lib%s.la %s.lo", | |
803 | dir_name, extra_flags, base_name, base_name); | |
804 | ||
805 | rc = system(compile_command); | |
806 | if(rc != 0) | |
807 | { | |
808 | sim_io_error(sd, "Error during linking: `%s' rc %d", | |
809 | compile_command, rc); | |
810 | } | |
811 | } | |
92fa4579 FCE |
812 | |
813 | /* install */ | |
814 | ||
815 | sprintf(compile_command, | |
816 | "gxtool --silent --mode=install cp lib%s.la %s/%s >/dev/null 2>/dev/null", | |
817 | base_name, pwd_name, dir_name); | |
818 | ||
819 | rc = system(compile_command); | |
820 | if(rc != 0) | |
821 | { | |
822 | sim_io_error(sd, "Error during install: `%s' rc %d", | |
823 | compile_command, rc); | |
824 | } | |
825 | ||
826 | ||
827 | /* finish */ | |
828 | ||
829 | sprintf(compile_command, | |
830 | "gxtool --silent --mode=finish %s >/dev/null 2>/dev/null", | |
831 | dir_name); | |
832 | ||
833 | rc = system(compile_command); | |
834 | if(rc != 0) | |
835 | { | |
836 | sim_io_error(sd, "Error during finish: `%s' rc %d", | |
837 | compile_command, rc); | |
838 | } | |
839 | ||
840 | /* clean up */ | |
841 | ||
3d7075f5 | 842 | sprintf(compile_command, "gxtool --silent --mode=uninstall rm -f lib%s.la %s.lo", base_name, base_name); |
92fa4579 FCE |
843 | rc = system(compile_command); |
844 | if(rc != 0) | |
845 | { | |
846 | sim_io_error(sd, "Error during cleanup: `%s' rc %d", | |
847 | compile_command, rc); | |
848 | } | |
849 | ||
850 | /* XXX: FILL IN block->object_name from .la file */ | |
851 | sprintf(block->object_name, "%s/%s/lib%s.so.0", | |
852 | pwd_name, dir_name, base_name); | |
853 | ||
854 | /* measure compile time */ | |
855 | time_end = time(NULL); | |
856 | ||
857 | if(time_end == time_begin) time_end ++; /* clamp minimum duration to 1 */ | |
858 | gx->compile_time += time_end - time_begin; | |
859 | /* fprintf(stderr, "*** compile time: %d\n", gx->compile_time); */ | |
860 | } | |
861 |