summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pavone <pavone@retrodev.com>2013-04-16 22:29:00 -0700
committerMike Pavone <pavone@retrodev.com>2013-04-16 22:29:00 -0700
commit9d263ae4d5ae12022177b4dda9120c88b20604df (patch)
treef2e177496bae97b9fa1b9cf02875e2e5b5b39aef
parent5b8b2105a5ebee2f9d272c06ba129c7f1fbb8922 (diff)
Make reset trigger debug exit to make it easier to test the same cases in blastem and musashi. Fix asl #1 overflow flag.
-rw-r--r--m68k_to_x86.c7
-rw-r--r--z80_to_x86.c369
-rw-r--r--z80_to_x86.h39
-rw-r--r--z80inst.c7
-rw-r--r--z80inst.h2
5 files changed, 419 insertions, 5 deletions
diff --git a/m68k_to_x86.c b/m68k_to_x86.c
index cb29a83..c8d9432 100644
--- a/m68k_to_x86.c
+++ b/m68k_to_x86.c
@@ -2640,6 +2640,7 @@ uint8_t * translate_shift(uint8_t * dst, m68kinst * inst, x86_ea *src_op, x86_ea
} else {
dst = shift_irdisp8(dst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size);
}
+ dst = setcc_r(dst, CC_O, FLAG_V);
}
} else {
if (src_op->base != RCX) {
@@ -3432,7 +3433,11 @@ uint8_t * translate_m68k(uint8_t * dst, m68kinst * inst, x86_68k_options * opts)
}
}
break;
- /*case M68K_RESET:*/
+ case M68K_RESET:
+ dst = call(dst, (uint8_t *)m68k_save_context);
+ dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
+ dst = call(dst, (uint8_t *)print_regs_exit);
+ break;
case M68K_ROL:
case M68K_ROR:
dst = mov_ir(dst, 0, FLAG_V, SZ_B);
diff --git a/z80_to_x86.c b/z80_to_x86.c
new file mode 100644
index 0000000..5acabc6
--- /dev/null
+++ b/z80_to_x86.c
@@ -0,0 +1,369 @@
+#include "z80_to_x86.h"
+#include "gen_x86.h"
+
+#define MODE_UNUSED (MODE_IMMED-1)
+
+#define ZCYCLES RBP
+#define SCRATCH1 R13
+#define SCRATCH2 R14
+
+void z80_read_byte();
+void z80_read_word();
+
+uint8_t z80_size(z80_inst * inst)
+{
+ uint8_t reg = (inst->reg & 0x1F);
+ if (reg != Z80_UNUSED &&) {
+ return reg < Z80_BC ? SZ_B : SZ_W;
+ }
+ //TODO: Handle any necessary special cases
+ return SZ_B;
+}
+
+uint8_t * zcylces(dst, uint32_t num_cycles)
+{
+ return add_ir(dst, num_cycles, ZCYCLES, SZ_D);
+}
+
+uint8_t * translate_z80_reg(z80_inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts)
+{
+ if (inst->reg == Z80_USE_IMMED) {
+ ea->mode = MODE_IMMED;
+ ea->disp = inst->immed;
+ } else if ((inst->reg & 0x1F) == Z80_UNUSED) {
+ ea->mode = MODE_UNUSED;
+ } else {
+ ea->mode = MODE_REG;
+ if (inst->reg == Z80_IYH) {
+ ea->base = opts->regs[Z80_IYL];
+ dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+ } else {
+ ea->base = opts->regs[inst->reg]
+ }
+ }
+ return dst;
+}
+
+uint8_t * save_z80_reg(uint8_t * dst, z80_inst * inst, x86_z80_options * opts)
+{
+ if (inst->reg == Z80_IYH) {
+ dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+ }
+ return dst;
+}
+
+uint8_t * translate_z80_ea(z80_inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts, uint8_t read, uint8_t modify)
+{
+ uint8_t size, reg, areg;
+ ea->mode = MODE_REG;
+ areg = read ? SCRATCH1 : SCRATCH2;
+ switch(inst->addr_mode & 0x1F)
+ {
+ case Z80_REG:
+ if (inst->ea_reg == Z80_IYH) {
+ ea->base = opts->regs[Z80_IYL];
+ dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+ } else {
+ ea->base = opts->regs[inst->ea_reg];
+ }
+ break;
+ case Z80_REG_INDIRECT:
+ dst = mov_rr(dst, opts->regs[inst->ea_reg], areg, SZ_W);
+ size = z80_size(inst);
+ if (read) {
+ if (modify) {
+ dst = push_r(dst, SCRATCH1);
+ }
+ if (size == SZ_B) {
+ dst = call(dst, (uint8_t *)z80_read_byte);
+ } else {
+ dst = call(dst, (uint8_t *)z80_read_word);
+ }
+ if (modify) {
+ dst = pop_r(dst, SCRATCH2);
+ }
+ }
+ ea->base = SCRATCH1;
+ break;
+ case Z80_IMMED:
+ ea->mode = MODE_IMMED;
+ ea->disp = inst->immed;
+ break;
+ case Z80_IMMED_INDIRECT:
+ dst = mov_ir(dst, inst->immed, areg, SZ_W);
+ size = z80_size(inst);
+ if (read) {
+ if (modify) {
+ dst = push_r(dst, SCRATCH1);
+ }
+ if (size == SZ_B) {
+ dst = call(dst, (uint8_t *)z80_read_byte);
+ } else {
+ dst = call(dst, (uint8_t *)z80_read_word);
+ }
+ if (modify) {
+ dst = pop_r(dst, SCRATCH2);
+ }
+ }
+ ea->base = SCRATCH1;
+ break;
+ case Z80_IX_INDEXED:
+ case Z80_IY_INDEXED:
+ reg = opts->regs[inst->addr_mode == Z80_IX_INDEXED ? Z80_IX : Z80_IY];
+ dst = mov_rr(dst, reg, areg, SZ_W);
+ dst = add_ir(dst, inst->immed, areg, SZ_W);
+ size = z80_size(inst);
+ if (read) {
+ if (modify) {
+ dst = push_r(dst, SCRATCH1);
+ }
+ if (size == SZ_B) {
+ dst = call(dst, (uint8_t *)z80_read_byte);
+ } else {
+ dst = call(dst, (uint8_t *)z80_read_word);
+ }
+ if (modify) {
+ dst = pop_r(dst, SCRATCH2);
+ }
+ }
+ break;
+ case Z80_UNUSED:
+ ea->mode = MODE_UNUSED:
+ break;
+ default:
+ fprintf(stderr, "Unrecognized Z80 addressing mode %d\n", inst->addr_mode);
+ exit(1);
+ }
+ return dst;
+}
+
+uint8_t * z80_save_ea(uint8_t * dst, z80_inst * inst, x86_z80_options * opts)
+{
+ if (inst->addr_mode == Z80_REG_DIRECT && inst->ea_reg == Z80_IYH) {
+ dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W);
+ }
+ return dst;
+}
+
+uint8_t * z80_save_result(uint8_t * dst, z80_inst * inst)
+{
+ if (z80_size(inst). == SZ_B) {
+ dst = call(dst, (uint8_t *)z80_write_byte);
+ } else {
+ dst = call(dst, (uint8_t *)z80_write_word);
+ }
+ return dst;
+}
+
+enum {
+ DONT_READ=0,
+ READ
+};
+
+enum {
+ DONT_MODIFY=0,
+ MODIFY
+};
+
+uint8_t zf_off(uint8_t flag)
+{
+ return offsetof(z80_context, flags) + flag;
+}
+
+uint8_t * translate_z80_inst(z80_inst * inst, uint8_t * dst, x86_z80_options * opts)
+{
+ uint32_t cycles;
+ x86_ea src_op, dst_op;
+ switch(inst->op)
+ {
+ case Z80_LD:
+ if (inst->addr_mode & Z80_DIR) {
+ dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+ dst = translate_z80_reg(inst, &dst_op, dst, opts);
+ } else {
+ dst = translate_z80_reg(inst, &src_op, dst, opts);
+ dst = translate_z80_ea(inst, &dst_op, dst, opts, DONT_READ, MODIFY);
+ }
+ if (ea_op.mode == MODE_REG_DIRECT) {
+ dst = mov_rr(dst, ea_op.base, reg_op.base, z80_size(inst));
+ } else {
+ dst = mov_ir(dst, ea_op.disp, reg_op.base, z80_size(inst));
+ }
+ dst = z80_save_reg(dst, inst, opts);
+ dst = z80_save_ea(dst, inst, opts);
+ if (!(inst->addr_mode & Z80_DIR)) {
+ dst = z80_save_result(dst, inst, opts);
+ }
+ break;
+ case Z80_PUSH:
+ dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5);
+ dst = sub_ir(dst, opts->regs[Z80_SP], SZ_W);
+ dst = translate_z80_reg(inst, &src_op, dst, opts);
+ dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
+ dst = call(dst, z80_write_word);
+ break;
+ case Z80_POP:
+ dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4);
+ dst = sub_ir(dst, opts->regs[Z80_SP], SZ_W);
+ dst = translate_z80_reg(inst, &src_op, dst, opts);
+ dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W);
+ dst = call(dst, z80_write_word);
+ break;
+ /*case Z80_EX:
+ case Z80_EXX:
+ case Z80_LDI:
+ case Z80_LDIR:
+ case Z80_LDD:
+ case Z80_LDDR:
+ case Z80_CPI:
+ case Z80_CPIR:
+ case Z80_CPD:
+ case Z80_CPDR:
+ break;*/
+ case Z80_ADD:
+ cycles = 4;
+ if (inst->addr_mode == Z80_IX_INDIRECT || inst->addr_mdoe == Z80_IY_INDIRECT) {
+ cycles += 12;
+ } else if(inst->addr_mode == Z80_IMMED) {
+ cycles += 3;
+ } else if(z80_size(inst) == SZ_W) {
+ cycles += 4;
+ }
+ dst = zcycles(dst, cycles);
+ dst = translate_z80_reg(inst, &dst_op, dst, opts);
+ dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+ if (src_op.mode == MODE_REG_DIRECT) {
+ dst = add_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+ } else {
+ dst = add_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+ }
+ dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
+ dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N));
+ //TODO: Implement half-carry flag
+ if (z80_size(inst) == SZ_B) {
+ dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
+ dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
+ dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S));
+ }
+ dst = z80_save_reg(dst, inst, opts);
+ dst = z80_save_ea(dst, inst, opts);
+ break;
+ /*case Z80_ADC:
+ break;*/
+ case Z80_SUB:
+ cycles = 4;
+ if (inst->addr_mode == Z80_IX_INDIRECT || inst->addr_mdoe == Z80_IY_INDIRECT) {
+ cycles += 12;
+ } else if(inst->addr_mode == Z80_IMMED) {
+ cycles += 3;
+ }
+ dst = zcycles(dst, cycles);
+ dst = translate_z80_reg(inst, &dst_op, dst, opts);
+ dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY);
+ if (src_op.mode == MODE_REG_DIRECT) {
+ dst = sub_rr(dst, src_op.base, dst_op.base, z80_size(inst));
+ } else {
+ dst = sub_ir(dst, src_op.disp, dst_op.base, z80_size(inst));
+ }
+ dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C));
+ dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N));
+ dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
+ //TODO: Implement half-carry flag
+ dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
+ dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S)
+ dst = z80_save_reg(dst, inst, opts);
+ dst = z80_save_ea(dst, inst, opts);
+ break;
+ /*case Z80_SBC:
+ case Z80_AND:
+ case Z80_OR:
+ case Z80_XOR:
+ case Z80_CP:*/
+ case Z80_INC:
+ cycles = 4;
+ if (inst->reg == Z80_IX || inst->reg == Z80_IY) {
+ cycles += 6;
+ } else if(z80_size(inst) == SZ_W) {
+ cycles += 2;
+ } else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) {
+ cycles += 4;
+ }
+ dst = translate_z80_reg(inst, &dst_op, dst, opts);
+ if (dst_op.mode == MODE_UNUSED) {
+ dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY);
+ }
+ dst = add_ir(dst, 1, dst_op.base, z80_size(inst));
+ if (z80_size(inst) == SZ_B) {
+ dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N));
+ //TODO: Implement half-carry flag
+ dst = setcc_rdisp8(dst, CC_O, zf_off(ZF_PV));
+ dst = setcc_rdisp8(dst, CC_Z, zf_off(ZF_Z));
+ dst = setcc_rdisp8(dst, CC_S, zf_off(ZF_S));
+ }
+ dst = z80_save_reg(dst, inst, opts);
+ dst = z80_save_ea(dst, inst, opts);
+ break;
+ /*case Z80_DEC:
+ break;
+ case Z80_DAA:
+ case Z80_CPL:
+ case Z80_NEG:
+ case Z80_CCF:
+ case Z80_SCF:*/
+ case Z80_NOP:
+ if (inst->immed == 42) {
+ dst = call(dst, (uint8_t *)z80_save_context);
+ dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
+ dst = jmp(dst, (uint8_t *)z80_print_regs_exit);
+ } else {
+ dst = zcycles(dst, 4 * inst->immed);
+ }
+ break;
+ /*case Z80_HALT:
+ case Z80_DI:
+ case Z80_EI:
+ case Z80_IM:
+ case Z80_RLC:
+ case Z80_RL:
+ case Z80_RRC:
+ case Z80_RR:
+ case Z80_SLA:
+ case Z80_SRA:
+ case Z80_SLL:
+ case Z80_SRL:
+ case Z80_RLD:
+ case Z80_RRD:
+ case Z80_BIT:
+ case Z80_SET:
+ case Z80_RES:
+ case Z80_JP:
+ case Z80_JPCC:
+ case Z80_JR:
+ case Z80_JRCC:
+ case Z80_DJNZ:
+ case Z80_CALL:
+ case Z80_CALLCC:
+ case Z80_RET:
+ case Z80_RETCC:
+ case Z80_RETI:
+ case Z80_RETN:
+ case Z80_RST:
+ case Z80_IN:
+ case Z80_INI:
+ case Z80_INIR:
+ case Z80_IND:
+ case Z80_INDR:
+ case Z80_OUT:
+ case Z80_OUTI:
+ case Z80_OTIR:
+ case Z80_OUTD:
+ case Z80_OTDR:*/
+ default:
+ fprintf(stderr, "unimplemented instruction: %d\n", inst->op);
+ exit(1);
+ }
+}
+
+void translate_z80_stream(z80_context * context, uint16_t address)
+{
+}
diff --git a/z80_to_x86.h b/z80_to_x86.h
new file mode 100644
index 0000000..dbea50e
--- /dev/null
+++ b/z80_to_x86.h
@@ -0,0 +1,39 @@
+#ifndef Z80_TO_X86_H_
+#define Z80_TO_X86_H_
+#include "z80inst.h"
+#include "x86_backend.h"
+
+#define ZNUM_MEM_AREAS 4
+
+enum {
+ ZF_C = 0,
+ ZF_N,
+ ZF_PV,
+ ZF_H,
+ ZF_Z,
+ ZF_S,
+ ZF_NUM
+};
+
+typedef struct {
+ uint32_t flags;
+ int8_t regs[Z80_UNUSED];
+} x86_z80_options;
+
+typedef struct {
+ void * native_pc;
+ uint16_t sp;
+ uint8_t flags[ZF_NUM];
+ uint16_t bank_reg;
+ uint8_t regs[Z80_A+1];
+ uint8_t alt_regs[Z80_A+1];
+ uint8_t * mem_pointers[ZNUM_MEM_AREAS];
+ native_map_slot * native_code_map;
+ void * options
+ void * next_context;
+} z80_context;
+
+void translate_z80_stream(z80_context * context, uint16_t address);
+
+#endif //Z80_TO_X86_H_
+
diff --git a/z80inst.c b/z80inst.c
index 4a326a2..ce936c6 100644
--- a/z80inst.c
+++ b/z80inst.c
@@ -1118,7 +1118,9 @@ z80inst z80_tbl_iy[256] = {
NOP2,
NOP2,
NOP2,
- NOP2
+ //TODO: Enable this based on a define
+ {Z80_NOP, Z80_UNUSED, Z80_UNUSED, Z80_UNUSED, 42}
+ //NOP2
};
#define SHIFT_BLOCK_IY(op) \
@@ -1342,14 +1344,13 @@ char * z80_regs[Z80_USE_IMMED] = {
"e",
"h",
"l",
- "",
- "a",
"ixh",
"ixl",
"iyh",
"iyl",
"i",
"r",
+ "a",
"bc",
"de",
"hl",
diff --git a/z80inst.h b/z80inst.h
index 67c41d5..fc7b2c1 100644
--- a/z80inst.h
+++ b/z80inst.h
@@ -78,13 +78,13 @@ enum {
Z80_E,
Z80_H,
Z80_L,
- Z80_A=7,
Z80_IXH,
Z80_IXL,
Z80_IYH,
Z80_IYL,
Z80_I,
Z80_R,
+ Z80_A,
Z80_BC,
Z80_DE,
Z80_HL,