summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend.h3
-rw-r--r--backend_x86.c11
-rw-r--r--m68k_core.c18
-rw-r--r--m68k_core.h3
-rw-r--r--m68k_core_x86.c168
-rw-r--r--m68k_internal.h1
6 files changed, 181 insertions, 23 deletions
diff --git a/backend.h b/backend.h
index 6c18675..388ce3a 100644
--- a/backend.h
+++ b/backend.h
@@ -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);