summaryrefslogtreecommitdiff
path: root/m68k_core.c
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2014-03-02 16:34:29 -0800
committerMichael Pavone <pavone@retrodev.com>2014-03-02 16:34:29 -0800
commit48d6afdd1c9aaafc5b8ce59c584e360d89571a5b (patch)
tree2974a8819a2c80d7fc0ebc2e71b9a8e1370863fe /m68k_core.c
parent8664df5a5d2870c67036666b66ce0d2f9fcdd1eb (diff)
Initial stab at separating the generic parts of the 68K core from the host-cpu specific parts.
Diffstat (limited to 'm68k_core.c')
-rw-r--r--m68k_core.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/m68k_core.c b/m68k_core.c
new file mode 100644
index 0000000..e8038f1
--- /dev/null
+++ b/m68k_core.c
@@ -0,0 +1,280 @@
+/*
+ Copyright 2014 Michael Pavone
+ This file is part of BlastEm.
+ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
+*/
+#include "m68k_core.h"
+#include "m68k_internal.h"
+#include "68kinst.h"
+#include "backend.h"
+#include "gen.h"
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+int8_t native_reg(m68k_op_info * op, m68k_options * opts)
+{
+ if (op->addr_mode == MODE_REG) {
+ return opts->dregs[op->params.regs.pri];
+ }
+ if (op->addr_mode == MODE_AREG) {
+ return opts->aregs[op->params.regs.pri];
+ }
+ return -1;
+}
+
+//must be called with an m68k_op_info that uses a register
+size_t reg_offset(m68k_op_info *op)
+{
+ if (op->addr_mode == MODE_REG) {
+ return offsetof(m68k_context, dregs) + sizeof(uint32_t) * op->params.regs.pri;
+ }
+ return offsetof(m68k_context, aregs) + sizeof(uint32_t) * op->params.regs.pri;
+}
+
+void print_regs_exit(m68k_context * context)
+{
+ printf("XNZVC\n%d%d%d%d%d\n", context->flags[0], context->flags[1], context->flags[2], context->flags[3], context->flags[4]);
+ for (int i = 0; i < 8; i++) {
+ printf("d%d: %X\n", i, context->dregs[i]);
+ }
+ for (int i = 0; i < 8; i++) {
+ printf("a%d: %X\n", i, context->aregs[i]);
+ }
+ exit(0);
+}
+
+void m68k_read_size(m68k_options *opts, uint8_t size)
+{
+ switch (size)
+ {
+ case OPSIZE_BYTE:
+ call(&opts->gen.code, opts->read_8);
+ break;
+ case OPSIZE_WORD:
+ call(&opts->gen.code, opts->read_16);
+ break;
+ case OPSIZE_LONG:
+ call(&opts->gen.code, opts->read_32);
+ break;
+ }
+}
+
+void m68k_write_size(m68k_options *opts, uint8_t size)
+{
+ switch (size)
+ {
+ case OPSIZE_BYTE:
+ call(&opts->gen.code, opts->write_8);
+ break;
+ case OPSIZE_WORD:
+ call(&opts->gen.code, opts->write_16);
+ break;
+ case OPSIZE_LONG:
+ call(&opts->gen.code, opts->write_32_highfirst);
+ break;
+ }
+}
+
+code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address)
+{
+ address &= 0xFFFFFF;
+ address /= 2;
+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
+ if (!native_code_map[chunk].base) {
+ return NULL;
+ }
+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
+ if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET || native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
+ return NULL;
+ }
+ return native_code_map[chunk].base + native_code_map[chunk].offsets[offset];
+}
+
+code_ptr get_native_from_context(m68k_context * context, uint32_t address)
+{
+ return get_native_address(context->native_code_map, address);
+}
+
+uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address)
+{
+ address &= 0xFFFFFF;
+ address /= 2;
+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
+ if (!native_code_map[chunk].base) {
+ return 0;
+ }
+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
+ if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) {
+ return 0;
+ }
+ while (native_code_map[chunk].offsets[offset] == EXTENSION_WORD) {
+ --address;
+ chunk = address / NATIVE_CHUNK_SIZE;
+ offset = address % NATIVE_CHUNK_SIZE;
+ }
+ return address*2;
+}
+
+void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size)
+{
+ native_map_slot * native_code_map = context->native_code_map;
+ m68k_options * opts = context->options;
+ address &= 0xFFFFFF;
+ if (address > 0xE00000) {
+ context->ram_code_flags[(address & 0xC000) >> 14] |= 1 << ((address & 0x3800) >> 11);
+ if (((address & 0x3FFF) + size) & 0xC000) {
+ context->ram_code_flags[((address+size) & 0xC000) >> 14] |= 1 << (((address+size) & 0x3800) >> 11);
+ }
+ uint32_t slot = (address & 0xFFFF)/1024;
+ if (!opts->gen.ram_inst_sizes[slot]) {
+ opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512);
+ }
+ opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512] = native_size;
+ }
+ address/= 2;
+ uint32_t chunk = address / NATIVE_CHUNK_SIZE;
+ if (!native_code_map[chunk].base) {
+ native_code_map[chunk].base = native_addr;
+ native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
+ memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
+ }
+ uint32_t offset = address % NATIVE_CHUNK_SIZE;
+ native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base;
+ for(address++,size-=2; size; address++,size-=2) {
+ chunk = address / NATIVE_CHUNK_SIZE;
+ offset = address % NATIVE_CHUNK_SIZE;
+ if (!native_code_map[chunk].base) {
+ native_code_map[chunk].base = native_addr;
+ native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE);
+ memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE);
+ }
+ native_code_map[chunk].offsets[offset] = EXTENSION_WORD;
+ }
+}
+
+uint8_t get_native_inst_size(m68k_options * opts, uint32_t address)
+{
+ if (address < 0xE00000) {
+ return 0;
+ }
+ uint32_t slot = (address & 0xFFFF)/1024;
+ return opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512];
+}
+
+uint8_t m68k_is_terminal(m68kinst * inst)
+{
+ return inst->op == M68K_RTS || inst->op == M68K_RTE || inst->op == M68K_RTR || inst->op == M68K_JMP
+ || inst->op == M68K_TRAP || inst->op == M68K_ILLEGAL || inst->op == M68K_INVALID || inst->op == M68K_RESET
+ || (inst->op == M68K_BCC && inst->extra.cond == COND_TRUE);
+}
+
+void m68k_handle_deferred(m68k_context * context)
+{
+ m68k_options * opts = context->options;
+ process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
+ if (opts->gen.deferred) {
+ translate_m68k_stream(opts->gen.deferred->address, context);
+ }
+}
+
+void translate_m68k_stream(uint32_t address, m68k_context * context)
+{
+ m68kinst instbuf;
+ m68k_options * opts = context->options;
+ code_info *code = &opts->gen.code;
+ address &= 0xFFFFFF;
+ if(get_native_address(opts->gen.native_code_map, address)) {
+ return;
+ }
+ char disbuf[1024];
+ uint16_t *encoded, *next;
+ if ((address & 0xFFFFFF) < 0x400000) {
+ encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2;
+ } else if ((address & 0xFFFFFF) > 0xE00000) {
+ encoded = context->mem_pointers[1] + (address & 0xFFFF)/2;
+ } else {
+ printf("attempt to translate non-memory address: %X\n", address);
+ exit(1);
+ }
+ do {
+ if (opts->address_log) {
+ fprintf(opts->address_log, "%X\n", address);
+ }
+ do {
+ if (address >= 0x400000 && address < 0xE00000) {
+ translate_out_of_bounds(code);
+ break;
+ }
+ code_ptr existing = get_native_address(opts->gen.native_code_map, address);
+ if (existing) {
+ jmp(code, existing);
+ break;
+ }
+ next = m68k_decode(encoded, &instbuf, address);
+ if (instbuf.op == M68K_INVALID) {
+ instbuf.src.params.immed = *encoded;
+ }
+ uint16_t m68k_size = (next-encoded)*2;
+ address += m68k_size;
+ encoded = next;
+ //m68k_disasm(&instbuf, disbuf);
+ //printf("%X: %s\n", instbuf.address, disbuf);
+
+ //make sure the beginning of the code for an instruction is contiguous
+ check_code_prologue(code);
+ code_ptr start = code->cur;
+ 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));
+ process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context);
+ if (opts->gen.deferred) {
+ address = opts->gen.deferred->address;
+ if ((address & 0xFFFFFF) < 0x400000) {
+ encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2;
+ } else if ((address & 0xFFFFFF) > 0xE00000) {
+ encoded = context->mem_pointers[1] + (address & 0xFFFF)/2;
+ } else {
+ printf("attempt to translate non-memory address: %X\n", address);
+ exit(1);
+ }
+ } else {
+ encoded = NULL;
+ }
+ } while(encoded != NULL);
+}
+
+code_ptr get_native_address_trans(m68k_context * context, uint32_t address)
+{
+ address &= 0xFFFFFF;
+ code_ptr ret = get_native_address(context->native_code_map, address);
+ if (!ret) {
+ translate_m68k_stream(address, context);
+ ret = get_native_address(context->native_code_map, address);
+ }
+ return ret;
+}
+
+void remove_breakpoint(m68k_context * context, uint32_t address)
+{
+ code_ptr native = get_native_address(context->native_code_map, address);
+ check_cycles_int(context->options, address);
+}
+
+void start_68k_context(m68k_context * context, uint32_t address)
+{
+ code_ptr addr = get_native_address_trans(context, address);
+ m68k_options * options = context->options;
+ options->start_context(addr, context);
+}
+
+void m68k_reset(m68k_context * context)
+{
+ //TODO: Make this actually use the normal read functions
+ context->aregs[7] = context->mem_pointers[0][0] << 16 | context->mem_pointers[0][1];
+ uint32_t address = context->mem_pointers[0][2] << 16 | context->mem_pointers[0][3];
+ start_68k_context(context, address);
+}
+