comparison z80_to_x86.c @ 626:7c46891a29b1

Properly handle Z80 breakpoints on self-modifying code and setting Z80 breakpoints before the Z80 program has been loaded
author Michael Pavone <pavone@retrodev.com>
date Thu, 19 Jun 2014 19:50:16 -0700
parents 6aa2a8ab9c70
children c5820734a5b6
comparison
equal deleted inserted replaced
625:6aa2a8ab9c70 626:7c46891a29b1
42 void z80_io_write(); 42 void z80_io_write();
43 void z80_halt(); 43 void z80_halt();
44 void z80_save_context(); 44 void z80_save_context();
45 void z80_load_context(); 45 void z80_load_context();
46 46
47 uint8_t * zbreakpoint_patch(z80_context * context, uint16_t address, uint8_t * native);
48
47 uint8_t z80_size(z80inst * inst) 49 uint8_t z80_size(z80inst * inst)
48 { 50 {
49 uint8_t reg = (inst->reg & 0x1F); 51 uint8_t reg = (inst->reg & 0x1F);
50 if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) { 52 if (reg != Z80_UNUSED && reg != Z80_USE_IMMED) {
51 return reg < Z80_BC ? SZ_B : SZ_W; 53 return reg < Z80_BC ? SZ_B : SZ_W;
332 x86_ea src_op, dst_op; 334 x86_ea src_op, dst_op;
333 uint8_t size; 335 uint8_t size;
334 x86_z80_options *opts = context->options; 336 x86_z80_options *opts = context->options;
335 uint8_t * start = dst; 337 uint8_t * start = dst;
336 dst = z80_check_cycles_int(dst, address); 338 dst = z80_check_cycles_int(dst, address);
339 if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) {
340 zbreakpoint_patch(context, address, start);
341 }
337 switch(inst->op) 342 switch(inst->op)
338 { 343 {
339 case Z80_LD: 344 case Z80_LD:
340 size = z80_size(inst); 345 size = z80_size(inst);
341 switch (inst->addr_mode & 0x1F) 346 switch (inst->addr_mode & 0x1F)
1973 context->iff1 = context->iff2 = 0; 1978 context->iff1 = context->iff2 = 0;
1974 context->native_pc = z80_get_native_address_trans(context, 0); 1979 context->native_pc = z80_get_native_address_trans(context, 0);
1975 context->extra_pc = NULL; 1980 context->extra_pc = NULL;
1976 } 1981 }
1977 1982
1983 uint8_t * zbreakpoint_patch(z80_context * context, uint16_t address, uint8_t * native)
1984 {
1985 native = mov_ir(native, address, SCRATCH1, SZ_W);
1986 native = call(native, context->bp_stub);
1987 return native;
1988 }
1989
1990 void zcreate_stub(z80_context * context)
1991 {
1992 x86_z80_options * opts = context->options;
1993 uint8_t * dst = opts->cur_code;
1994 uint8_t * dst_end = opts->code_end;
1995 if (dst_end - dst < 128) {
1996 size_t size = 1024*1024;
1997 dst = alloc_code(&size);
1998 opts->code_end = dst_end = dst + size;
1999 }
2000 context->bp_stub = dst;
2001
2002 //Calculate length of prologue
2003 int check_int_size = z80_check_cycles_int(dst, 0) - dst;
2004
2005 //Calculate length of patch
2006 int patch_size = zbreakpoint_patch(context, 0, dst) - dst;
2007
2008 //Save context and call breakpoint handler
2009 dst = call(dst, (uint8_t *)z80_save_context);
2010 dst = push_r(dst, SCRATCH1);
2011 dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
2012 dst = mov_rr(dst, SCRATCH1, RSI, SZ_W);
2013 dst = call(dst, context->bp_handler);
2014 dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
2015 //Restore context
2016 dst = call(dst, (uint8_t *)z80_load_context);
2017 dst = pop_r(dst, SCRATCH1);
2018 //do prologue stuff
2019 dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D);
2020 uint8_t * jmp_off = dst+1;
2021 dst = jcc(dst, CC_NC, dst + 7);
2022 dst = pop_r(dst, SCRATCH1);
2023 dst = add_ir(dst, check_int_size - patch_size, SCRATCH1, SZ_Q);
2024 dst = push_r(dst, SCRATCH1);
2025 dst = jmp(dst, (uint8_t *)z80_handle_cycle_limit_int);
2026 *jmp_off = dst - (jmp_off+1);
2027 //jump back to body of translated instruction
2028 dst = pop_r(dst, SCRATCH1);
2029 dst = add_ir(dst, check_int_size - patch_size, SCRATCH1, SZ_Q);
2030 dst = jmp_r(dst, SCRATCH1);
2031 opts->cur_code = dst;
2032 }
2033
1978 void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler) 2034 void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler)
1979 { 2035 {
1980 static uint8_t * bp_stub = NULL; 2036 context->bp_handler = bp_handler;
1981 uint8_t * native = z80_get_native_address_trans(context, address); 2037 uint8_t bit = 1 << (address % sizeof(uint8_t));
1982 uint8_t * start_native = native; 2038 if (!(bit & context->breakpoint_flags[address / sizeof(uint8_t)])) {
1983 native = mov_ir(native, address, SCRATCH1, SZ_W); 2039 context->breakpoint_flags[address / sizeof(uint8_t)] |= bit;
1984 if (!bp_stub) { 2040 if (!context->bp_stub) {
1985 x86_z80_options * opts = context->options; 2041 zcreate_stub(context);
1986 uint8_t * dst = opts->cur_code; 2042 }
1987 uint8_t * dst_end = opts->code_end; 2043 uint8_t * native = z80_get_native_address(context, address);
1988 if (dst_end - dst < 128) { 2044 if (native) {
1989 size_t size = 1024*1024; 2045 zbreakpoint_patch(context, address, native);
1990 dst = alloc_code(&size); 2046 }
1991 opts->code_end = dst_end = dst + size;
1992 }
1993 bp_stub = dst;
1994 native = call(native, bp_stub);
1995
1996 //Calculate length of prologue
1997 dst = z80_check_cycles_int(dst, address);
1998 int check_int_size = dst-bp_stub;
1999 dst = bp_stub;
2000
2001 //Save context and call breakpoint handler
2002 dst = call(dst, (uint8_t *)z80_save_context);
2003 dst = push_r(dst, SCRATCH1);
2004 dst = mov_rr(dst, CONTEXT, RDI, SZ_Q);
2005 dst = mov_rr(dst, SCRATCH1, RSI, SZ_W);
2006 dst = call(dst, bp_handler);
2007 dst = mov_rr(dst, RAX, CONTEXT, SZ_Q);
2008 //Restore context
2009 dst = call(dst, (uint8_t *)z80_load_context);
2010 dst = pop_r(dst, SCRATCH1);
2011 //do prologue stuff
2012 dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D);
2013 uint8_t * jmp_off = dst+1;
2014 dst = jcc(dst, CC_NC, dst + 7);
2015 dst = pop_r(dst, SCRATCH1);
2016 dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q);
2017 dst = push_r(dst, SCRATCH1);
2018 dst = jmp(dst, (uint8_t *)z80_handle_cycle_limit_int);
2019 *jmp_off = dst - (jmp_off+1);
2020 //jump back to body of translated instruction
2021 dst = pop_r(dst, SCRATCH1);
2022 dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q);
2023 dst = jmp_r(dst, SCRATCH1);
2024 opts->cur_code = dst;
2025 } else {
2026 native = call(native, bp_stub);
2027 } 2047 }
2028 } 2048 }
2029 2049
2030 void zremove_breakpoint(z80_context * context, uint16_t address) 2050 void zremove_breakpoint(z80_context * context, uint16_t address)
2031 { 2051 {
2052 context->breakpoint_flags[address / sizeof(uint8_t)] &= 1 << (address % sizeof(uint8_t));
2032 uint8_t * native = z80_get_native_address(context, address); 2053 uint8_t * native = z80_get_native_address(context, address);
2033 z80_check_cycles_int(native, address); 2054 if (native) {
2034 } 2055 z80_check_cycles_int(native, address);
2035 2056 }
2036 2057 }
2058
2059