1 /* GX target-independent functions for block translation.
2 Copyright (C) 1998 Cygnus Solutions. */
6 #include "sim-assert.h"
10 /* #include "cconfig.h" */
12 /* shared object functions */
37 #ifdef HAVE_SYS_STAT_H
46 /* Load the object file with given gx block. Return pointer to GX
47 function or NULL on failure. */
50 sim_gx_compiled_block_f(sim_gx_compiled_block
* gx
)
52 sim_gx_function f
= gx
->function_dlhandle
;
53 SIM_DESC sd
= current_state
;
59 if(gx
->object_name
== NULL
&& gx
->source_name
!= NULL
)
61 char compile_command
[2000];
63 gx
->object_name
= strdup(gx
->source_name
);
64 /* turn *.c into *.o */
65 gx
->object_name
[strlen(gx
->object_name
)]='o';
67 /* compute command string to compile object */
68 sprintf(compile_command
,
69 "make -f %s OBJ=%s SRC=%s gx",
70 #define GX_MAKEFILE "--no-makefile-yet--"
75 rc
= system(compile_command
);
78 sim_io_error(sd
, "Compile error rc %d for GX source %s: %s",
86 if(gx
->object_dlhandle
== NULL
&& gx
->object_name
!= NULL
)
88 gx
->object_dlhandle
= dlopen(gx
->object_name
, RTLD_NOW
);
89 if(gx
->object_dlhandle
== NULL
)
91 sim_io_error(sd
, "Load error for GX object %s: %s",
98 if(gx
->function_dlhandle
== NULL
&& gx
->object_dlhandle
!= NULL
&& gx
->symbol_name
!= NULL
)
100 f
= gx
->function_dlhandle
= dlsym(gx
->object_dlhandle
, gx
->symbol_name
);
103 sim_io_error(sd
, "Resolve error for GX object %s symbol %s: %s",
116 /* Forget about given GX block. Remove its source/object; unload it
119 sim_gx_compiled_block_dispose(sim_gx_compiled_block
* gx
)
121 SIM_DESC sd
= current_state
;
124 /* forget dl information */
125 gx
->function_dlhandle
= NULL
;
127 /* unload shared library */
128 if(gx
->object_dlhandle
!= NULL
)
130 rc
= dlclose(gx
->object_dlhandle
);
133 sim_io_error(sd
, "dlclose() error for GX object %s: %s",
137 gx
->object_dlhandle
= NULL
;
141 zfree(gx
->source_name
);
142 zfree(gx
->object_name
);
143 zfree(gx
->symbol_name
);
149 /* Translate a piece of the code segment around given PC, in given mode. */
151 sim_gx_block_create(sim_cia cia
)
155 /* allocate emtpy block */
156 block
= zalloc(sizeof(sim_gx_block
));
158 /* initialize block bounds, callback struct etc. */
159 tgx_block_ctor(block
, cia
);
161 /* create learning mode translation */
162 sim_gx_block_translate(block
, 0 /* learning mode */);
164 /* add block to block list */
165 sim_gx_block_add(block
);
172 /* Write the current block list to the state file */
174 sim_gx_write_block_list()
177 SIM_DESC sd
= current_state
;
178 sim_gx_block_list
* blocks
= STATE_BLOCKS(sd
);
180 char state_file_name
[PATH_MAX
];
183 /* get base of executable name */
184 exec_name
= bfd_get_filename(STATE_PROG_BFD(sd
));
185 if(strrchr(exec_name
, '/') != NULL
)
186 exec_name
= strrchr(exec_name
, '/') + 1;
188 /* generate base name */
189 sprintf(state_file_name
, "%s/%s.gx",
193 f
= fopen(state_file_name
, "w");
196 sim_io_error(sd
, "Error: cannot write to state file %s, errno %d",
197 state_file_name
, errno
);
200 fprintf(f
, "# This file was automatically generated. Do not edit.\n");
202 /* write block descriptors into state file */
203 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
205 sim_gx_block
* gx
= blocks
->gx_blocks
[i
];
206 sim_gx_compiled_block
* block
;
210 age
= time(NULL
) - gx
->learn_last_change
; /* store interval */
211 fprintf(f
, "BLOCK 0x%lx 0x%lx %u %u\n", gx
->origin
, gx
->length
, gx
->divisor
, age
);
212 fprintf(f
, "FLAGS ");
213 for(j
=0; j
<GX_PC_FLAGS_INDEX(gx
, gx
->origin
+ gx
->length
); j
++)
215 fprintf(f
, "%2x ", gx
->pc_flags
[j
]);
219 /* write learning mode names */
220 block
= gx
->learning_block
;
221 fprintf(f
, "LEARNING %s %s %s %lu %u\n",
222 block
->source_name
, block
->object_name
, block
->symbol_name
,
223 gx
->compile_time
, gx
->opt_compile_count
);
225 /* write optimized mode names */
226 block
= gx
->optimized_block
;
228 fprintf(f
, "OPTIMIZED %s %s %s\n",
229 block
->source_name
, block
->object_name
, block
->symbol_name
);
231 /* NB: other fields will be filled in with freshly guessed values */
240 print_gx_blocks(sim_gx_block_list
* blocks
, char* where
)
242 printf("print_gx_blocks: %s\n", where
);
249 printf("size: %d, used: %d\n",
250 blocks
->gx_blocks_size
, blocks
->gx_blocks_used
);
253 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
255 sim_gx_block
* gx
= blocks
->gx_blocks
[i
];
256 printf("block %d: %p\n", i
, (void*) gx
);
258 printf("** NULL!\n");
260 printf(" begin 0x%08x length 0x%08x [opt %d%s]\n",
261 (unsigned)gx
->origin
, (unsigned)gx
->length
,
262 gx
->opt_compile_count
,
263 (gx
->optimized_block
? " loaded" : " discarded"));
271 /* Read the current block list from the cache */
273 sim_gx_read_block_list()
275 SIM_DESC sd
= current_state
;
277 char state_file_name
[PATH_MAX
];
280 /* check for block */
281 if(STATE_PROG_BFD(sd
) == NULL
)
284 /* get base of executable name */
285 exec_name
= bfd_get_filename(STATE_PROG_BFD(sd
));
286 if(strrchr(exec_name
, '/') != NULL
)
287 exec_name
= strrchr(exec_name
, '/') + 1;
289 /* generate base name */
290 sprintf(state_file_name
, "%s/%s.gx",
294 f
= fopen(state_file_name
, "r");
297 /* XXX: print warning */
301 fscanf(f
, "#%*[^\n]\n"); /* swallow # comment line */
305 unsigned_4 origin
, length
;
309 sim_gx_compiled_block
* block
;
313 rc
= fscanf(f
, "BLOCK 0x%0lx 0x%lx %u %u\n", & origin
, & length
, & divisor
, & age
);
314 if(rc
!= 4) /* not all fields matched - assume EOF */
317 gx
= zalloc(sizeof(sim_gx_block
));
319 /* initialize block bounds, callback struct etc. */
320 tgx_block_ctor2(gx
, origin
, length
, divisor
);
324 for(j
=0; j
<GX_PC_FLAGS_INDEX(gx
, gx
->origin
+ gx
->length
); j
++)
327 fscanf(f
, "%2x ", & value
);
328 gx
->pc_flags
[j
] = (unsigned_1
) value
;
332 /* read learning mode info */
333 block
= zalloc(sizeof(sim_gx_compiled_block
));
334 gx
->learning_block
= block
;
335 block
->source_name
= zalloc(PATH_MAX
);
336 block
->object_name
= zalloc(PATH_MAX
);
337 block
->symbol_name
= zalloc(PATH_MAX
);
338 fscanf(f
, "LEARNING %s %s %s %lu %u\n",
339 block
->source_name
, block
->object_name
, block
->symbol_name
,
340 & gx
->compile_time
, & gx
->opt_compile_count
);
342 /* read optimized mode info */
343 block
= zalloc(sizeof(sim_gx_compiled_block
));
344 gx
->optimized_block
= block
;
345 block
->source_name
= zalloc(PATH_MAX
);
346 block
->object_name
= zalloc(PATH_MAX
);
347 block
->symbol_name
= zalloc(PATH_MAX
);
348 rc
= fscanf(f
, "OPTIMIZED %s %s %s\n",
349 block
->source_name
, block
->object_name
, block
->symbol_name
);
352 /* oops, not an optimized block */
353 zfree(block
->source_name
);
354 zfree(block
->object_name
);
355 zfree(block
->symbol_name
);
357 gx
->optimized_block
= NULL
;
360 /* fill in remaining fields */
361 gx
->learn_last_change
= time(NULL
) - age
; /* make absolute */
364 sim_gx_block_add(gx
);
367 print_gx_blocks(STATE_BLOCKS(sd
), "after restoring state");
375 /* Add a gx block to list */
377 sim_gx_block_add(sim_gx_block
* block
)
379 SIM_DESC sd
= current_state
;
380 sim_gx_block_list
* blocks
= STATE_BLOCKS(sd
);
383 /* print_gx_blocks(blocks, "pre add"); */
386 blocks
= STATE_BLOCKS(sd
) = zalloc(sizeof(sim_gx_block_list
));
388 /* need to enlarge block vector? */
389 if(blocks
->gx_blocks_used
== blocks
->gx_blocks_size
)
391 sim_gx_block
** new_blocks
;
394 blocks
->gx_blocks_size
+= 20;
395 new_blocks
= zalloc(blocks
->gx_blocks_size
* sizeof(sim_gx_block
*));
396 for(j
=0; j
<blocks
->gx_blocks_used
; j
++)
397 new_blocks
[j
] = blocks
->gx_blocks
[j
];
398 if(blocks
->gx_blocks
) zfree(blocks
->gx_blocks
);
399 blocks
->gx_blocks
= new_blocks
;
402 /* insert new block */
403 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
405 ASSERT(blocks
->gx_blocks
[i
] != NULL
);
407 /* insertion point reached? */
408 if(blocks
->gx_blocks
[i
]->origin
> block
->origin
)
411 for(j
=blocks
->gx_blocks_used
; j
>=i
; j
--)
412 blocks
->gx_blocks
[j
] = blocks
->gx_blocks
[j
-1];
413 blocks
->gx_blocks
[i
] = block
;
414 blocks
->gx_blocks_used
++;
419 /* end of block vector */
420 if(i
== blocks
->gx_blocks_used
)
422 blocks
->gx_blocks
[blocks
->gx_blocks_used
++] = block
;
425 /* print_gx_blocks(blocks, "post add"); */
430 /* Remove a gx block from list */
432 sim_gx_block_remove(sim_gx_block
* block
)
434 SIM_DESC sd
= current_state
;
435 sim_gx_block_list
* blocks
= STATE_BLOCKS(sd
);
438 /* print_gx_blocks(blocks, "pre remove"); */
441 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
443 if(blocks
->gx_blocks
[i
] == block
)
446 while(i
< blocks
->gx_blocks_used
- 1)
448 blocks
->gx_blocks
[i
] = blocks
->gx_blocks
[i
+1];
451 blocks
->gx_blocks_used
--;
456 /* print_gx_blocks(blocks, "post remove"); */
460 /* Find a gx block from list */
462 sim_gx_block_find(sim_cia cia
)
464 SIM_DESC sd
= current_state
;
465 sim_gx_block_list
* blocks
= STATE_BLOCKS(sd
);
468 if(blocks
== NULL
) return NULL
;
470 /* print_gx_blocks(blocks, "pre find"); */
473 for(i
=0; i
<blocks
->gx_blocks_used
; i
++)
475 sim_gx_block
* gx
= blocks
->gx_blocks
[i
];
478 if(GX_PC_INCLUDES(gx
,cia
))
491 sim_gx_block_translate(sim_gx_block
* gx
, int optimized
)
493 char pwd_name
[PATH_MAX
];
494 char dir_name
[PATH_MAX
];
495 char base_name
[PATH_MAX
];
496 char compile_command
[PATH_MAX
*4];
498 SIM_DESC sd
= current_state
;
501 sim_gx_compiled_block
* block
= zalloc(sizeof(sim_gx_compiled_block
));
502 unsigned time_begin
, time_end
;
504 time_begin
= time(NULL
);
506 if(optimized
) gx
->optimized_block
= block
;
507 else gx
->learning_block
= block
;
509 /* get base of executable name */
510 exec_name
= bfd_get_filename(STATE_PROG_BFD(sd
));
511 if(strrchr(exec_name
, '/') != NULL
)
512 exec_name
= strrchr(exec_name
, '/') + 1;
514 /* generate base name */
515 sprintf(dir_name
, "%s/%s",
519 /* generate base name */
520 getcwd(pwd_name
, sizeof(pwd_name
));
522 /* create work directory */
523 rc
= mkdir(GX_DIR
, 0777);
527 sim_io_error(sd
, "Error: cannot create directory %s, errno %d",
531 rc
= mkdir(dir_name
, 0777);
535 sim_io_error(sd
, "Error: cannot create directory %s, errno %d",
539 /* compute base name */
541 sprintf(base_name
, "%08lx_opt%d", gx
->origin
, gx
->opt_compile_count
);
543 sprintf(base_name
, "%08lx", gx
->origin
);
545 /* generate source/object file names */
546 block
->source_name
= zalloc(PATH_MAX
);
547 block
->object_name
= zalloc(PATH_MAX
);
548 sprintf(block
->source_name
, "%s/%s.c", dir_name
, base_name
);
550 /* generate symbol name for gx function */
551 block
->symbol_name
= zalloc(PATH_MAX
);
552 sprintf(block
->symbol_name
, "gx_%s", base_name
);
554 /* open source file */
555 block
->source_file
= fopen(block
->source_name
, "w");
556 if(block
->source_file
== NULL
)
558 sim_io_error(sd
, "Error: cannot open file %s, errno %d",
559 block
->source_name
, errno
);
563 fprintf(block
->source_file
, "/* sim-gx version %d */\n", GX_VERSION
);
564 fprintf(block
->source_file
, "/* gx block date stamp %lu */\n\n", time(NULL
));
566 /* emit head end of source */
567 tgx_emit_pre_function(gx
, optimized
);
569 /* emit function header */
570 fprintf(block
->source_file
, "\n\n");
571 fprintf(block
->source_file
, "extern int\n");
572 fprintf(block
->source_file
, "%s", block
->symbol_name
);
573 fprintf(block
->source_file
, "(struct tgx_cpu_regs* regs, char* pc_flags, struct tgx_callbacks* callbacks)\n");
574 fprintf(block
->source_file
, "{\n");
575 fprintf(block
->source_file
, " int rc = 0;\n");
577 fprintf(block
->source_file
, " unsigned int insn_count = 0;\n");
579 /* pre-block gunk: register load */
580 tgx_emit_load_block(gx
, optimized
);
582 /* emit intra-block jump label */
583 fprintf(block
->source_file
, "\n");
584 fprintf(block
->source_file
, "shortjump:\n");
585 fprintf(block
->source_file
, " pc = npc;\n");
587 /* translate jumptarget table */
590 fprintf(block
->source_file
, " pc_flags[(pc - 0x%08x) / %u] |= %d;\n",
591 (unsigned)gx
->origin
, gx
->divisor
, GX_PCF_JUMPTARGET
);
594 /* enforce learning mode run limit */
597 fprintf(block
->source_file
, " insn_count++;\n");
598 fprintf(block
->source_file
, " if (insn_count > %d)\n", GX_LEARN_RUN_LIMIT
);
599 fprintf(block
->source_file
, " {\n");
600 fprintf(block
->source_file
, " rc = %d;\n", GX_F_YIELD
);
601 fprintf(block
->source_file
, " npc = pc;\n");
602 fprintf(block
->source_file
, " goto save;\n");
603 fprintf(block
->source_file
, " }\n");
606 /* emit PC switch, use compressed case numbers */
607 fprintf(block
->source_file
, "\n");
608 fprintf(block
->source_file
, " switch((pc - 0x%08x) / %u)\n",
609 (unsigned)gx
->origin
, gx
->divisor
);
610 fprintf(block
->source_file
, " {\n");
612 /* handle bad-PC event */
613 fprintf(block
->source_file
, " /* handle unknown jump target */\n");
614 fprintf(block
->source_file
, " default:\n");
615 fprintf(block
->source_file
, " rc = %d;\n", GX_F_NONPC
);
616 fprintf(block
->source_file
, " npc = pc;\n");
617 fprintf(block
->source_file
, " goto save;\n");
619 /* start translating at the origin */
622 /* translate instructions in block */
623 while(GX_PC_INCLUDES(gx
,gx_cia
))
627 /* translate PC case statement */
628 fprintf(block
->source_file
, "\n");
629 fprintf(block
->source_file
, " /* PC: 0x%08x, flags %02x */\n",
630 gx_cia
, (int) GX_PC_FLAGS(gx
, gx_cia
));
633 /* skip over this instruction if it is not executed */
634 if(optimized
&& !(GX_PC_FLAGS(gx
, gx_cia
) & GX_PCF_INSTRUCTION
))
636 fprintf(block
->source_file
, " /* (not reached) */\n");
638 /* prevent fall-through from previous translated insn */
639 if(gx_cia
> gx
->origin
&&
640 GX_PC_FLAGS(gx
, (gx_cia
- gx
->divisor
)) & GX_PCF_INSTRUCTION
)
642 fprintf(block
->source_file
, " /* prevent fall-through */\n");
643 fprintf(block
->source_file
, " npc = 0x%08x;\n", gx_cia
);
644 fprintf(block
->source_file
, " rc = %d;\n", GX_F_NONPC
);
645 fprintf(block
->source_file
, " goto save;\n");
648 next_gx_cia
= gx_cia
+ gx
->divisor
;
649 goto skip_instruction
;
652 /* translate PC case statement */
654 (GX_PC_FLAGS(gx
, gx_cia
) & GX_PCF_JUMPTARGET
))
656 fprintf(block
->source_file
, " case %ld:\n",
657 ((gx_cia
- gx
->origin
) / gx
->divisor
));
660 /* translate breakpoint check & exit */
661 if(GX_PC_FLAGS(gx
, gx_cia
) & GX_PCF_COND_HALT
)
663 fprintf(block
->source_file
, " if(pc_flags[%ld] & %d)\n",
664 GX_PC_FLAGS_INDEX(gx
, gx_cia
),
666 fprintf(block
->source_file
, " {\n");
667 fprintf(block
->source_file
, " rc = %d;\n", GX_F_HALT
);
668 fprintf(block
->source_file
, " npc = pc;\n");
669 fprintf(block
->source_file
, " goto save;\n");
670 fprintf(block
->source_file
, " }\n");
673 /* [don't] emit PC-setting */
674 /* fprintf(block->source_file, " pc = 0x%08x;\n", gx_cia); */
676 /* mark traversed instructions */
679 fprintf(block
->source_file
, " pc_flags[%ld] |= %d;\n",
680 GX_PC_FLAGS_INDEX(gx
, gx_cia
),
685 /* translate instruction semantics */
686 next_gx_cia
= tgx_emit_insn(gx
, gx_cia
, optimized
);
690 /* go to next instruction */
691 gx_cia
= next_gx_cia
;
693 fprintf(block
->source_file
, " }\n");
695 /* dropped through last instruction in switch block */
696 fprintf(block
->source_file
, "\n");
697 fprintf(block
->source_file
, " /* dropped through PC switch */\n");
698 fprintf(block
->source_file
, " npc = 0x%08x;\n", gx_cia
);
699 fprintf(block
->source_file
, " rc = %d;\n", GX_F_RANGE
);
700 fprintf(block
->source_file
, " goto save;\n");
702 /* unknown length jump */
703 fprintf(block
->source_file
, "\n");
704 fprintf(block
->source_file
, "unknownjump:\n");
705 fprintf(block
->source_file
, " if(npc >= 0x%08lx && npc < 0x%08lx)\n",
706 gx
->origin
, gx
->origin
+ gx
->length
);
707 fprintf(block
->source_file
, " goto shortjump;\n");
710 fprintf(block
->source_file
, "\n");
711 fprintf(block
->source_file
, "longjump:\n");
712 fprintf(block
->source_file
, " rc = %d;\n", GX_F_RANGE
);
714 /* post-block gunk: SAVE etc. */
715 fprintf(block
->source_file
, "\n");
716 fprintf(block
->source_file
, "save:\n");
718 tgx_emit_save_block(gx
, optimized
);
720 /* emit tail end of function */
721 fprintf(block
->source_file
, "\n");
722 fprintf(block
->source_file
, " return rc;\n");
723 fprintf(block
->source_file
, "}\n");
725 /* emit tail end of source */
726 tgx_emit_post_function(gx
, optimized
);
728 /* close source file */
729 fclose(block
->source_file
);
730 block
->source_file
= NULL
;
732 /* compile source & produce shared object */
734 sprintf(compile_command
,
735 "gxtool --silent --mode=compile gcc -c -g %s %s",
736 (optimized
? "-O3" : "-O"), block
->source_name
);
738 rc
= system(compile_command
);
741 sim_io_error(sd
, "Error during compiling: `%s' rc %d",
742 compile_command
, rc
);
747 sprintf(compile_command
,
748 "gxtool --silent --mode=link gcc -export-dynamic -rpath %s -g -o lib%s.la %s.lo",
749 dir_name
, base_name
, base_name
);
751 rc
= system(compile_command
);
754 sim_io_error(sd
, "Error during linking: `%s' rc %d",
755 compile_command
, rc
);
761 sprintf(compile_command
,
762 "gxtool --silent --mode=install cp lib%s.la %s/%s >/dev/null 2>/dev/null",
763 base_name
, pwd_name
, dir_name
);
765 rc
= system(compile_command
);
768 sim_io_error(sd
, "Error during install: `%s' rc %d",
769 compile_command
, rc
);
775 sprintf(compile_command
,
776 "gxtool --silent --mode=finish %s >/dev/null 2>/dev/null",
779 rc
= system(compile_command
);
782 sim_io_error(sd
, "Error during finish: `%s' rc %d",
783 compile_command
, rc
);
788 sprintf(compile_command
, "rm -f lib%s.la %s.lo", base_name
, base_name
);
789 rc
= system(compile_command
);
792 sim_io_error(sd
, "Error during cleanup: `%s' rc %d",
793 compile_command
, rc
);
796 /* XXX: FILL IN block->object_name from .la file */
797 sprintf(block
->object_name
, "%s/%s/lib%s.so.0",
798 pwd_name
, dir_name
, base_name
);
800 /* measure compile time */
801 time_end
= time(NULL
);
803 if(time_end
== time_begin
) time_end
++; /* clamp minimum duration to 1 */
804 gx
->compile_time
+= time_end
- time_begin
;
805 /* fprintf(stderr, "*** compile time: %d\n", gx->compile_time); */