nkeynes@363: /** nkeynes@586: * $Id$ nkeynes@363: * nkeynes@363: * Test cases for the SH4 => x86 translator core. Takes as nkeynes@363: * input a binary SH4 object (and VMA), generates the nkeynes@363: * corresponding x86 code, and outputs the disassembly. nkeynes@363: * nkeynes@363: * Copyright (c) 2005 Nathan Keynes. nkeynes@363: * nkeynes@363: * This program is free software; you can redistribute it and/or modify nkeynes@363: * it under the terms of the GNU General Public License as published by nkeynes@363: * the Free Software Foundation; either version 2 of the License, or nkeynes@363: * (at your option) any later version. nkeynes@363: * nkeynes@363: * This program is distributed in the hope that it will be useful, nkeynes@363: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@363: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@363: * GNU General Public License for more details. nkeynes@363: */ nkeynes@363: nkeynes@363: #include nkeynes@363: #include nkeynes@363: #include nkeynes@365: #include nkeynes@365: #include "x86dasm/x86dasm.h" nkeynes@363: #include "sh4/sh4trans.h" nkeynes@363: #include "sh4/sh4core.h" nkeynes@586: #include "sh4/sh4mmio.h" nkeynes@586: nkeynes@820: struct dreamcast_module sh4_module; nkeynes@586: struct mmio_region mmio_region_MMU; nkeynes@820: struct mmio_region mmio_region_PMM; nkeynes@586: struct breakpoint_struct sh4_breakpoints[MAX_BREAKPOINTS]; nkeynes@586: int sh4_breakpoint_count = 0; nkeynes@363: nkeynes@363: #define MAX_INS_SIZE 32 nkeynes@363: nkeynes@930: nkeynes@930: struct mem_region_fn **sh4_address_space = (void *)0x12345432; nkeynes@363: char *option_list = "s:o:d:h"; nkeynes@363: struct option longopts[1] = { { NULL, 0, 0, 0 } }; nkeynes@363: nkeynes@363: char *input_file = NULL; nkeynes@363: char *diff_file = NULL; nkeynes@363: char *output_file = NULL; nkeynes@602: gboolean sh4_starting; nkeynes@363: uint32_t start_addr = 0x8C010000; nkeynes@365: uint32_t sh4_cpu_period = 5; nkeynes@934: unsigned char dc_main_ram[4096]; nkeynes@934: unsigned char dc_boot_rom[4096]; nkeynes@363: FILE *in; nkeynes@363: nkeynes@363: char *inbuf; nkeynes@365: nkeynes@365: struct x86_symbol local_symbols[] = { nkeynes@919: { "sh4r+128", ((char *)&sh4r)+128 }, nkeynes@919: { "sh4_cpu_period", &sh4_cpu_period }, nkeynes@930: { "sh4_address_space", 0x12345432 }, nkeynes@919: { "sh4_write_fpscr", sh4_write_fpscr }, nkeynes@919: { "sh4_write_sr", sh4_write_sr }, nkeynes@919: { "sh4_read_sr", sh4_read_sr }, nkeynes@919: { "sh4_sleep", sh4_sleep }, nkeynes@919: { "sh4_fsca", sh4_fsca }, nkeynes@919: { "sh4_ftrv", sh4_ftrv }, nkeynes@919: { "sh4_switch_fr_banks", sh4_switch_fr_banks }, nkeynes@919: { "sh4_execute_instruction", sh4_execute_instruction }, nkeynes@919: { "signsat48", signsat48 }, nkeynes@919: { "sh4_read_byte", sh4_read_byte }, nkeynes@919: { "sh4_read_word", sh4_read_word }, nkeynes@919: { "sh4_read_long", sh4_read_long }, nkeynes@919: { "sh4_write_byte", sh4_write_byte }, nkeynes@919: { "sh4_write_word", sh4_write_word }, nkeynes@919: { "sh4_write_long", sh4_write_long }, nkeynes@919: { "xlat_get_code_by_vma", xlat_get_code_by_vma }, nkeynes@919: { "xlat_get_code", xlat_get_code } nkeynes@365: }; nkeynes@363: nkeynes@905: int32_t FASTCALL sh4_read_byte( uint32_t addr ) nkeynes@363: { nkeynes@363: return *(uint8_t *)(inbuf+(addr-start_addr)); nkeynes@363: } nkeynes@905: int32_t FASTCALL sh4_read_word( uint32_t addr ) nkeynes@363: { nkeynes@363: return *(uint16_t *)(inbuf+(addr-start_addr)); nkeynes@363: } nkeynes@905: int32_t FASTCALL sh4_read_long( uint32_t addr ) nkeynes@363: { nkeynes@363: return *(uint32_t *)(inbuf+(addr-start_addr)); nkeynes@363: } nkeynes@929: nkeynes@363: // Stubs nkeynes@802: gboolean sh4_execute_instruction( ) { return TRUE; } nkeynes@363: void sh4_accept_interrupt() {} nkeynes@586: void sh4_set_breakpoint( uint32_t pc, breakpoint_type_t type ) { } nkeynes@802: gboolean sh4_clear_breakpoint( uint32_t pc, breakpoint_type_t type ) { return TRUE; } nkeynes@775: gboolean dreamcast_is_running() { return FALSE; } nkeynes@802: int sh4_get_breakpoint( uint32_t pc ) { return 0; } nkeynes@740: void sh4_core_exit( int exit_code ){} nkeynes@740: void sh4_flush_icache(){} nkeynes@363: void event_execute() {} nkeynes@363: void TMU_run_slice( uint32_t nanos ) {} nkeynes@931: void CCN_set_cache_control( uint32_t val ) { } nkeynes@884: void PMM_write_control( int ctr, uint32_t val ) { } nkeynes@363: void SCIF_run_slice( uint32_t nanos ) {} nkeynes@905: void FASTCALL sh4_write_byte( uint32_t addr, uint32_t val ) {} nkeynes@905: void FASTCALL sh4_write_word( uint32_t addr, uint32_t val ) {} nkeynes@905: void FASTCALL sh4_write_long( uint32_t addr, uint32_t val ) {} nkeynes@905: void FASTCALL sh4_write_fpscr( uint32_t val ) { } nkeynes@905: void FASTCALL sh4_write_sr( uint32_t val ) { } nkeynes@905: uint32_t FASTCALL sh4_read_sr( void ) { return 0; } nkeynes@905: void FASTCALL sh4_sleep() { } nkeynes@905: void FASTCALL sh4_fsca( uint32_t angle, float *fr ) { } nkeynes@905: void FASTCALL sh4_ftrv( float *fv ) { } nkeynes@905: void FASTCALL signsat48(void) { } nkeynes@669: void sh4_switch_fr_banks() { } nkeynes@918: void mem_copy_to_sh4( sh4addr_t addr, sh4ptr_t src, size_t size ) { } nkeynes@602: gboolean sh4_has_page( sh4vma_t vma ) { return TRUE; } nkeynes@385: void syscall_invoke( uint32_t val ) { } nkeynes@586: void dreamcast_stop() {} nkeynes@586: void dreamcast_reset() {} nkeynes@905: gboolean FASTCALL sh4_raise_reset( int exc ) { return TRUE; } nkeynes@905: gboolean FASTCALL sh4_raise_exception( int exc ) { return TRUE; } nkeynes@905: gboolean FASTCALL sh4_raise_tlb_exception( int exc ) { return TRUE; } nkeynes@905: gboolean FASTCALL sh4_raise_trap( int exc ) { return TRUE; } nkeynes@939: void FASTCALL sh4_flush_store_queue( sh4addr_t addr ) { } nkeynes@939: void FASTCALL sh4_flush_store_queue_mmu( sh4addr_t addr, void *exc ) { } nkeynes@802: uint32_t sh4_sleep_run_slice(uint32_t nanosecs) { return nanosecs; } nkeynes@802: gboolean gui_error_dialog( const char *fmt, ... ) { return TRUE; } nkeynes@939: gboolean FASTCALL mmu_update_icache( sh4vma_t addr ) { return TRUE; } nkeynes@939: void MMU_ldtlb() { } nkeynes@586: struct sh4_icache_struct sh4_icache; nkeynes@930: struct mem_region_fn mem_region_unmapped; nkeynes@363: nkeynes@363: void usage() nkeynes@363: { nkeynes@363: fprintf( stderr, "Usage: testsh4x86 [options] \n"); nkeynes@363: fprintf( stderr, "Options:\n"); nkeynes@363: fprintf( stderr, " -d Diff results against contents of file\n" ); nkeynes@363: fprintf( stderr, " -h Display this help message\n" ); nkeynes@363: fprintf( stderr, " -o Output disassembly to file [stdout]\n" ); nkeynes@363: fprintf( stderr, " -s Specify start address of binary [8C010000]\n" ); nkeynes@363: } nkeynes@363: nkeynes@363: void emit( void *ptr, int level, const gchar *source, const char *msg, ... ) nkeynes@363: { nkeynes@363: va_list ap; nkeynes@363: va_start( ap, msg ); nkeynes@363: vfprintf( stderr, msg, ap ); nkeynes@363: fprintf( stderr, "\n" ); nkeynes@363: va_end(ap); nkeynes@363: } nkeynes@363: nkeynes@363: nkeynes@363: struct sh4_registers sh4r; nkeynes@363: nkeynes@363: nkeynes@363: int main( int argc, char *argv[] ) nkeynes@363: { nkeynes@363: struct stat st; nkeynes@363: int opt; nkeynes@363: while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) { nkeynes@363: switch( opt ) { nkeynes@363: case 'd': nkeynes@363: diff_file = optarg; nkeynes@363: break; nkeynes@363: case 'o': nkeynes@363: output_file = optarg; nkeynes@363: break; nkeynes@363: case 's': nkeynes@363: start_addr = strtoul(optarg, NULL, 0); nkeynes@363: break; nkeynes@363: case 'h': nkeynes@363: usage(); nkeynes@363: exit(0); nkeynes@363: } nkeynes@363: } nkeynes@363: if( optind < argc ) { nkeynes@363: input_file = argv[optind++]; nkeynes@363: } else { nkeynes@363: usage(); nkeynes@363: exit(1); nkeynes@363: } nkeynes@363: nkeynes@919: mmio_region_MMU.mem = malloc(4096); nkeynes@919: memset( mmio_region_MMU.mem, 0, 4096 ); nkeynes@919: nkeynes@929: ((uint32_t *)mmio_region_MMU.mem)[4] = 1; nkeynes@929: nkeynes@363: in = fopen( input_file, "ro" ); nkeynes@363: if( in == NULL ) { nkeynes@363: perror( "Unable to open input file" ); nkeynes@363: exit(2); nkeynes@363: } nkeynes@363: fstat( fileno(in), &st ); nkeynes@363: inbuf = malloc( st.st_size ); nkeynes@363: fread( inbuf, st.st_size, 1, in ); nkeynes@919: sh4_icache.mask = 0xFFFFF000; nkeynes@919: sh4_icache.page_vma = start_addr & 0xFFFFF000; nkeynes@919: sh4_icache.page = (unsigned char *)(inbuf - (sh4_icache.page_vma&0xFFF)); nkeynes@919: sh4_icache.page_ppa = start_addr & 0xFFFFF000; nkeynes@363: nkeynes@365: xlat_cache_init(); nkeynes@925: uintptr_t pc; nkeynes@365: uint8_t *buf = sh4_translate_basic_block( start_addr ); nkeynes@919: uint32_t buflen = xlat_get_code_size(buf); nkeynes@934: x86_disasm_init( (uintptr_t)buf, (uintptr_t)buf, buflen ); nkeynes@919: x86_set_symtab( local_symbols, sizeof(local_symbols)/sizeof(struct x86_symbol) ); nkeynes@925: for( pc = buf; pc < buf + buflen; ) { nkeynes@363: char buf[256]; nkeynes@363: char op[256]; nkeynes@925: uintptr_t pc2 = x86_disasm_instruction( pc, buf, sizeof(buf), op ); nkeynes@929: fprintf( stdout, "%08x: %s\n", pc, buf ); nkeynes@363: pc = pc2; nkeynes@363: } nkeynes@802: return 0; nkeynes@363: }