diff m68k_core.c @ 570:76bba9ffe351

Initial stab at separating the generic parts of the 68K core from the host-cpu specific parts.
author Michael Pavone <pavone@retrodev.com>
date Sun, 02 Mar 2014 16:34:29 -0800
parents
children 1594525e2157
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m68k_core.c	Sun Mar 02 16:34:29 2014 -0800
@@ -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);
+}
+