Mercurial > repos > blastem
diff m68k_core.c @ 2396:bf4f1a8d1d48
Implement 68K watchpoints in internal debugger
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 23 Dec 2023 17:37:57 -0800 |
parents | 66b3f2eda0c8 |
children | 68eba54b60f7 |
line wrap: on
line diff
--- a/m68k_core.c Wed Dec 13 20:09:18 2023 -0800 +++ b/m68k_core.c Sat Dec 23 17:37:57 2023 -0800 @@ -835,6 +835,133 @@ return context; } +static m68k_watchpoint *m68k_find_watchpoint(uint32_t address, m68k_context *context) +{ + for (uint32_t i = 0; i < context->num_watchpoints; i++) + { + if (address >= context->watchpoints[i].start && address < context->watchpoints[i].end) { + return context->watchpoints + i; + } + } + return NULL; +} + +static void *m68k_watchpoint_check16(uint32_t address, void *vcontext, uint16_t value) +{ + m68k_context *context = vcontext; + m68k_watchpoint *watch = m68k_find_watchpoint(address, context); + if (!watch) { + return vcontext; + } + if (watch->check_change) { + uint16_t old = read_word(address, (void **)context->mem_pointers, &context->options->gen, context); + if (old == value) { + return vcontext; + } + context->wp_old_value = old; + } else { + context->wp_old_value = value; + } + context->wp_hit_address = address; + context->wp_hit_value = value; + context->wp_hit = 1; + context->target_cycle = context->sync_cycle = context->current_cycle; + system_header *system = context->system; + system->enter_debugger = 1; + return vcontext; +} + +static void *m68k_watchpoint_check8(uint32_t address, void *vcontext, uint8_t value) +{ + m68k_context *context = vcontext; + m68k_watchpoint *watch = m68k_find_watchpoint(address, context); + if (!watch) { + return vcontext; + } + if (watch->check_change) { + uint8_t old = read_byte(address, (void **)context->mem_pointers, &context->options->gen, context); + if (old == value) { + return vcontext; + } + context->wp_old_value = old; + } else { + context->wp_old_value = value; + } + context->wp_hit_address = address; + context->wp_hit_value = value; + context->wp_hit = 1; + context->target_cycle = context->sync_cycle = context->current_cycle; + system_header *system = context->system; + system->enter_debugger = 1; + return vcontext; +} + +static void m68k_enable_watchpoints(m68k_context *context) +{ + if (context->options->gen.check_watchpoints_16) { + //already enabled + return; + } + context->options->gen.check_watchpoints_16 = m68k_watchpoint_check16; + context->options->gen.check_watchpoints_8 = m68k_watchpoint_check8; + //re-generate write handlers with watchpoints enabled + code_ptr new_write16 = gen_mem_fun(&context->options->gen, context->options->gen.memmap, context->options->gen.memmap_chunks, WRITE_16, NULL); + code_ptr new_write8 = gen_mem_fun(&context->options->gen, context->options->gen.memmap, context->options->gen.memmap_chunks, WRITE_8, NULL); + + //patch old write handlers to point to the new ones + code_info code = { + .cur = context->options->write_16, + .last = context->options->write_16 + 256 + }; + jmp(&code, new_write16); + code.cur = context->options->write_8; + code.last = code.cur + 256; + jmp(&code, new_write8); + context->options->write_16 = new_write16; + context->options->write_8 = new_write8; +} + +void m68k_add_watchpoint(m68k_context *context, uint32_t address, uint32_t size) +{ + uint32_t end = address + size; + for (uint32_t i = 0; i < context->num_watchpoints; i++) + { + if (context->watchpoints[i].start == address && context->watchpoints[i].end == end) { + return; + } + } + m68k_enable_watchpoints(context); + if (context->wp_storage == context->num_watchpoints) { + context->wp_storage = context->wp_storage ? context->wp_storage * 2 : 4; + context->watchpoints = realloc(context->watchpoints, context->wp_storage * sizeof(m68k_breakpoint)); + } + const memmap_chunk *chunk = find_map_chunk(address, &context->options->gen, 0, NULL); + context->watchpoints[context->num_watchpoints++] = (m68k_watchpoint){ + .start = address, + .end = end, + .check_change = chunk && (chunk->flags & MMAP_READ) + }; + if (context->watchpoint_min > address) { + context->watchpoint_min = address; + } + if (context->watchpoint_max < address + size) { + context->watchpoint_max = address + size; + } +} + +void m68k_remove_watchpoint(m68k_context *context, uint32_t address, uint32_t size) +{ + uint32_t end = address + size; + for (uint32_t i = 0; i < context->num_watchpoints; i++) + { + if (context->watchpoints[i].start == address && context->watchpoints[i].end == end) { + context->watchpoints[i] = context->watchpoints[context->num_watchpoints-1]; + context->num_watchpoints--; + return; + } + } +} + typedef enum { RAW_FUNC = 1, BINARY_ARITH,