diff options
author | Michael Pavone <pavone@retrodev.com> | 2016-04-26 23:13:37 -0700 |
---|---|---|
committer | Michael Pavone <pavone@retrodev.com> | 2016-04-26 23:13:37 -0700 |
commit | 8b7027061d5d79712f2bdd859f55923d571efb4f (patch) | |
tree | b7d0e553d1fa1f450e21f64e561a2b74bc849530 | |
parent | 042768acd31ac2a59049db55e31b647c2eb51818 (diff) |
Initial stab at implementing address error exceptions. Need to fill in the value of IR, undefined bits of last stack frame word and properly deal with address errors that occur during exception processing.
-rw-r--r-- | backend.h | 3 | ||||
-rw-r--r-- | backend_x86.c | 11 | ||||
-rw-r--r-- | m68k_core.c | 18 | ||||
-rw-r--r-- | m68k_core.h | 3 | ||||
-rw-r--r-- | m68k_core_x86.c | 168 | ||||
-rw-r--r-- | m68k_internal.h | 1 |
6 files changed, 181 insertions, 23 deletions
@@ -86,6 +86,8 @@ typedef struct { code_ptr handle_cycle_limit; code_ptr handle_cycle_limit_int; code_ptr handle_code_write; + code_ptr handle_align_error_write; + code_ptr handle_align_error_read; uint32_t memmap_chunks; uint32_t address_mask; uint32_t max_address; @@ -101,6 +103,7 @@ typedef struct { uint8_t limit; uint8_t scratch1; uint8_t scratch2; + uint8_t align_error_mask; } cpu_options; typedef uint8_t * (*native_addr_func)(void * context, uint32_t address); diff --git a/backend_x86.c b/backend_x86.c index 2892f83..0619dd7 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -51,18 +51,23 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n code_info *code = &opts->code; code_ptr start = code->cur; check_cycles(opts); + uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8; + uint8_t adr_reg = is_write ? opts->scratch2 : opts->scratch1; + uint8_t size = (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B; + if (size != SZ_B && opts->align_error_mask) { + test_ir(code, opts->align_error_mask, adr_reg, SZ_D); + jcc(code, CC_NZ, is_write ? opts->handle_align_error_write : opts->handle_align_error_read); + } cycles(opts, opts->bus_cycles); if (after_inc) { *after_inc = code->cur; } - uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8; - uint8_t adr_reg = is_write ? opts->scratch2 : opts->scratch1; + if (opts->address_size == SZ_D && opts->address_mask != 0xFFFFFFFF) { and_ir(code, opts->address_mask, adr_reg, SZ_D); } code_ptr lb_jcc = NULL, ub_jcc = NULL; uint16_t access_flag = is_write ? MMAP_WRITE : MMAP_READ; - uint8_t size = (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B; uint32_t ram_flags_off = opts->ram_flags_off; for (uint32_t chunk = 0; chunk < num_chunks; chunk++) { diff --git a/m68k_core.c b/m68k_core.c index b687045..5a302ab 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -553,9 +553,7 @@ code_ptr get_native_address(m68k_options *opts, uint32_t address) { native_map_slot * native_code_map = opts->gen.native_code_map; address &= opts->gen.address_mask; - if (address & 1) { - return opts->odd_address; - } + //TODO: Refactor part of this loop into some kind of get_ram_chunk function for (int i = 0; i < opts->gen.memmap_chunks; i++) { if (address >= opts->gen.memmap[i].start && address < opts->gen.memmap[i].end) { @@ -563,7 +561,7 @@ code_ptr get_native_address(m68k_options *opts, uint32_t address) address = opts->gen.memmap[i].start + ((address - opts->gen.memmap[i].start) & opts->gen.memmap[i].mask); } } - address /= 2; + uint32_t chunk = address / NATIVE_CHUNK_SIZE; if (!native_code_map[chunk].base) { return NULL; @@ -591,7 +589,6 @@ uint32_t get_instruction_start(m68k_options *opts, native_map_slot * native_code } } - address /= 2; uint32_t chunk = address / NATIVE_CHUNK_SIZE; if (!native_code_map[chunk].base) { return 0; @@ -643,7 +640,7 @@ void map_native_address(m68k_context * context, uint32_t address, code_ptr nativ meta_off += size; } } - address/= 2; + uint32_t chunk = address / NATIVE_CHUNK_SIZE; if (!native_code_map[chunk].base) { native_code_map[chunk].base = native_addr; @@ -819,6 +816,10 @@ impl_info m68k_impls[] = { void translate_m68k(m68k_options * opts, m68kinst * inst) { + if (inst->address & 1) { + translate_m68k_odd(opts, inst); + return; + } check_cycles_int(&opts->gen, inst->address); //log_address(&opts->gen, inst->address, "M68K: %X @ %d\n"); if ( @@ -872,9 +873,6 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) fflush(opts->address_log); } do { - if (address & 1) { - break; - } encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); if (!encoded) { map_native_address(context, address, code->cur, 2, 1); @@ -902,7 +900,7 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) translate_m68k(opts, &instbuf); code_ptr after = code->cur; map_native_address(context, instbuf.address, start, m68k_size, after-start); - } while(!m68k_is_terminal(&instbuf)); + } while(!m68k_is_terminal(&instbuf) && !(address & 1)); process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context); if (opts->gen.deferred) { address = opts->gen.deferred->address; diff --git a/m68k_core.h b/m68k_core.h index cc9ca24..204ba44 100644 --- a/m68k_core.h +++ b/m68k_core.h @@ -13,7 +13,7 @@ struct m68kinst; #define NUM_MEM_AREAS 8 #define NATIVE_MAP_CHUNKS (64*1024) -#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2) +#define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)) #define MAX_NATIVE_SIZE 255 #define M68K_OPT_BROKEN_READ_MODIFY 1 @@ -36,7 +36,6 @@ typedef struct { code_ptr write_32_highfirst; code_ptr do_sync; code_ptr trap; - code_ptr odd_address; start_fun start_context; code_ptr retrans_stub; code_ptr native_addr; diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 48d245b..2533452 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2128,6 +2128,54 @@ void translate_m68k_trapv(m68k_options *opts, m68kinst *inst) *no_trap = code->cur - (no_trap + 1); } +void translate_m68k_odd(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + //swap USP and SSP if not already in supervisor mode + check_user_mode_swap_ssp_usp(opts); + //save PC + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D); + call(code, opts->write_32_lowfirst); + //save status register + subi_areg(opts, 2, 7); + call(code, opts->get_sr); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //save instruction register + subi_areg(opts, 2, 7); + //TODO: Use actual value + mov_ir(code, 0, opts->gen.scratch1, SZ_W); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //save access address + subi_areg(opts, 4, 7); + mov_ir(code, inst->address, opts->gen.scratch1, SZ_D); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_32_lowfirst); + //save FC, I/N and R/W word' + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W); + //FC3 is basically the same as the supervisor bit + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B); + shr_ir(code, 3, opts->gen.scratch1, SZ_B); + and_ir(code, 4, opts->gen.scratch1, SZ_B); + //set FC1 to one to indicate instruction fetch, and R/W to indicate read + or_ir(code, 0x12, opts->gen.scratch1, SZ_B); + //TODO: Figure out what undefined bits get set to, looks like it might be value of IR + subi_areg(opts, 2, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //set supervisor bit + or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + //load vector address + mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D); + call(code, opts->read_32); + call(code, opts->native_addr_and_sync); + cycles(&opts->gen, 18); + jmp_r(code, opts->gen.scratch1); +} + void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { code_info *code = &opts->gen.code; @@ -2285,6 +2333,7 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->gen.cycles = RAX; opts->gen.limit = RBP; opts->gen.scratch1 = RCX; + opts->gen.align_error_mask = 1; opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); @@ -2392,7 +2441,14 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu retn(code); opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write; - + + check_alloc_code(code, 256); + opts->gen.handle_align_error_write = code->cur; + code->cur += 256; + check_alloc_code(code, 256); + opts->gen.handle_align_error_read = code->cur; + code->cur += 256; + opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL); opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL); opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL); @@ -2493,6 +2549,109 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu } } retn(code); + + code_info tmp_code = *code; + code->cur = opts->gen.handle_align_error_write; + code->last = code->cur + 256; + //unwind the stack one functinon call + add_ir(code, 16, RSP, SZ_PTR); + //save address that triggered error so we can write it to the 68K stack at the appropriate place + push_r(code, opts->gen.scratch2); + //swap USP and SSP if not already in supervisor mode + check_user_mode_swap_ssp_usp(opts); + //save PC + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D); + call(code, opts->write_32_lowfirst); + //save status register + subi_areg(opts, 2, 7); + call(code, opts->get_sr); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //save instruction register + subi_areg(opts, 2, 7); + //TODO: Use actual value + mov_ir(code, 0, opts->gen.scratch1, SZ_W); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //save access address + subi_areg(opts, 4, 7); + pop_r(code, opts->gen.scratch1); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_32_lowfirst); + //save FC, I/N and R/W word' + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W); + //FC3 is basically the same as the supervisor bit + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B); + shr_ir(code, 3, opts->gen.scratch1, SZ_B); + and_ir(code, 4, opts->gen.scratch1, SZ_B); + //set FC0 to one to indicate data access + or_ir(code, 1, opts->gen.scratch1, SZ_B); + //TODO: Figure out what undefined bits get set to, looks like it might be value of IR + subi_areg(opts, 2, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //set supervisor bit + or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + //load vector address + mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D); + call(code, opts->read_32); + call(code, opts->native_addr_and_sync); + cycles(&opts->gen, 18); + jmp_r(code, opts->gen.scratch1); + + code->cur = opts->gen.handle_align_error_read; + code->last = code->cur + 256; + //unwind the stack one functinon call + add_ir(code, 16, RSP, SZ_PTR); + //save address that triggered error so we can write it to the 68K stack at the appropriate place + push_r(code, opts->gen.scratch1); + //swap USP and SSP if not already in supervisor mode + check_user_mode_swap_ssp_usp(opts); + //save PC + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, last_prefetch_address), opts->gen.scratch1, SZ_D); + call(code, opts->write_32_lowfirst); + //save status register + subi_areg(opts, 2, 7); + call(code, opts->get_sr); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //save instruction register + subi_areg(opts, 2, 7); + //TODO: Use actual value + mov_ir(code, 0, opts->gen.scratch1, SZ_W); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //save access address + subi_areg(opts, 4, 7); + pop_r(code, opts->gen.scratch1); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_32_lowfirst); + //save FC, I/N and R/W word' + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_W); + //FC3 is basically the same as the supervisor bit + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, status), opts->gen.scratch1, SZ_B); + shr_ir(code, 3, opts->gen.scratch1, SZ_B); + and_ir(code, 4, opts->gen.scratch1, SZ_B); + //set FC0 to one to indicate data access, and R/W to indicate read + or_ir(code, 0x11, opts->gen.scratch1, SZ_B); + //TODO: Figure out what undefined bits get set to, looks like it might be value of IR + subi_areg(opts, 2, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_16); + //set supervisor bit + or_irdisp(code, 0x20, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + //load vector address + mov_ir(code, 4 * VECTOR_ADDRESS_ERROR, opts->gen.scratch1, SZ_D); + call(code, opts->read_32); + call(code, opts->native_addr_and_sync); + cycles(&opts->gen, 18); + jmp_r(code, opts->gen.scratch1); + + *code = tmp_code; opts->gen.handle_cycle_limit_int = code->cur; //calculate stack adjust size @@ -2630,11 +2789,4 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu call(code, opts->native_addr_and_sync); cycles(&opts->gen, 18); jmp_r(code, opts->gen.scratch1); - - opts->odd_address = code->cur; - mov_ir(code, (int64_t)stderr, RDI, SZ_PTR); - mov_ir(code, (int64_t)"Attempt to execute code at odd address\n", RSI, SZ_PTR); - call_args_abi(code, (code_ptr)fprintf, 2, RDI, RSI, RDX); - xor_rr(code, RDI, RDI, SZ_D); - call_args(code, (code_ptr)exit, 1, RDI); } diff --git a/m68k_internal.h b/m68k_internal.h index dbfc0df..4b32e4a 100644 --- a/m68k_internal.h +++ b/m68k_internal.h @@ -33,6 +33,7 @@ void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_ void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst); void check_user_mode_swap_ssp_usp(m68k_options *opts); void m68k_set_last_prefetch(m68k_options *opts, uint32_t address); +void translate_m68k_odd(m68k_options *opts, m68kinst *inst); //functions implemented in m68k_core.c int8_t native_reg(m68k_op_info * op, m68k_options * opts); |