summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2014-12-22 20:55:10 -0800
committerMichael Pavone <pavone@retrodev.com>2014-12-22 20:55:10 -0800
commit12c73dc400c1b6b61531df4ff0fd1efe4ef7ae12 (patch)
tree12f0b6e224aac2cadc0199e040a9f4dc579d920d
parent4cad512b6d7ac0f7042b90e1029626fb14788bf0 (diff)
Z80 core is sort of working again
-rw-r--r--Makefile2
-rw-r--r--backend.h2
-rw-r--r--backend_x86.c2
-rw-r--r--blastem.c2
-rw-r--r--gen_x86.c34
-rw-r--r--gen_x86.h3
-rw-r--r--z80_to_x86.c237
-rw-r--r--z80_to_x86.h23
-rw-r--r--ztestrun.c53
9 files changed, 228 insertions, 130 deletions
diff --git a/Makefile b/Makefile
index 61e8a19..272605d 100644
--- a/Makefile
+++ b/Makefile
@@ -38,7 +38,7 @@ NOZ80:=1
endif
endif
-Z80OBJS=z80inst.o z80_to_x86.o zruntime.o
+Z80OBJS=z80inst.o z80_to_x86.o
AUDIOOBJS=ym2612.o psg.o wave.o
CONFIGOBJS=config.o tern.o util.o
diff --git a/backend.h b/backend.h
index a228d13..131314c 100644
--- a/backend.h
+++ b/backend.h
@@ -109,7 +109,7 @@ void cycles(cpu_options *opts, uint32_t num);
void check_cycles_int(cpu_options *opts, uint32_t address);
void check_cycles(cpu_options * opts);
-code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc);
+code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc);
#endif //BACKEND_H_
diff --git a/backend_x86.c b/backend_x86.c
index 7f75761..6ba1a7a 100644
--- a/backend_x86.c
+++ b/backend_x86.c
@@ -28,7 +28,7 @@ void check_cycles(cpu_options * opts)
*jmp_off = code->cur - (jmp_off+1);
}
-code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc)
+code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc)
{
code_info *code = &opts->code;
code_ptr start = code->cur;
diff --git a/blastem.c b/blastem.c
index 2659fa4..c704ef2 100644
--- a/blastem.c
+++ b/blastem.c
@@ -198,7 +198,7 @@ void sync_z80(z80_context * z_context, uint32_t mclks)
}
z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle;
dprintf("Running Z80 from cycle %d to cycle %d. Native PC: %p\n", z_context->current_cycle, z_context->sync_cycle, z_context->native_pc);
- z80_run(z_context);
+ z_context->run(z_context);
dprintf("Z80 ran to cycle %d\n", z_context->current_cycle);
}
}
diff --git a/gen_x86.c b/gen_x86.c
index ccc03eb..b1b48d4 100644
--- a/gen_x86.c
+++ b/gen_x86.c
@@ -33,6 +33,7 @@
#define OP_TEST 0x84
#define OP_XCHG 0x86
#define OP_MOV 0x88
+#define PRE_XOP 0x8F
#define OP_XCHG_AX 0x90
#define OP_CDQ 0x99
#define OP_PUSHF 0x9C
@@ -1516,6 +1517,13 @@ void push_r(code_info *code, uint8_t reg)
code->cur = out;
}
+void push_rdisp(code_info *code, uint8_t base, int32_t disp)
+{
+ //This instruction has no explicit size, so we pass SZ_B
+ //to avoid any prefixes or bits being set
+ x86_rdisp_size(code, OP_SINGLE_EA, OP_EX_PUSH_EA, base, disp, SZ_B);
+}
+
void pop_r(code_info *code, uint8_t reg)
{
check_alloc_code(code, 2);
@@ -1528,6 +1536,19 @@ void pop_r(code_info *code, uint8_t reg)
code->cur = out;
}
+void pop_rind(code_info *code, uint8_t reg)
+{
+ check_alloc_code(code, 3);
+ code_ptr out = code->cur;
+ if (reg >= R8) {
+ *(out++) = PRE_REX | REX_RM_FIELD;
+ reg -= R8 - X86_R8;
+ }
+ *(out++) = PRE_XOP;
+ *(out++) = MODE_REG_INDIRECT | reg;
+ code->cur = out;
+}
+
void setcc_r(code_info *code, uint8_t cc, uint8_t dst)
{
check_alloc_code(code, 4);
@@ -1855,6 +1876,19 @@ void jmp_r(code_info *code, uint8_t dst)
code->cur = out;
}
+void jmp_rind(code_info *code, uint8_t dst)
+{
+ check_alloc_code(code, 3);
+ code_ptr out = code->cur;
+ if (dst >= R8) {
+ dst -= R8 - X86_R8;
+ *(out++) = PRE_REX | REX_RM_FIELD;
+ }
+ *(out++) = OP_SINGLE_EA;
+ *(out++) = MODE_REG_INDIRECT | dst | (OP_EX_JMP_EA << 3);
+ code->cur = out;
+}
+
void call(code_info *code, code_ptr fun)
{
check_alloc_code(code, 5);
diff --git a/gen_x86.h b/gen_x86.h
index 07eae3a..583808b 100644
--- a/gen_x86.h
+++ b/gen_x86.h
@@ -187,7 +187,9 @@ void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size);
void pushf(code_info *code);
void popf(code_info *code);
void push_r(code_info *code, uint8_t reg);
+void push_rdisp(code_info *code, uint8_t base, int32_t disp);
void pop_r(code_info *code, uint8_t reg);
+void pop_rind(code_info *code, uint8_t reg);
void setcc_r(code_info *code, uint8_t cc, uint8_t dst);
void setcc_rind(code_info *code, uint8_t cc, uint8_t dst);
void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp);
@@ -208,6 +210,7 @@ void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp
void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size);
void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size);
void jcc(code_info *code, uint8_t cc, code_ptr dest);
+void jmp_rind(code_info *code, uint8_t dst);
void call_r(code_info *code, uint8_t dst);
void retn(code_info *code);
void cdq(code_info *code);
diff --git a/z80_to_x86.c b/z80_to_x86.c
index 6d5f928..b556b57 100644
--- a/z80_to_x86.c
+++ b/z80_to_x86.c
@@ -28,22 +28,6 @@
#define dprintf
#endif
-void z80_read_byte();
-void z80_read_word();
-void z80_write_byte();
-void z80_write_word_highfirst();
-void z80_write_word_lowfirst();
-void z80_save_context();
-void z80_native_addr();
-void z80_do_sync();
-void z80_handle_cycle_limit_int();
-void z80_retrans_stub();
-void z80_io_read();
-void z80_io_write();
-void z80_halt();
-void z80_save_context();
-void z80_load_context();
-
uint8_t z80_size(z80inst * inst)
{
uint8_t reg = (inst->reg & 0x1F);
@@ -184,9 +168,9 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t
push_r(code, opts->gen.scratch1);
}*/
if (size == SZ_B) {
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
} else {
- call(code, (uint8_t *)z80_read_word);
+ call(code, opts->read_16);
}
if (modify) {
//pop_r(code, opts->gen.scratch2);
@@ -207,9 +191,9 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t
mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W);
}
if (size == SZ_B) {
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
} else {
- call(code, (uint8_t *)z80_read_word);
+ call(code, opts->read_16);
}
if (modify) {
//pop_r(code, opts->gen.scratch2);
@@ -248,7 +232,7 @@ void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts)
}
}
-void z80_save_result(code_info *code, z80inst * inst)
+void z80_save_result(z80_options *opts, z80inst * inst)
{
switch(inst->addr_mode & 0x1f)
{
@@ -257,9 +241,9 @@ void z80_save_result(code_info *code, z80inst * inst)
case Z80_IX_DISPLACE:
case Z80_IY_DISPLACE:
if (z80_size(inst) == SZ_B) {
- call(code, (uint8_t *)z80_write_byte);
+ call(&opts->gen.code, opts->write_8);
} else {
- call(code, (uint8_t *)z80_write_word_lowfirst);
+ call(&opts->gen.code, opts->write_16_lowfirst);
}
}
}
@@ -369,7 +353,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
z80_save_reg(inst, opts);
z80_save_ea(code, inst, opts);
if (inst->addr_mode & Z80_DIR) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
}
break;
case Z80_PUSH:
@@ -394,14 +378,14 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W);
}
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_word_highfirst);
+ call(code, opts->write_16_highfirst);
//no call to save_z80_reg needed since there's no chance we'll use the only
//the upper half of a register pair
break;
case Z80_POP:
cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_word);
+ call(code, opts->read_16);
add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
if (inst->reg == Z80_AF) {
@@ -452,10 +436,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
}
} else {
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_byte);
+ call(code, opts->write_8);
cycles(&opts->gen, 1);
uint8_t high_reg = z80_high_reg(inst->reg);
uint8_t use_reg;
@@ -466,11 +450,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
ror_ir(code, 8, use_reg, SZ_W);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
add_ir(code, 1, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
add_ir(code, 1, opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_byte);
+ call(code, opts->write_8);
//restore reg to normal rotation
ror_ir(code, 8, use_reg, SZ_W);
cycles(&opts->gen, 2);
@@ -491,9 +475,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
case Z80_LDI: {
cycles(&opts->gen, 8);
mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_byte);
+ call(code, opts->write_8);
cycles(&opts->gen, 2);
add_ir(code, 1, opts->regs[Z80_DE], SZ_W);
add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
@@ -506,9 +490,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
case Z80_LDIR: {
cycles(&opts->gen, 8);
mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_byte);
+ call(code, opts->write_8);
add_ir(code, 1, opts->regs[Z80_DE], SZ_W);
add_ir(code, 1, opts->regs[Z80_HL], SZ_W);
@@ -529,9 +513,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
case Z80_LDD: {
cycles(&opts->gen, 8);
mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_byte);
+ call(code, opts->write_8);
cycles(&opts->gen, 2);
sub_ir(code, 1, opts->regs[Z80_DE], SZ_W);
sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
@@ -544,9 +528,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
case Z80_LDDR: {
cycles(&opts->gen, 8);
mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_byte);
+ call(code, opts->write_8);
sub_ir(code, 1, opts->regs[Z80_DE], SZ_W);
sub_ir(code, 1, opts->regs[Z80_HL], SZ_W);
@@ -810,7 +794,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
}
z80_save_reg(inst, opts);
z80_save_ea(code, inst, opts);
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
break;
case Z80_DEC:
num_cycles = 4;
@@ -836,7 +820,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
}
z80_save_reg(inst, opts);
z80_save_ea(code, inst, opts);
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
break;
//case Z80_DAA:
case Z80_CPL:
@@ -869,20 +853,30 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
break;
case Z80_NOP:
if (inst->immed == 42) {
- call(code, (uint8_t *)z80_save_context);
+ call(code, opts->gen.save_context);
mov_rr(code, opts->gen.context_reg, RDI, SZ_Q);
jmp(code, (uint8_t *)z80_print_regs_exit);
} else {
cycles(&opts->gen, 4 * inst->immed);
}
break;
- case Z80_HALT:
+ case Z80_HALT: {
cycles(&opts->gen, 4);
mov_ir(code, address, opts->gen.scratch1, SZ_W);
uint8_t * call_inst = code->cur;
- call(code, (uint8_t *)z80_halt);
+ mov_rr(code, opts->gen.limit, opts->gen.scratch2, SZ_D);
+ sub_rr(code, opts->gen.cycles, opts->gen.scratch2, SZ_D);
+ and_ir(code, 0xFFFFFFFC, opts->gen.scratch2, SZ_D);
+ add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D);
+ cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D);
+ code_ptr skip_last = code->cur+1;
+ jcc(code, CC_B, opts->gen.handle_cycle_limit_int);
+ cycles(&opts->gen, 4);
+ *skip_last = code->cur - (skip_last+1);
+ call(code, opts->gen.handle_cycle_limit_int);
jmp(code, call_inst);
break;
+ }
case Z80_DI:
cycles(&opts->gen, 4);
mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
@@ -897,7 +891,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B);
//interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles
add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D);
- call(code, (uint8_t *)z80_do_sync);
+ call(code, opts->do_sync);
break;
case Z80_IM:
cycles(&opts->gen, 4);
@@ -926,7 +920,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
if (inst->addr_mode != Z80_UNUSED) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (src_op.mode != MODE_UNUSED) {
z80_save_reg(inst, opts);
}
@@ -958,7 +952,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
if (inst->addr_mode != Z80_UNUSED) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (src_op.mode != MODE_UNUSED) {
z80_save_reg(inst, opts);
}
@@ -989,7 +983,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
if (inst->addr_mode != Z80_UNUSED) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (src_op.mode != MODE_UNUSED) {
z80_save_reg(inst, opts);
}
@@ -1021,7 +1015,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
if (inst->addr_mode != Z80_UNUSED) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (src_op.mode != MODE_UNUSED) {
z80_save_reg(inst, opts);
}
@@ -1056,7 +1050,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
if (inst->addr_mode != Z80_UNUSED) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (src_op.mode != MODE_UNUSED) {
z80_save_reg(inst, opts);
}
@@ -1087,7 +1081,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
if (inst->addr_mode != Z80_UNUSED) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (src_op.mode != MODE_UNUSED) {
z80_save_reg(inst, opts);
}
@@ -1118,7 +1112,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z));
setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S));
if (inst->addr_mode != Z80_UNUSED) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (src_op.mode != MODE_UNUSED) {
z80_save_reg(inst, opts);
}
@@ -1129,7 +1123,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
case Z80_RLD:
cycles(&opts->gen, 8);
mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
//Before: (HL) = 0x12, A = 0x34
//After: (HL) = 0x24, A = 0x31
mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B);
@@ -1151,12 +1145,12 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
ror_ir(code, 8, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_write_byte);
+ call(code, opts->write_8);
break;
case Z80_RRD:
cycles(&opts->gen, 8);
mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_byte);
+ call(code, opts->read_8);
//Before: (HL) = 0x12, A = 0x34
//After: (HL) = 0x41, A = 0x32
movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W);
@@ -1181,7 +1175,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W);
ror_ir(code, 8, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_write_byte);
+ call(code, opts->write_8);
break;
case Z80_BIT: {
num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16;
@@ -1247,7 +1241,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
}
}
if ((inst->addr_mode & 0x1F) != Z80_REG) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (inst->reg != Z80_USE_IMMED) {
z80_save_reg(inst, opts);
}
@@ -1289,7 +1283,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
}
}
if (inst->addr_mode != Z80_REG) {
- z80_save_result(code, inst);
+ z80_save_result(opts, inst);
if (inst->reg != Z80_USE_IMMED) {
z80_save_reg(inst, opts);
}
@@ -1318,7 +1312,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
} else {
mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
}
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
}
break;
@@ -1363,7 +1357,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
jmp(code, call_dst);
} else {
mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
}
*no_jump_off = code->cur - (no_jump_off+1);
@@ -1382,7 +1376,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
jmp(code, call_dst);
} else {
mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
}
break;
@@ -1417,7 +1411,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
jmp(code, call_dst);
} else {
mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
}
*no_jump_off = code->cur - (no_jump_off+1);
@@ -1440,7 +1434,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
jmp(code, call_dst);
} else {
mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
}
*no_jump_off = code->cur - (no_jump_off+1);
@@ -1450,7 +1444,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
mov_ir(code, address + 3, opts->gen.scratch1, SZ_W);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
+ call(code, opts->write_16_highfirst);//T States: 3, 3
if (inst->immed < 0x4000) {
code_ptr call_dst = z80_get_native_address(context, inst->immed);
if (!call_dst) {
@@ -1461,7 +1455,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
jmp(code, call_dst);
} else {
mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
}
break;
@@ -1498,7 +1492,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
mov_ir(code, address + 3, opts->gen.scratch1, SZ_W);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
+ call(code, opts->write_16_highfirst);//T States: 3, 3
if (inst->immed < 0x4000) {
code_ptr call_dst = z80_get_native_address(context, inst->immed);
if (!call_dst) {
@@ -1509,7 +1503,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
jmp(code, call_dst);
} else {
mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
}
*no_call_off = code->cur - (no_call_off+1);
@@ -1517,9 +1511,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
case Z80_RET:
cycles(&opts->gen, 4);//T States: 4
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_word);//T STates: 3, 3
+ call(code, opts->read_16);//T STates: 3, 3
add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
break;
case Z80_RETCC: {
@@ -1551,9 +1545,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
uint8_t *no_call_off = code->cur+1;
jcc(code, cond, code->cur+2);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_word);//T STates: 3, 3
+ call(code, opts->read_16);//T STates: 3, 3
add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
*no_call_off = code->cur - (no_call_off+1);
break;
@@ -1562,9 +1556,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
//For some systems, this may need a callback for signalling interrupt routine completion
cycles(&opts->gen, 8);//T States: 4, 4
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
- call(code, (uint8_t *)z80_read_word);//T STates: 3, 3
+ call(code, opts->read_16);//T STates: 3, 3
add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
break;
case Z80_RETN:
@@ -1572,9 +1566,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W);
mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B);
- call(code, (uint8_t *)z80_read_word);//T STates: 3, 3
+ call(code, opts->read_16);//T STates: 3, 3
add_ir(code, 2, opts->regs[Z80_SP], SZ_W);
- call(code, (uint8_t *)z80_native_addr);
+ call(code, opts->native_addr);
jmp_r(code, opts->gen.scratch1);
break;
case Z80_RST: {
@@ -1583,7 +1577,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
sub_ir(code, 2, opts->regs[Z80_SP], SZ_W);
mov_ir(code, address + 1, opts->gen.scratch1, SZ_W);
mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W);
- call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3
+ call(code, opts->write_16_highfirst);//T States: 3, 3
code_ptr call_dst = z80_get_native_address(context, inst->immed);
if (!call_dst) {
opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1);
@@ -1600,7 +1594,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
} else {
mov_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B);
}
- call(code, (uint8_t *)z80_io_read);
+ call(code, opts->read_io);
translate_z80_reg(inst, &dst_op, opts);
mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B);
z80_save_reg(inst, opts);
@@ -1618,7 +1612,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address)
}
translate_z80_reg(inst, &src_op, opts);
mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B);
- call(code, (uint8_t *)z80_io_write);
+ call(code, opts->write_io);
z80_save_reg(inst, opts);
break;
/*case Z80_OUTI:
@@ -1737,7 +1731,7 @@ z80_context * z80_handle_code_write(uint32_t address, z80_context * context)
z80_options * opts = context->options;
dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address);
mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D);
- call(&code, (uint8_t *)z80_retrans_stub);
+ call(&code, opts->retrans_stub);
}
return context;
}
@@ -1959,8 +1953,9 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
int reg;
uint8_t size;
if (i < Z80_I) {
- int reg = i /2 + Z80_BC;
+ reg = i /2 + Z80_BC;
size = SZ_W;
+ i++;
} else {
reg = i;
@@ -1977,6 +1972,7 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D);
mov_rrdisp(code, options->bank_reg, options->gen.context_reg, offsetof(z80_context, bank_reg), SZ_W);
mov_rrdisp(code, options->bank_pointer, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, SZ_PTR);
+ retn(code);
options->load_context_scratch = code->cur;
mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W);
@@ -2005,6 +2001,18 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D);
mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, bank_reg), options->bank_reg, SZ_W);
mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, options->bank_pointer, SZ_PTR);
+ retn(code);
+
+ options->native_addr = code->cur;
+ call(code, options->gen.save_context);
+ push_r(code, options->gen.context_reg);
+ mov_rr(code, options->gen.context_reg, RDI, SZ_PTR);
+ movzx_rr(code, options->gen.scratch1, RSI, SZ_W, SZ_D);
+ call(code, (code_ptr)z80_get_native_address_trans);
+ mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
+ pop_r(code, options->gen.context_reg);
+ call(code, options->gen.load_context);
+ retn(code);
options->gen.handle_cycle_limit = code->cur;
cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D);
@@ -2065,8 +2073,70 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3
pop_r(code, options->gen.scratch2);
//TODO: Support interrupt mode 0 and 2
mov_ir(code, 0x38, options->gen.scratch1, SZ_W);
- call(code, (code_ptr)z80_native_addr);
+ call(code, options->native_addr);
+ jmp_r(code, options->gen.scratch1);
+ *skip_int = code->cur - (skip_int+1);
+ cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D);
+ code_ptr skip_sync = code->cur + 1;
+ jcc(code, CC_B, skip_sync);
+ options->do_sync = code->cur;
+ call(code, options->gen.save_context);
+ pop_rind(code, options->gen.context_reg);
+ //restore callee saved registers
+ pop_r(code, R15);
+ pop_r(code, R14);
+ pop_r(code, R13);
+ pop_r(code, R12);
+ pop_r(code, RBP);
+ pop_r(code, RBX);
+ //return to caller of z80_run
+ *skip_sync = code->cur - (skip_sync+1);
+ retn(code);
+
+ options->read_io = code->cur;
+ check_cycles(&options->gen);
+ cycles(&options->gen, 4);
+ //Genesis has no IO hardware and always returns FF
+ //eventually this should use a second memory map array
+ mov_ir(code, 0xFF, options->gen.scratch1, SZ_B);
+ retn(code);
+
+ options->write_io = code->cur;
+ check_cycles(&options->gen);
+ cycles(&options->gen, 4);
+ retn(code);
+
+ options->retrans_stub = code->cur;
+ //pop return address
+ pop_r(code, options->gen.scratch2);
+ call(code, options->gen.save_context);
+ //adjust pointer before move and call instructions that got us here
+ sub_ir(code, 11, options->gen.scratch2, SZ_PTR);
+ mov_rr(code, options->gen.scratch1, RDI, SZ_D);
+ mov_rr(code, options->gen.scratch2, RDX, SZ_PTR);
+ push_r(code, options->gen.context_reg);
+ call(code, (code_ptr)z80_retranslate_inst);
+ pop_r(code, options->gen.context_reg);
+ mov_rr(code, RAX, options->gen.scratch1, SZ_PTR);
+ call(code, options->gen.load_context);
jmp_r(code, options->gen.scratch1);
+
+ options->run = (z80_run_fun)code->cur;
+ //save callee save registers
+ push_r(code, RBX);
+ push_r(code, RBP);
+ push_r(code, R12);
+ push_r(code, R13);
+ push_r(code, R14);
+ push_r(code, R15);
+ mov_rr(code, RDI, options->gen.context_reg, SZ_PTR);
+ cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
+ code_ptr no_extra = code->cur+1;
+ jcc(code, CC_Z, no_extra);
+ push_rdisp(code, options->gen.context_reg, offsetof(z80_context, extra_pc));
+ mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR);
+ *no_extra = code->cur - (no_extra + 1);
+ jmp_rind(code, options->gen.context_reg);
}
void * z80_gen_bank_write(uint32_t start_address, void * voptions)
@@ -2086,6 +2156,7 @@ void init_z80_context(z80_context * context, z80_options * options)
context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9));
memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9));
context->options = options;
+ context->run = options->run;
}
void z80_reset(z80_context * context)
@@ -2115,14 +2186,14 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha
code->cur = bp_stub;
//Save context and call breakpoint handler
- call(code, (uint8_t *)z80_save_context);
+ call(code, opts->gen.save_context);
push_r(code, opts->gen.scratch1);
mov_rr(code, opts->gen.context_reg, RDI, SZ_Q);
mov_rr(code, opts->gen.scratch1, RSI, SZ_W);
call(code, bp_handler);
mov_rr(code, RAX, opts->gen.context_reg, SZ_Q);
//Restore context
- call(code, (uint8_t *)z80_load_context);
+ call(code, opts->gen.load_context);
pop_r(code, opts->gen.scratch1);
//do prologue stuff
cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D);
@@ -2131,7 +2202,7 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha
pop_r(code, opts->gen.scratch1);
add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q);
push_r(code, opts->gen.scratch1);
- jmp(code, (uint8_t *)z80_handle_cycle_limit_int);
+ jmp(code, opts->gen.handle_cycle_limit_int);
*jmp_off = code->cur - (jmp_off+1);
//jump back to body of translated instruction
pop_r(code, opts->gen.scratch1);
diff --git a/z80_to_x86.h b/z80_to_x86.h
index d5d232c..6870343 100644
--- a/z80_to_x86.h
+++ b/z80_to_x86.h
@@ -21,21 +21,29 @@ enum {
ZF_NUM
};
+typedef void (*z80_run_fun)(void * context);
+
typedef struct {
cpu_options gen;
code_ptr save_context_scratch;
code_ptr load_context_scratch;
- code_ptr read_8;
- code_ptr write_8;
+ code_ptr native_addr;
+ code_ptr retrans_stub;
+ code_ptr do_sync;
+ code_ptr read_8;
+ code_ptr write_8;
code_ptr write_8_noinc;
- code_ptr read_16;
- code_ptr write_16_highfirst;
- code_ptr write_16_lowfirst;
+ code_ptr read_16;
+ code_ptr write_16_highfirst;
+ code_ptr write_16_lowfirst;
+ code_ptr read_io;
+ code_ptr write_io;
uint32_t flags;
int8_t regs[Z80_UNUSED];
- int8_t bank_reg;
- int8_t bank_pointer;
+ int8_t bank_reg;
+ int8_t bank_pointer;
+ z80_run_fun run;
} z80_options;
typedef struct {
@@ -63,6 +71,7 @@ typedef struct {
void * system;
uint8_t ram_code_flags[(8 * 1024)/128/8];
uint32_t int_enable_cycle;
+ z80_run_fun run;
uint16_t pc;
} z80_context;
diff --git a/ztestrun.c b/ztestrun.c
index 9f500f1..781afa9 100644
--- a/ztestrun.c
+++ b/ztestrun.c
@@ -1,6 +1,6 @@
/*
Copyright 2013 Michael Pavone
- This file is part of BlastEm.
+ 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 "z80inst.h"
@@ -11,7 +11,6 @@
#include <stdlib.h>
uint8_t z80_ram[0x2000];
-uint16_t cart[0x200000];
#define MCLKS_PER_Z80 15
//TODO: Figure out the exact value for this
@@ -19,26 +18,26 @@ uint16_t cart[0x200000];
#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80)
#define CYCLE_NEVER 0xFFFFFFFF
-uint8_t z80_read_ym(uint16_t location, z80_context * context)
+uint8_t z80_unmapped_read(uint32_t location, void * context)
{
return 0xFF;
}
-z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value)
+void * z80_unmapped_write(uint32_t location, void * context, uint8_t value)
{
return context;
}
-z80_context * z80_vdp_port_write(uint16_t location, z80_context * context, uint8_t value)
-{
- return context;
-}
+const memmap_chunk z80_map[] = {
+ { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL },
+ { 0x4000, 0x10000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE, NULL, NULL, NULL, z80_unmapped_read, z80_unmapped_write}
+};
int main(int argc, char ** argv)
{
long filesize;
uint8_t *filebuf;
- x86_z80_options opts;
+ z80_options opts;
z80_context context;
if (argc < 2) {
fputs("usage: transz80 zrom [cartrom]\n", stderr);
@@ -54,47 +53,29 @@ int main(int argc, char ** argv)
fseek(f, 0, SEEK_SET);
fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f);
fclose(f);
- if (argc > 2) {
- f = fopen(argv[2], "rb");
- if (!f) {
- fprintf(stderr, "unable to open file %s\n", argv[2]);
- exit(1);
- }
- fseek(f, 0, SEEK_END);
- filesize = ftell(f);
- fseek(f, 0, SEEK_SET);
- fread(cart, 1, filesize < sizeof(cart) ? filesize : sizeof(cart), f);
- fclose(f);
- for(unsigned short * cur = cart; cur - cart < (filesize/2); ++cur)
- {
- *cur = (*cur >> 8) | (*cur << 8);
- }
- }
- init_x86_z80_opts(&opts);
+ init_x86_z80_opts(&opts, z80_map, 2);
init_z80_context(&context, &opts);
//Z80 RAM
context.mem_pointers[0] = z80_ram;
context.sync_cycle = context.target_cycle = 1000;
context.int_cycle = CYCLE_NEVER;
- //cartridge/bank
- context.mem_pointers[1] = context.mem_pointers[2] = (uint8_t *)cart;
z80_reset(&context);
while (context.current_cycle < 1000) {
- z80_run(&context);
+ context.run(&context);
}
- printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n",
+ printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n",
context.regs[Z80_A], context.regs[Z80_B], context.regs[Z80_C],
- context.regs[Z80_D], context.regs[Z80_E],
- (context.regs[Z80_H] << 8) | context.regs[Z80_L],
- (context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL],
- (context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL],
+ context.regs[Z80_D], context.regs[Z80_E],
+ (context.regs[Z80_H] << 8) | context.regs[Z80_L],
+ (context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL],
+ (context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL],
context.sp, context.im, context.iff1, context.iff2);
printf("Flags: SZVNC\n"
" %d%d%d%d%d\n", context.flags[ZF_S], context.flags[ZF_Z], context.flags[ZF_PV], context.flags[ZF_N], context.flags[ZF_C]);
puts("--Alternate Regs--");
- printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n",
+ printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n",
context.alt_regs[Z80_A], context.alt_regs[Z80_B], context.alt_regs[Z80_C],
- context.alt_regs[Z80_D], context.alt_regs[Z80_E],
+ context.alt_regs[Z80_D], context.alt_regs[Z80_E],
(context.alt_regs[Z80_H] << 8) | context.alt_regs[Z80_L]);
return 0;
}