1 /* GX target-independent functions for block translation.
2 Copyright (C) 1998 Cygnus Solutions. */
6 #include "sim-assert.h"
11 /* shared object functions */
36 #ifdef HAVE_SYS_STAT_H
45 /* Load the object file with given gx block. Return pointer to GX
46 function or NULL on failure. */
49 sim_gx_compiled_block_f(sim_gx_compiled_block
* gx
)
51 sim_gx_function f
= gx
->function_dlhandle
;
52 SIM_DESC sd
= current_state
;
58 if(gx
->object_dlhandle
== NULL
&& gx
->object_name
!= NULL
)
60 gx
->object_dlhandle
= dlopen(gx
->object_name
, RTLD_NOW
);
61 if(gx
->object_dlhandle
== NULL
)
63 sim_io_error(sd
, "Load error for GX object %s: %s",
70 if(gx
->function_dlhandle
== NULL
&& gx
->object_dlhandle
!= NULL
&& gx
->symbol_name
!= NULL
)
72 f
= gx
->function_dlhandle
= dlsym(gx
->object_dlhandle
, gx
->symbol_name
);
75 sim_io_error(sd
, "Resolve error for GX object %s symbol %s: %s",
88 /* Forget about given GX block. Remove its source/object; unload it
91 sim_gx_compiled_block_dispose(sim_gx_compiled_block
* gx
)
93 SIM_DESC sd
= current_state
;
95 char compile_command
[2000];
98 /* forget dl information */
99 gx
->function_dlhandle
= NULL
;
101 /* unload shared library */
102 if(gx
->object_dlhandle
!= NULL
)
104 rc
= dlclose(gx
->object_dlhandle
);
107 sim_io_error(sd
, "dlclose() error for GX object %s: %s",
111 gx
->object_dlhandle
= NULL
;
114 /* uninstall shared object */
116 strcpy(la_name
, gx
->object_name
);
117 strcpy(strstr(la_name
, ".so.0"), ".la");
118 sprintf(compile_command
, "gxtool --silent --mode=uninstall rm -f %s", la_name
);
120 rc
= system(compile_command
);
123 sim_io_error(sd
, "Error during finish: `%s' rc %d",
124 compile_command
, rc
);
129 /* sprintf(compile_command, "rm -f %s", block->source_name); */
132 zfree(gx
->source_name
);
133 zfree(gx
->object_name
);
134 zfree(gx
->symbol_name
);
140 /* Translate a piece of the code segment around given PC, in given mode. */
142 sim_gx_block_create(sim_cia cia
)
146 /* allocate emtpy block */
147 block
= zalloc(sizeof(sim_gx_block
));
149 /* initialize block bounds, callback struct etc. */
150 tgx_block_ctor(block
, cia
);
152 /* create learning mode translation */
153 sim_gx_block_translate(block
, 0 /* learning mode */);
155 /* add block to block list */
156 sim_gx_block_add(block
);
163 /* Write the current block list to the state file */
165 sim_gx_write_block_list()
168 SIM_DESC sd
= current_state
;
169 sim_gx_block_list
* blocks
= STATE_BLOCKS(sd
);
171 char state_file_name
[PATH_MAX
];
174 /* get base of executable name */
175 exec_name
= bfd_get_filename(STATE_PROG_BFD(sd
));
176 if(strrchr(exec_name
, '/') != NULL
)
177 exec_name
= strrchr(exec_name
, '/') + 1;
179 /* generate base name */
180 sprintf(state_file_name
, "%s/%s.gx",
184 f
= fopen(state_file_name
, "w");
187 sim_io_error(sd
, "Error: cannot write to state file %s, errno %d",
188 state_file_name
, errno
);
191 fprintf(f
, "# This file was automatically generated. Do not edit.\n");
193 /* write block descriptors into state file */
194 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
196 sim_gx_block
* gx
= blocks
->gx_blocks
[i
];
197 sim_gx_compiled_block
* block
;
201 age
= time(NULL
) - gx
->learn_last_change
; /* store interval */
202 fprintf(f
, "BLOCK 0x%lx 0x%lx %u %u\n", gx
->origin
, gx
->length
, gx
->divisor
, age
);
203 fprintf(f
, "FLAGS ");
204 for(j
=0; j
<GX_PC_FLAGS_INDEX(gx
, gx
->origin
+ gx
->length
); j
++)
206 fprintf(f
, "%2x ", gx
->pc_flags
[j
]);
210 /* write learning mode names */
211 block
= gx
->learning_block
;
212 fprintf(f
, "LEARNING %s %s %s %lu %u\n",
213 block
->source_name
, block
->object_name
, block
->symbol_name
,
214 gx
->compile_time
, gx
->opt_compile_count
);
216 /* write optimized mode names */
217 block
= gx
->optimized_block
;
219 fprintf(f
, "OPTIMIZED %s %s %s\n",
220 block
->source_name
, block
->object_name
, block
->symbol_name
);
222 /* NB: other fields will be filled in with freshly guessed values */
231 print_gx_blocks(sim_gx_block_list
* blocks
, char* where
)
233 printf("print_gx_blocks: %s\n", where
);
240 printf("size: %d, used: %d\n",
241 blocks
->gx_blocks_size
, blocks
->gx_blocks_used
);
244 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
246 sim_gx_block
* gx
= blocks
->gx_blocks
[i
];
247 printf("block %d: %p\n", i
, (void*) gx
);
249 printf("** NULL!\n");
251 printf(" begin 0x%08x length 0x%08x [opt %d%s]\n",
252 (unsigned)gx
->origin
, (unsigned)gx
->length
,
253 gx
->opt_compile_count
,
254 (gx
->optimized_block
? " loaded" : " discarded"));
262 /* Read the current block list from the cache */
264 sim_gx_read_block_list()
266 SIM_DESC sd
= current_state
;
268 char state_file_name
[PATH_MAX
];
271 /* check for block */
272 if(STATE_PROG_BFD(sd
) == NULL
)
275 /* get base of executable name */
276 exec_name
= bfd_get_filename(STATE_PROG_BFD(sd
));
277 if(strrchr(exec_name
, '/') != NULL
)
278 exec_name
= strrchr(exec_name
, '/') + 1;
280 /* generate base name */
281 sprintf(state_file_name
, "%s/%s.gx",
285 f
= fopen(state_file_name
, "r");
288 /* XXX: print warning */
292 fscanf(f
, "#%*[^\n]\n"); /* swallow # comment line */
296 unsigned_4 origin
, length
;
300 sim_gx_compiled_block
* block
;
304 rc
= fscanf(f
, "BLOCK 0x%0lx 0x%lx %u %u\n", & origin
, & length
, & divisor
, & age
);
305 if(rc
!= 4) /* not all fields matched - assume EOF */
308 gx
= zalloc(sizeof(sim_gx_block
));
310 /* initialize block bounds, callback struct etc. */
311 tgx_block_ctor2(gx
, origin
, length
, divisor
);
315 for(j
=0; j
<GX_PC_FLAGS_INDEX(gx
, gx
->origin
+ gx
->length
); j
++)
318 fscanf(f
, "%2x ", & value
);
319 gx
->pc_flags
[j
] = (unsigned_1
) value
;
323 /* read learning mode info */
324 block
= zalloc(sizeof(sim_gx_compiled_block
));
325 gx
->learning_block
= block
;
326 block
->source_name
= zalloc(PATH_MAX
);
327 block
->object_name
= zalloc(PATH_MAX
);
328 block
->symbol_name
= zalloc(PATH_MAX
);
329 fscanf(f
, "LEARNING %s %s %s %lu %u\n",
330 block
->source_name
, block
->object_name
, block
->symbol_name
,
331 & gx
->compile_time
, & gx
->opt_compile_count
);
333 /* read optimized mode info */
334 block
= zalloc(sizeof(sim_gx_compiled_block
));
335 gx
->optimized_block
= block
;
336 block
->source_name
= zalloc(PATH_MAX
);
337 block
->object_name
= zalloc(PATH_MAX
);
338 block
->symbol_name
= zalloc(PATH_MAX
);
339 rc
= fscanf(f
, "OPTIMIZED %s %s %s\n",
340 block
->source_name
, block
->object_name
, block
->symbol_name
);
343 /* oops, not an optimized block */
344 zfree(block
->source_name
);
345 zfree(block
->object_name
);
346 zfree(block
->symbol_name
);
348 gx
->optimized_block
= NULL
;
351 /* fill in remaining fields */
352 gx
->learn_last_change
= time(NULL
) - age
; /* make absolute */
355 sim_gx_block_add(gx
);
358 /* print_gx_blocks(STATE_BLOCKS(sd), "after restoring state"); */
366 /* Add a gx block to list */
368 sim_gx_block_add(sim_gx_block
* block
)
370 SIM_DESC sd
= current_state
;
371 sim_gx_block_list
* blocks
= STATE_BLOCKS(sd
);
374 /* print_gx_blocks(blocks, "pre add"); */
377 blocks
= STATE_BLOCKS(sd
) = zalloc(sizeof(sim_gx_block_list
));
379 /* need to enlarge block vector? */
380 if(blocks
->gx_blocks_used
== blocks
->gx_blocks_size
)
382 sim_gx_block
** new_blocks
;
385 blocks
->gx_blocks_size
+= 20;
386 new_blocks
= zalloc(blocks
->gx_blocks_size
* sizeof(sim_gx_block
*));
387 for(j
=0; j
<blocks
->gx_blocks_used
; j
++)
388 new_blocks
[j
] = blocks
->gx_blocks
[j
];
389 if(blocks
->gx_blocks
) zfree(blocks
->gx_blocks
);
390 blocks
->gx_blocks
= new_blocks
;
393 /* insert new block */
394 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
396 ASSERT(blocks
->gx_blocks
[i
] != NULL
);
398 /* insertion point reached? */
399 if(blocks
->gx_blocks
[i
]->origin
> block
->origin
)
402 for(j
=blocks
->gx_blocks_used
; j
>=i
; j
--)
403 blocks
->gx_blocks
[j
] = blocks
->gx_blocks
[j
-1];
404 blocks
->gx_blocks
[i
] = block
;
405 blocks
->gx_blocks_used
++;
410 /* end of block vector */
411 if(i
== blocks
->gx_blocks_used
)
413 blocks
->gx_blocks
[blocks
->gx_blocks_used
++] = block
;
416 /* print_gx_blocks(blocks, "post add"); */
421 /* Remove a gx block from list */
423 sim_gx_block_remove(sim_gx_block
* block
)
425 SIM_DESC sd
= current_state
;
426 sim_gx_block_list
* blocks
= STATE_BLOCKS(sd
);
429 /* print_gx_blocks(blocks, "pre remove"); */
432 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
434 if(blocks
->gx_blocks
[i
] == block
)
437 while(i
< blocks
->gx_blocks_used
- 1)
439 blocks
->gx_blocks
[i
] = blocks
->gx_blocks
[i
+1];
442 blocks
->gx_blocks_used
--;
447 /* print_gx_blocks(blocks, "post remove"); */
451 /* Find a gx block from list */
453 sim_gx_block_find(sim_cia cia
)
455 SIM_DESC sd
= current_state
;
456 sim_gx_block_list
* blocks
= STATE_BLOCKS(sd
);
459 if(blocks
== NULL
) return NULL
;
461 /* print_gx_blocks(blocks, "pre find"); */
464 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
466 sim_gx_block
* gx
= blocks
->gx_blocks
[i
];
469 if(GX_PC_INCLUDES(gx
,cia
))
482 sim_gx_block_translate(sim_gx_block
* gx
, int optimized
)
484 char pwd_name
[PATH_MAX
];
485 char dir_name
[PATH_MAX
];
486 char base_name
[PATH_MAX
];
487 char compile_command
[PATH_MAX
*4];
489 SIM_DESC sd
= current_state
;
492 sim_gx_compiled_block
* block
= zalloc(sizeof(sim_gx_compiled_block
));
493 unsigned time_begin
, time_end
;
495 time_begin
= time(NULL
);
497 if(optimized
) gx
->optimized_block
= block
;
498 else gx
->learning_block
= block
;
500 /* get base of executable name */
501 exec_name
= bfd_get_filename(STATE_PROG_BFD(sd
));
502 if(strrchr(exec_name
, '/') != NULL
)
503 exec_name
= strrchr(exec_name
, '/') + 1;
505 /* generate base name */
506 sprintf(dir_name
, "%s/%s",
510 /* generate base name */
511 getcwd(pwd_name
, sizeof(pwd_name
));
513 /* create work directory */
514 rc
= mkdir(GX_DIR
, 0777);
518 sim_io_error(sd
, "Error: cannot create directory %s, errno %d",
522 rc
= mkdir(dir_name
, 0777);
526 sim_io_error(sd
, "Error: cannot create directory %s, errno %d",
530 /* compute base name */
532 sprintf(base_name
, "%08lx_opt%d", gx
->origin
, gx
->opt_compile_count
);
534 sprintf(base_name
, "%08lx", gx
->origin
);
536 /* generate source/object file names */
537 block
->source_name
= zalloc(PATH_MAX
);
538 block
->object_name
= zalloc(PATH_MAX
);
539 sprintf(block
->source_name
, "%s/%s.c", dir_name
, base_name
);
541 /* generate symbol name for gx function */
542 block
->symbol_name
= zalloc(PATH_MAX
);
543 sprintf(block
->symbol_name
, "gx_%s", base_name
);
545 /* open source file */
546 block
->source_file
= fopen(block
->source_name
, "w");
547 if(block
->source_file
== NULL
)
549 sim_io_error(sd
, "Error: cannot open file %s, errno %d",
550 block
->source_name
, errno
);
554 fprintf(block
->source_file
, "/* sim-gx version %d */\n", GX_VERSION
);
555 fprintf(block
->source_file
, "/* gx block date stamp %lu */\n\n", time(NULL
));
557 /* emit head end of source */
558 tgx_emit_pre_function(gx
, optimized
);
560 /* emit function header */
561 fprintf(block
->source_file
, "\n\n");
562 fprintf(block
->source_file
, "extern int\n");
563 fprintf(block
->source_file
, "%s", block
->symbol_name
);
564 fprintf(block
->source_file
, "(struct tgx_info* info)\n");
565 fprintf(block
->source_file
, "{\n");
566 fprintf(block
->source_file
, " int rc = 0;\n");
568 fprintf(block
->source_file
, " unsigned int insn_count = 0;\n");
570 /* emit threaded goto vector for __GNUC__ */
571 fprintf(block
->source_file
, "#ifdef __GNUC__\n");
572 fprintf(block
->source_file
, " static void* jump_table[] =\n");
573 fprintf(block
->source_file
, " {\n");
575 while(GX_PC_INCLUDES(gx
,gx_cia
))
579 (GX_PC_FLAGS(gx
, gx_cia
) & GX_PCF_JUMPTARGET
))
581 fprintf(block
->source_file
, " && gx_label_%ld,\n",
582 ((gx_cia
- gx
->origin
) / gx
->divisor
));
586 fprintf(block
->source_file
, " && gx_label_default,\n");
588 gx_cia
= gx_cia
+ gx
->divisor
;
590 fprintf(block
->source_file
, " };\n");
591 fprintf(block
->source_file
, "#endif /*__GNUC__*/\n");
593 /* pre-block gunk: register load */
594 tgx_emit_load_block(gx
, optimized
);
596 /* emit intra-block jump label */
597 fprintf(block
->source_file
, "\n");
598 fprintf(block
->source_file
, "shortjump:\n");
599 fprintf(block
->source_file
, " pc = npc;\n");
601 /* translate jumptarget table */
604 fprintf(block
->source_file
, " pc_flags[(pc - 0x%08x) / %u] |= %d;\n",
605 (unsigned)gx
->origin
, gx
->divisor
, GX_PCF_JUMPTARGET
);
608 /* enforce learning mode run limit */
611 fprintf(block
->source_file
, " insn_count++;\n");
612 fprintf(block
->source_file
, " if (insn_count > %d)\n", GX_LEARN_RUN_LIMIT
);
613 fprintf(block
->source_file
, " {\n");
614 fprintf(block
->source_file
, " rc = %d;\n", GX_F_YIELD
);
615 fprintf(block
->source_file
, " npc = pc;\n");
616 fprintf(block
->source_file
, " goto save;\n");
617 fprintf(block
->source_file
, " }\n");
620 /* emit PC switch, use compressed case numbers */
621 fprintf(block
->source_file
, "\n");
622 fprintf(block
->source_file
, "#ifdef __GNUC__\n");
623 fprintf(block
->source_file
, " goto * jump_table[((pc - 0x%08x) / %u)];\n",
624 (unsigned)gx
->origin
, gx
->divisor
);
625 fprintf(block
->source_file
, "#else /* ! __GNUC__*/\n");
626 fprintf(block
->source_file
, " switch((pc - 0x%08x) / %u)\n",
627 (unsigned)gx
->origin
, gx
->divisor
);
628 fprintf(block
->source_file
, "#endif /*__GNUC__*/\n");
629 fprintf(block
->source_file
, " {\n");
631 /* handle bad-PC event */
632 fprintf(block
->source_file
, " /* handle unknown jump target */\n");
633 fprintf(block
->source_file
, "#ifdef __GNUC__\n");
634 fprintf(block
->source_file
, " gx_label_default:\n");
635 fprintf(block
->source_file
, "#else /* ! __GNUC__*/\n");
636 fprintf(block
->source_file
, " default:\n");
637 fprintf(block
->source_file
, "#endif /*__GNUC__*/\n");
638 fprintf(block
->source_file
, " rc = %d;\n", GX_F_NONPC
);
639 fprintf(block
->source_file
, " npc = pc;\n");
640 fprintf(block
->source_file
, " goto save;\n");
642 /* start translating at the origin */
645 /* translate instructions in block */
646 while(GX_PC_INCLUDES(gx
,gx_cia
))
650 /* translate PC case statement */
651 fprintf(block
->source_file
, "\n");
652 fprintf(block
->source_file
, " /* PC: 0x%08x, flags %02x */\n",
653 gx_cia
, (int) GX_PC_FLAGS(gx
, gx_cia
));
656 /* skip over this instruction if it is not executed */
657 if(optimized
&& !(GX_PC_FLAGS(gx
, gx_cia
) & GX_PCF_INSTRUCTION
))
659 fprintf(block
->source_file
, " /* (not reached) */\n");
661 /* prevent fall-through from previous translated insn */
662 if(gx_cia
> gx
->origin
&&
663 GX_PC_FLAGS(gx
, (gx_cia
- gx
->divisor
)) & GX_PCF_INSTRUCTION
)
665 fprintf(block
->source_file
, " /* prevent fall-through */\n");
666 fprintf(block
->source_file
, " npc = 0x%08x;\n", gx_cia
);
667 fprintf(block
->source_file
, " rc = %d;\n", GX_F_NONPC
);
668 fprintf(block
->source_file
, " goto save;\n");
671 next_gx_cia
= gx_cia
+ gx
->divisor
;
672 goto skip_instruction
;
675 /* translate PC case statement */
677 (GX_PC_FLAGS(gx
, gx_cia
) & GX_PCF_JUMPTARGET
))
679 fprintf(block
->source_file
, " gx_label_%ld:\n",
680 ((gx_cia
- gx
->origin
) / gx
->divisor
));
681 fprintf(block
->source_file
, "#ifndef __GNUC__\n");
682 fprintf(block
->source_file
, " case %ld:\n",
683 ((gx_cia
- gx
->origin
) / gx
->divisor
));
684 fprintf(block
->source_file
, "#endif /* !__GNUC__ */\n");
687 /* translate breakpoint check & exit */
688 if(GX_PC_FLAGS(gx
, gx_cia
) & GX_PCF_COND_HALT
)
690 fprintf(block
->source_file
, " if(pc_flags[%ld] & %d)\n",
691 GX_PC_FLAGS_INDEX(gx
, gx_cia
),
693 fprintf(block
->source_file
, " {\n");
694 fprintf(block
->source_file
, " rc = %d;\n", GX_F_HALT
);
695 fprintf(block
->source_file
, " npc = pc;\n");
696 fprintf(block
->source_file
, " goto save;\n");
697 fprintf(block
->source_file
, " }\n");
700 /* [don't] emit PC-setting */
701 /* fprintf(block->source_file, " pc = 0x%08x;\n", gx_cia); */
703 /* mark traversed instructions */
706 fprintf(block
->source_file
, " pc_flags[%ld] |= %d;\n",
707 GX_PC_FLAGS_INDEX(gx
, gx_cia
),
712 /* translate instruction semantics */
713 next_gx_cia
= tgx_emit_insn(gx
, gx_cia
, optimized
);
717 /* go to next instruction */
718 gx_cia
= next_gx_cia
;
720 fprintf(block
->source_file
, " }\n");
722 /* dropped through last instruction in switch block */
723 fprintf(block
->source_file
, "\n");
724 fprintf(block
->source_file
, " /* dropped through PC switch */\n");
725 fprintf(block
->source_file
, " npc = 0x%08x;\n", gx_cia
);
726 fprintf(block
->source_file
, " rc = %d;\n", GX_F_RANGE
);
727 fprintf(block
->source_file
, " goto save;\n");
729 /* unknown length jump */
730 fprintf(block
->source_file
, "\n");
731 fprintf(block
->source_file
, "unknownjump:\n");
732 fprintf(block
->source_file
, " if(npc >= 0x%08lx && npc < 0x%08lx)\n",
733 gx
->origin
, gx
->origin
+ gx
->length
);
734 fprintf(block
->source_file
, " goto shortjump;\n");
737 fprintf(block
->source_file
, "\n");
738 fprintf(block
->source_file
, "longjump:\n");
739 fprintf(block
->source_file
, " rc = %d;\n", GX_F_RANGE
);
741 /* post-block gunk: SAVE etc. */
742 fprintf(block
->source_file
, "\n");
743 fprintf(block
->source_file
, "save:\n");
745 tgx_emit_save_block(gx
, optimized
);
747 /* emit tail end of function */
748 fprintf(block
->source_file
, "\n");
749 fprintf(block
->source_file
, " return rc;\n");
750 fprintf(block
->source_file
, "}\n");
752 /* emit tail end of source */
753 tgx_emit_post_function(gx
, optimized
);
755 /* close source file */
756 fclose(block
->source_file
);
757 block
->source_file
= NULL
;
759 /* compile source & produce shared object */
761 sprintf(compile_command
,
762 "gxtool --silent --mode=compile gcc -c %s %s",
763 (optimized
? "-O9 -fomit-frame-pointer" : "-O"), block
->source_name
);
765 rc
= system(compile_command
);
768 sim_io_error(sd
, "Error during compiling: `%s' rc %d",
769 compile_command
, rc
);
774 sprintf(compile_command
,
775 "gxtool --silent --mode=link gcc -export-dynamic -rpath %s -o lib%s.la %s.lo",
776 dir_name
, base_name
, base_name
);
778 rc
= system(compile_command
);
781 sim_io_error(sd
, "Error during linking: `%s' rc %d",
782 compile_command
, rc
);
788 sprintf(compile_command
,
789 "gxtool --silent --mode=install cp lib%s.la %s/%s >/dev/null 2>/dev/null",
790 base_name
, pwd_name
, dir_name
);
792 rc
= system(compile_command
);
795 sim_io_error(sd
, "Error during install: `%s' rc %d",
796 compile_command
, rc
);
802 sprintf(compile_command
,
803 "gxtool --silent --mode=finish %s >/dev/null 2>/dev/null",
806 rc
= system(compile_command
);
809 sim_io_error(sd
, "Error during finish: `%s' rc %d",
810 compile_command
, rc
);
815 sprintf(compile_command
, "gxtool --silent --mode=uninstall rm -f lib%s.la %s.lo", base_name
, base_name
);
816 rc
= system(compile_command
);
819 sim_io_error(sd
, "Error during cleanup: `%s' rc %d",
820 compile_command
, rc
);
823 /* XXX: FILL IN block->object_name from .la file */
824 sprintf(block
->object_name
, "%s/%s/lib%s.so.0",
825 pwd_name
, dir_name
, base_name
);
827 /* measure compile time */
828 time_end
= time(NULL
);
830 if(time_end
== time_begin
) time_end
++; /* clamp minimum duration to 1 */
831 gx
->compile_time
+= time_end
- time_begin
;
832 /* fprintf(stderr, "*** compile time: %d\n", gx->compile_time); */
This page took 0.045935 seconds and 4 git commands to generate.