# HG changeset patch # User Michael Pavone # Date 1461737617 25200 # Node ID 1f09994e92c5974e7f28abf6266fb98d56d6fb20 # Parent f680fe746a7d53b47689b95a346e6f24dee40667 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. diff -r f680fe746a7d -r 1f09994e92c5 backend.h --- a/backend.h Tue Apr 26 00:07:15 2016 -0700 +++ b/backend.h Tue Apr 26 23:13:37 2016 -0700 @@ -86,6 +86,8 @@ 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 @@ 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 -r f680fe746a7d -r 1f09994e92c5 backend_x86.c --- a/backend_x86.c Tue Apr 26 00:07:15 2016 -0700 +++ b/backend_x86.c Tue Apr 26 23:13:37 2016 -0700 @@ -51,18 +51,23 @@ 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 -r f680fe746a7d -r 1f09994e92c5 m68k_core.c --- a/m68k_core.c Tue Apr 26 00:07:15 2016 -0700 +++ b/m68k_core.c Tue Apr 26 23:13:37 2016 -0700 @@ -553,9 +553,7 @@ { 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 @@ 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 @@ } } - address /= 2; uint32_t chunk = address / NATIVE_CHUNK_SIZE; if (!native_code_map[chunk].base) { return 0; @@ -643,7 +640,7 @@ 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 @@ 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 @@ 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 @@ 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 -r f680fe746a7d -r 1f09994e92c5 m68k_core.h --- a/m68k_core.h Tue Apr 26 00:07:15 2016 -0700 +++ b/m68k_core.h Tue Apr 26 23:13:37 2016 -0700 @@ -13,7 +13,7 @@ #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 @@ 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 -r f680fe746a7d -r 1f09994e92c5 m68k_core_x86.c --- a/m68k_core_x86.c Tue Apr 26 00:07:15 2016 -0700 +++ b/m68k_core_x86.c Tue Apr 26 23:13:37 2016 -0700 @@ -2128,6 +2128,54 @@ *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 @@ 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 @@ 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 @@ } } 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 @@ 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 -r f680fe746a7d -r 1f09994e92c5 m68k_internal.h --- a/m68k_internal.h Tue Apr 26 00:07:15 2016 -0700 +++ b/m68k_internal.h Tue Apr 26 23:13:37 2016 -0700 @@ -33,6 +33,7 @@ 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);