# UNDF: UNDF-2026-000001054 # UNDF: UNDF-2026-XXXXXXXXX --- a/Core/debugger.c +++ b/Core/debugger.c @@ -2401,13 +2401,26 @@ static void test_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t flags, uint static void test_watchpoint(GB_gameboy_t *gb, uint16_t addr, uint8_t flags, uint8_t value) { if (unlikely(gb->backstep_instructions)) return; + /* O(1) fast-path: bail immediately if no watchpoint covers this address+flags */ + if (!(gb->watchpoint_address_flags[addr] & flags)) return; uint16_t bank = bank_for_addr(gb, addr); for (unsigned i = 0; i < gb->n_watchpoints; i++) { struct GB_watchpoint_s *watchpoint = &gb->watchpoints[i]; if (watchpoint->bank != (uint16_t)-1) { if (watchpoint->bank != bank) continue; } if (!(watchpoint->flags & flags)) continue; if (addr < watchpoint->addr) continue; if (addr > (uint32_t)watchpoint->addr + watchpoint->length + watchpoint->inclusive) continue; if (!watchpoint->condition) { condition_ok: GB_debugger_break(gb); --- a/Core/gb.h +++ b/Core/gb.h @@ -768,6 +768,8 @@ struct GB_gameboy_internal_s { uint16_t n_watchpoints; struct GB_watchpoint_s *watchpoints; + /* Per-address flags OR'd across all watchpoints covering that address (READ|WRITE). + Allows O(1) early-exit in GB_read_memory / GB_write_memory hot path. */ + uint8_t watchpoint_address_flags[0x10000]; --- a/Core/debugger.c (watchpoint add) +++ b/Core/debugger.c (watchpoint add) @@ -1290,6 +1290,12 @@ static bool watch(GB_gameboy_t *gb, char *arguments, char *modifiers, const debu gb->watchpoints[gb->n_watchpoints++] = (struct GB_watchpoint_s){ .id = id, .key = key, .condition = condition? strdup(condition) : NULL, .flags = flags, .length = length, .inclusive = inclusive, }; + /* Update O(1) lookup table for addresses covered by this watchpoint */ + for (uint32_t a = result.value; a <= (uint32_t)result.value + length + inclusive; a++) { + gb->watchpoint_address_flags[(uint16_t)a] |= flags; + } --- a/Core/debugger.c (watchpoint delete/rebuild) +++ b/Core/debugger.c (watchpoint delete/rebuild) @@ rebuild watchpoint_address_flags after any removal +static void rebuild_watchpoint_flags(GB_gameboy_t *gb) +{ + memset(gb->watchpoint_address_flags, 0, sizeof(gb->watchpoint_address_flags)); + for (unsigned i = 0; i < gb->n_watchpoints; i++) { + struct GB_watchpoint_s *wp = &gb->watchpoints[i]; + for (uint32_t a = wp->addr; a <= (uint32_t)wp->addr + wp->length + wp->inclusive; a++) { + gb->watchpoint_address_flags[(uint16_t)a] |= wp->flags; + } + } +}