nkeynes@363 | 1 | /**
|
nkeynes@586 | 2 | * $Id$
|
nkeynes@363 | 3 | *
|
nkeynes@363 | 4 | * Test cases for the SH4 => x86 translator core. Takes as
|
nkeynes@363 | 5 | * input a binary SH4 object (and VMA), generates the
|
nkeynes@363 | 6 | * corresponding x86 code, and outputs the disassembly.
|
nkeynes@363 | 7 | *
|
nkeynes@363 | 8 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@363 | 9 | *
|
nkeynes@363 | 10 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@363 | 11 | * it under the terms of the GNU General Public License as published by
|
nkeynes@363 | 12 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@363 | 13 | * (at your option) any later version.
|
nkeynes@363 | 14 | *
|
nkeynes@363 | 15 | * This program is distributed in the hope that it will be useful,
|
nkeynes@363 | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@363 | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@363 | 18 | * GNU General Public License for more details.
|
nkeynes@363 | 19 | */
|
nkeynes@363 | 20 |
|
nkeynes@363 | 21 | #include <stdio.h>
|
nkeynes@363 | 22 | #include <stdarg.h>
|
nkeynes@363 | 23 | #include <getopt.h>
|
nkeynes@365 | 24 | #include <sys/stat.h>
|
nkeynes@365 | 25 | #include "x86dasm/x86dasm.h"
|
nkeynes@363 | 26 | #include "sh4/sh4trans.h"
|
nkeynes@363 | 27 | #include "sh4/sh4core.h"
|
nkeynes@586 | 28 | #include "sh4/sh4mmio.h"
|
nkeynes@586 | 29 |
|
nkeynes@820 | 30 | struct dreamcast_module sh4_module;
|
nkeynes@586 | 31 | struct mmio_region mmio_region_MMU;
|
nkeynes@820 | 32 | struct mmio_region mmio_region_PMM;
|
nkeynes@586 | 33 | struct breakpoint_struct sh4_breakpoints[MAX_BREAKPOINTS];
|
nkeynes@586 | 34 | int sh4_breakpoint_count = 0;
|
nkeynes@363 | 35 |
|
nkeynes@363 | 36 | #define MAX_INS_SIZE 32
|
nkeynes@363 | 37 |
|
nkeynes@930 | 38 |
|
nkeynes@930 | 39 | struct mem_region_fn **sh4_address_space = (void *)0x12345432;
|
nkeynes@363 | 40 | char *option_list = "s:o:d:h";
|
nkeynes@363 | 41 | struct option longopts[1] = { { NULL, 0, 0, 0 } };
|
nkeynes@363 | 42 |
|
nkeynes@363 | 43 | char *input_file = NULL;
|
nkeynes@363 | 44 | char *diff_file = NULL;
|
nkeynes@363 | 45 | char *output_file = NULL;
|
nkeynes@602 | 46 | gboolean sh4_starting;
|
nkeynes@363 | 47 | uint32_t start_addr = 0x8C010000;
|
nkeynes@365 | 48 | uint32_t sh4_cpu_period = 5;
|
nkeynes@586 | 49 | sh4ptr_t sh4_main_ram;
|
nkeynes@363 | 50 | FILE *in;
|
nkeynes@363 | 51 |
|
nkeynes@363 | 52 | char *inbuf;
|
nkeynes@365 | 53 |
|
nkeynes@365 | 54 | struct x86_symbol local_symbols[] = {
|
nkeynes@919 | 55 | { "sh4r+128", ((char *)&sh4r)+128 },
|
nkeynes@919 | 56 | { "sh4_cpu_period", &sh4_cpu_period },
|
nkeynes@919 | 57 | { "mmu_vma_to_phys_read", mmu_vma_to_phys_read },
|
nkeynes@919 | 58 | { "mmu_vma_to_phys_write", mmu_vma_to_phys_write },
|
nkeynes@930 | 59 | { "sh4_address_space", 0x12345432 },
|
nkeynes@919 | 60 | { "sh4_write_fpscr", sh4_write_fpscr },
|
nkeynes@919 | 61 | { "sh4_write_sr", sh4_write_sr },
|
nkeynes@919 | 62 | { "sh4_read_sr", sh4_read_sr },
|
nkeynes@919 | 63 | { "sh4_sleep", sh4_sleep },
|
nkeynes@919 | 64 | { "sh4_fsca", sh4_fsca },
|
nkeynes@919 | 65 | { "sh4_ftrv", sh4_ftrv },
|
nkeynes@919 | 66 | { "sh4_switch_fr_banks", sh4_switch_fr_banks },
|
nkeynes@919 | 67 | { "sh4_execute_instruction", sh4_execute_instruction },
|
nkeynes@919 | 68 | { "signsat48", signsat48 },
|
nkeynes@919 | 69 | { "sh4_read_byte", sh4_read_byte },
|
nkeynes@919 | 70 | { "sh4_read_word", sh4_read_word },
|
nkeynes@919 | 71 | { "sh4_read_long", sh4_read_long },
|
nkeynes@919 | 72 | { "sh4_write_byte", sh4_write_byte },
|
nkeynes@919 | 73 | { "sh4_write_word", sh4_write_word },
|
nkeynes@919 | 74 | { "sh4_write_long", sh4_write_long },
|
nkeynes@919 | 75 | { "xlat_get_code_by_vma", xlat_get_code_by_vma },
|
nkeynes@919 | 76 | { "xlat_get_code", xlat_get_code }
|
nkeynes@365 | 77 | };
|
nkeynes@363 | 78 |
|
nkeynes@905 | 79 | int32_t FASTCALL sh4_read_byte( uint32_t addr )
|
nkeynes@363 | 80 | {
|
nkeynes@363 | 81 | return *(uint8_t *)(inbuf+(addr-start_addr));
|
nkeynes@363 | 82 | }
|
nkeynes@905 | 83 | int32_t FASTCALL sh4_read_word( uint32_t addr )
|
nkeynes@363 | 84 | {
|
nkeynes@363 | 85 | return *(uint16_t *)(inbuf+(addr-start_addr));
|
nkeynes@363 | 86 | }
|
nkeynes@905 | 87 | int32_t FASTCALL sh4_read_long( uint32_t addr )
|
nkeynes@363 | 88 | {
|
nkeynes@363 | 89 | return *(uint32_t *)(inbuf+(addr-start_addr));
|
nkeynes@363 | 90 | }
|
nkeynes@929 | 91 | mem_region_fn_t FASTCALL sh7750_decode_address( sh4addr_t address )
|
nkeynes@929 | 92 | {
|
nkeynes@929 | 93 | return NULL;
|
nkeynes@929 | 94 | }
|
nkeynes@929 | 95 | void FASTCALL sh7750_decode_address_copy( sh4addr_t address, mem_region_fn_t out )
|
nkeynes@929 | 96 | {
|
nkeynes@929 | 97 | }
|
nkeynes@929 | 98 |
|
nkeynes@363 | 99 | // Stubs
|
nkeynes@802 | 100 | gboolean sh4_execute_instruction( ) { return TRUE; }
|
nkeynes@363 | 101 | void sh4_accept_interrupt() {}
|
nkeynes@586 | 102 | void sh4_set_breakpoint( uint32_t pc, breakpoint_type_t type ) { }
|
nkeynes@802 | 103 | gboolean sh4_clear_breakpoint( uint32_t pc, breakpoint_type_t type ) { return TRUE; }
|
nkeynes@775 | 104 | gboolean dreamcast_is_running() { return FALSE; }
|
nkeynes@802 | 105 | int sh4_get_breakpoint( uint32_t pc ) { return 0; }
|
nkeynes@740 | 106 | void sh4_core_exit( int exit_code ){}
|
nkeynes@740 | 107 | void sh4_flush_icache(){}
|
nkeynes@363 | 108 | void event_execute() {}
|
nkeynes@363 | 109 | void TMU_run_slice( uint32_t nanos ) {}
|
nkeynes@884 | 110 | void PMM_write_control( int ctr, uint32_t val ) { }
|
nkeynes@363 | 111 | void SCIF_run_slice( uint32_t nanos ) {}
|
nkeynes@905 | 112 | void FASTCALL sh4_write_byte( uint32_t addr, uint32_t val ) {}
|
nkeynes@905 | 113 | void FASTCALL sh4_write_word( uint32_t addr, uint32_t val ) {}
|
nkeynes@905 | 114 | void FASTCALL sh4_write_long( uint32_t addr, uint32_t val ) {}
|
nkeynes@905 | 115 | void FASTCALL sh4_write_fpscr( uint32_t val ) { }
|
nkeynes@905 | 116 | void FASTCALL sh4_write_sr( uint32_t val ) { }
|
nkeynes@905 | 117 | uint32_t FASTCALL sh4_read_sr( void ) { return 0; }
|
nkeynes@905 | 118 | void FASTCALL sh4_sleep() { }
|
nkeynes@905 | 119 | void FASTCALL sh4_fsca( uint32_t angle, float *fr ) { }
|
nkeynes@905 | 120 | void FASTCALL sh4_ftrv( float *fv ) { }
|
nkeynes@905 | 121 | void FASTCALL signsat48(void) { }
|
nkeynes@669 | 122 | void sh4_switch_fr_banks() { }
|
nkeynes@918 | 123 | void mem_copy_to_sh4( sh4addr_t addr, sh4ptr_t src, size_t size ) { }
|
nkeynes@602 | 124 | gboolean sh4_has_page( sh4vma_t vma ) { return TRUE; }
|
nkeynes@385 | 125 | void syscall_invoke( uint32_t val ) { }
|
nkeynes@586 | 126 | void dreamcast_stop() {}
|
nkeynes@586 | 127 | void dreamcast_reset() {}
|
nkeynes@905 | 128 | gboolean FASTCALL sh4_raise_reset( int exc ) { return TRUE; }
|
nkeynes@905 | 129 | gboolean FASTCALL sh4_raise_exception( int exc ) { return TRUE; }
|
nkeynes@905 | 130 | gboolean FASTCALL sh4_raise_tlb_exception( int exc ) { return TRUE; }
|
nkeynes@905 | 131 | gboolean FASTCALL sh4_raise_trap( int exc ) { return TRUE; }
|
nkeynes@802 | 132 | uint32_t sh4_sleep_run_slice(uint32_t nanosecs) { return nanosecs; }
|
nkeynes@802 | 133 | gboolean gui_error_dialog( const char *fmt, ... ) { return TRUE; }
|
nkeynes@586 | 134 | struct sh4_icache_struct sh4_icache;
|
nkeynes@930 | 135 | struct mem_region_fn mem_region_unmapped;
|
nkeynes@363 | 136 |
|
nkeynes@363 | 137 | void usage()
|
nkeynes@363 | 138 | {
|
nkeynes@363 | 139 | fprintf( stderr, "Usage: testsh4x86 [options] <input bin file>\n");
|
nkeynes@363 | 140 | fprintf( stderr, "Options:\n");
|
nkeynes@363 | 141 | fprintf( stderr, " -d <filename> Diff results against contents of file\n" );
|
nkeynes@363 | 142 | fprintf( stderr, " -h Display this help message\n" );
|
nkeynes@363 | 143 | fprintf( stderr, " -o <filename> Output disassembly to file [stdout]\n" );
|
nkeynes@363 | 144 | fprintf( stderr, " -s <addr> Specify start address of binary [8C010000]\n" );
|
nkeynes@363 | 145 | }
|
nkeynes@363 | 146 |
|
nkeynes@363 | 147 | void emit( void *ptr, int level, const gchar *source, const char *msg, ... )
|
nkeynes@363 | 148 | {
|
nkeynes@363 | 149 | va_list ap;
|
nkeynes@363 | 150 | va_start( ap, msg );
|
nkeynes@363 | 151 | vfprintf( stderr, msg, ap );
|
nkeynes@363 | 152 | fprintf( stderr, "\n" );
|
nkeynes@363 | 153 | va_end(ap);
|
nkeynes@363 | 154 | }
|
nkeynes@363 | 155 |
|
nkeynes@363 | 156 |
|
nkeynes@363 | 157 | struct sh4_registers sh4r;
|
nkeynes@363 | 158 |
|
nkeynes@363 | 159 |
|
nkeynes@363 | 160 | int main( int argc, char *argv[] )
|
nkeynes@363 | 161 | {
|
nkeynes@363 | 162 | struct stat st;
|
nkeynes@363 | 163 | int opt;
|
nkeynes@363 | 164 | while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
|
nkeynes@363 | 165 | switch( opt ) {
|
nkeynes@363 | 166 | case 'd':
|
nkeynes@363 | 167 | diff_file = optarg;
|
nkeynes@363 | 168 | break;
|
nkeynes@363 | 169 | case 'o':
|
nkeynes@363 | 170 | output_file = optarg;
|
nkeynes@363 | 171 | break;
|
nkeynes@363 | 172 | case 's':
|
nkeynes@363 | 173 | start_addr = strtoul(optarg, NULL, 0);
|
nkeynes@363 | 174 | break;
|
nkeynes@363 | 175 | case 'h':
|
nkeynes@363 | 176 | usage();
|
nkeynes@363 | 177 | exit(0);
|
nkeynes@363 | 178 | }
|
nkeynes@363 | 179 | }
|
nkeynes@363 | 180 | if( optind < argc ) {
|
nkeynes@363 | 181 | input_file = argv[optind++];
|
nkeynes@363 | 182 | } else {
|
nkeynes@363 | 183 | usage();
|
nkeynes@363 | 184 | exit(1);
|
nkeynes@363 | 185 | }
|
nkeynes@363 | 186 |
|
nkeynes@919 | 187 | mmio_region_MMU.mem = malloc(4096);
|
nkeynes@919 | 188 | memset( mmio_region_MMU.mem, 0, 4096 );
|
nkeynes@919 | 189 |
|
nkeynes@929 | 190 | ((uint32_t *)mmio_region_MMU.mem)[4] = 1;
|
nkeynes@929 | 191 |
|
nkeynes@363 | 192 | in = fopen( input_file, "ro" );
|
nkeynes@363 | 193 | if( in == NULL ) {
|
nkeynes@363 | 194 | perror( "Unable to open input file" );
|
nkeynes@363 | 195 | exit(2);
|
nkeynes@363 | 196 | }
|
nkeynes@363 | 197 | fstat( fileno(in), &st );
|
nkeynes@363 | 198 | inbuf = malloc( st.st_size );
|
nkeynes@363 | 199 | fread( inbuf, st.st_size, 1, in );
|
nkeynes@919 | 200 | sh4_icache.mask = 0xFFFFF000;
|
nkeynes@919 | 201 | sh4_icache.page_vma = start_addr & 0xFFFFF000;
|
nkeynes@919 | 202 | sh4_icache.page = (unsigned char *)(inbuf - (sh4_icache.page_vma&0xFFF));
|
nkeynes@919 | 203 | sh4_icache.page_ppa = start_addr & 0xFFFFF000;
|
nkeynes@363 | 204 |
|
nkeynes@365 | 205 | xlat_cache_init();
|
nkeynes@925 | 206 | uintptr_t pc;
|
nkeynes@365 | 207 | uint8_t *buf = sh4_translate_basic_block( start_addr );
|
nkeynes@919 | 208 | uint32_t buflen = xlat_get_code_size(buf);
|
nkeynes@925 | 209 | x86_disasm_init( buf, buf, buflen );
|
nkeynes@919 | 210 | x86_set_symtab( local_symbols, sizeof(local_symbols)/sizeof(struct x86_symbol) );
|
nkeynes@925 | 211 | for( pc = buf; pc < buf + buflen; ) {
|
nkeynes@363 | 212 | char buf[256];
|
nkeynes@363 | 213 | char op[256];
|
nkeynes@925 | 214 | uintptr_t pc2 = x86_disasm_instruction( pc, buf, sizeof(buf), op );
|
nkeynes@929 | 215 | fprintf( stdout, "%08x: %s\n", pc, buf );
|
nkeynes@363 | 216 | pc = pc2;
|
nkeynes@363 | 217 | }
|
nkeynes@802 | 218 | return 0;
|
nkeynes@363 | 219 | }
|