Mercurial > repos > blastem
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 |