Mercurial > repos > blastem
diff m68k_core.c @ 574:1594525e2157
More 68K core refactoring to both reduce the amount of code and better split the host-cpu specific parts from the generic parts
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 03 Mar 2014 22:17:20 -0800 |
parents | 76bba9ffe351 |
children | 9f40aa5243c2 |
line wrap: on
line diff
--- a/m68k_core.c Mon Mar 03 22:16:41 2014 -0800 +++ b/m68k_core.c Mon Mar 03 22:17:20 2014 -0800 @@ -13,6 +13,8 @@ #include <stdlib.h> #include <string.h> +char disasm_buf[1024]; + int8_t native_reg(m68k_op_info * op, m68k_options * opts) { if (op->addr_mode == MODE_REG) { @@ -24,13 +26,20 @@ return -1; } +size_t dreg_offset(uint8_t reg) +{ + return offsetof(m68k_context, dregs) + sizeof(uint32_t) * reg; +} + +size_t areg_offset(uint8_t reg) +{ + return offsetof(m68k_context, aregs) + sizeof(uint32_t) * reg; +} + //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; + return op->addr_mode == MODE_REG ? dreg_offset(op->params.regs.pri) : areg_offset(op->params.regs.pri); } void print_regs_exit(m68k_context * context) @@ -77,6 +86,281 @@ } } +void translate_m68k_lea(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + int8_t dst_reg = native_reg(&(inst->dst), opts); + switch(inst->src.addr_mode) + { + case MODE_AREG_INDIRECT: + cycles(&opts->gen, BUS); + if (dst_reg >= 0) { + areg_to_native(opts, inst->src.params.regs.pri, dst_reg); + } else { + if (opts->aregs[inst->src.params.regs.pri] >= 0) { + native_to_areg(opts, opts->aregs[inst->src.params.regs.pri], inst->dst.params.regs.pri); + } else { + areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + } + break; + case MODE_AREG_DISPLACE: + cycles(&opts->gen, 8); + calc_areg_displace(opts, &inst->src, dst_reg >= 0 ? dst_reg : opts->gen.scratch1); + if (dst_reg < 0) { + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + break; + case MODE_AREG_INDEX_DISP8: + cycles(&opts->gen, 12); + if (dst_reg < 0 || inst->dst.params.regs.pri == inst->src.params.regs.pri || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) { + dst_reg = opts->gen.scratch1; + } + calc_areg_index_disp8(opts, &inst->src, dst_reg); + if (dst_reg == opts->gen.scratch1) { + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + break; + case MODE_PC_DISPLACE: + cycles(&opts->gen, 8); + ldi_areg(opts, inst->src.params.regs.displacement + inst->address+2, inst->dst.params.regs.pri); + break; + case MODE_PC_INDEX_DISP8: + cycles(&opts->gen, BUS*3); + if (dst_reg < 0 || inst->dst.params.regs.pri == (inst->src.params.regs.sec >> 1 & 0x7)) { + dst_reg = opts->gen.scratch1; + } + ldi_native(opts, inst->address+2, dst_reg); + calc_index_disp8(opts, &inst->src, dst_reg); + if (dst_reg == opts->gen.scratch1) { + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + } + break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2); + ldi_areg(opts, inst->src.params.immed, inst->dst.params.regs.pri); + break; + default: + m68k_disasm(inst, disasm_buf); + printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode); + exit(1); + } +} + +void translate_m68k_pea(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + switch(inst->src.addr_mode) + { + case MODE_AREG_INDIRECT: + cycles(&opts->gen, BUS); + areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); + break; + case MODE_AREG_DISPLACE: + cycles(&opts->gen, 8); + calc_areg_displace(opts, &inst->src, opts->gen.scratch1); + break; + case MODE_AREG_INDEX_DISP8: + cycles(&opts->gen, 6);//TODO: Check to make sure this is correct + calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1); + break; + case MODE_PC_DISPLACE: + cycles(&opts->gen, 8); + ldi_native(opts, inst->src.params.regs.displacement + inst->address+2, opts->gen.scratch1); + break; + case MODE_PC_INDEX_DISP8: + cycles(&opts->gen, BUS*3);//TODO: Check to make sure this is correct + ldi_native(opts, inst->address+2, opts->gen.scratch1); + calc_index_disp8(opts, &inst->src, opts->gen.scratch1); + break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + cycles(&opts->gen, (inst->src.addr_mode == MODE_ABSOLUTE) ? BUS * 3 : BUS * 2); + ldi_native(opts, inst->src.params.immed, opts->gen.scratch1); + break; + default: + m68k_disasm(inst, disasm_buf); + printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode); + exit(1); + } + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(code, opts->write_32_lowfirst); +} + +void push_const(m68k_options *opts, int32_t value) +{ + ldi_native(opts, value, opts->gen.scratch1); + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + call(&opts->gen.code, opts->write_32_highfirst); +} + +void jump_m68k_abs(m68k_options * opts, uint32_t address) +{ + code_info *code = &opts->gen.code; + code_ptr dest_addr = get_native_address(opts->gen.native_code_map, address); + if (!dest_addr) { + opts->gen.deferred = defer_address(opts->gen.deferred, address, code->cur + 1); + //dummy address to be replaced later, make sure it generates a 4-byte displacement + dest_addr = code->cur + 256; + } + jmp(code, dest_addr); + //this used to call opts->native_addr for destinations in RAM, but that shouldn't be needed + //since instruction retranslation patches the original native instruction location +} + +void translate_m68k_bsr(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + int32_t disp = inst->src.params.immed; + uint32_t after = inst->address + (inst->variant == VAR_BYTE ? 2 : 4); + //TODO: Add cycles in the right place relative to pushing the return address on the stack + cycles(&opts->gen, 10); + push_const(opts, after); + jump_m68k_abs(opts, inst->address + 2 + disp); +} + +void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst) +{ + uint8_t is_jsr = inst->op == M68K_JSR; + code_info *code = &opts->gen.code; + code_ptr dest_addr; + uint8_t sec_reg; + uint32_t after; + uint32_t m68k_addr; + switch(inst->src.addr_mode) + { + case MODE_AREG_INDIRECT: + cycles(&opts->gen, BUS*2); + if (is_jsr) { + push_const(opts, inst->address+2); + } + areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + break; + case MODE_AREG_DISPLACE: + cycles(&opts->gen, BUS*2); + if (is_jsr) { + push_const(opts, inst->address+4); + } + calc_areg_displace(opts, &inst->src, opts->gen.scratch1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + break; + case MODE_AREG_INDEX_DISP8: + cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct + if (is_jsr) { + push_const(opts, inst->address+4); + } + calc_areg_index_disp8(opts, &inst->src, opts->gen.scratch1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + break; + case MODE_PC_DISPLACE: + //TODO: Add cycles in the right place relative to pushing the return address on the stack + cycles(&opts->gen, 10); + if (is_jsr) { + push_const(opts, inst->address+4); + } + jump_m68k_abs(opts, inst->src.params.regs.displacement + inst->address + 2); + break; + case MODE_PC_INDEX_DISP8: + cycles(&opts->gen, BUS*3);//TODO: CHeck that this is correct + if (is_jsr) { + push_const(opts, inst->address+4); + } + ldi_native(opts, inst->address+2, opts->gen.scratch1); + calc_index_disp8(opts, &inst->src, opts->gen.scratch1); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); + break; + case MODE_ABSOLUTE: + case MODE_ABSOLUTE_SHORT: + //TODO: Add cycles in the right place relative to pushing the return address on the stack + cycles(&opts->gen, inst->src.addr_mode == MODE_ABSOLUTE ? 12 : 10); + if (is_jsr) { + push_const(opts, inst->address + (inst->src.addr_mode == MODE_ABSOLUTE ? 6 : 4)); + } + jump_m68k_abs(opts, inst->src.params.immed); + break; + default: + m68k_disasm(inst, disasm_buf); + printf("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp"); + exit(1); + } +} + +void translate_m68k_unlk(m68k_options * opts, m68kinst * inst) +{ + cycles(&opts->gen, BUS); + areg_to_native(opts, inst->dst.params.regs.pri, opts->aregs[7]); + areg_to_native(opts, 7, opts->gen.scratch1); + call(&opts->gen.code, opts->read_32); + native_to_areg(opts, opts->gen.scratch1, inst->dst.params.regs.pri); + addi_areg(opts, 4, 7); +} + +void translate_m68k_link(m68k_options * opts, m68kinst * inst) +{ + //compensate for displacement word + cycles(&opts->gen, BUS); + subi_areg(opts, 4, 7); + areg_to_native(opts, 7, opts->gen.scratch2); + areg_to_native(opts, inst->src.params.regs.pri, opts->gen.scratch1); + call(&opts->gen.code, opts->write_32_highfirst); + native_to_areg(opts, opts->aregs[7], inst->src.params.regs.pri); + addi_areg(opts, inst->dst.params.immed, 7); + //prefetch + cycles(&opts->gen, BUS); +} + +void translate_m68k_rts(m68k_options * opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + //TODO: Add cycles + areg_to_native(opts, 7, opts->gen.scratch1); + addi_areg(opts, 4, 7); + call(code, opts->read_32); + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); +} + +void translate_m68k_rtr(m68k_options *opts, m68kinst * inst) +{ + code_info *code = &opts->gen.code; + //Read saved CCR + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_16); + addi_areg(opts, 2, 7); + call(code, opts->set_ccr); + //Read saved PC + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_32); + addi_areg(opts, 4, 7); + //Get native address and jump to it + call(code, opts->native_addr); + jmp_r(code, opts->gen.scratch1); +} + +void translate_m68k_trap(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + ldi_native(opts, inst->src.params.immed + VECTOR_TRAP_0, opts->gen.scratch2); + ldi_native(opts, inst->address+2, opts->gen.scratch1); + jmp(code, opts->trap); +} + +void swap_ssp_usp(m68k_options * opts) +{ + areg_to_native(opts, 7, opts->gen.scratch2); + areg_to_native(opts, 8, opts->aregs[7]); + native_to_areg(opts, opts->gen.scratch2, 8); +} + code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address) { address &= 0xFFFFFF; @@ -278,3 +562,12 @@ start_68k_context(context, address); } + +void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts) +{ + memset(context, 0, sizeof(m68k_context)); + context->native_code_map = native_code_map; + context->options = opts; + context->int_cycle = 0xFFFFFFFF; + context->status = 0x27; +}