comparison z80_to_x86.c @ 2400:c97609fe8315

Implement watchpoints in Z80 debugger
author Michael Pavone <pavone@retrodev.com>
date Sat, 23 Dec 2023 23:03:31 -0800
parents 3e591869d135
children ed7b4d869989
comparison
equal deleted inserted replaced
2399:68eba54b60f7 2400:c97609fe8315
3199 options->gen.address_size = SZ_W; 3199 options->gen.address_size = SZ_W;
3200 options->gen.address_mask = 0xFFFF; 3200 options->gen.address_mask = 0xFFFF;
3201 options->gen.max_address = 0x10000; 3201 options->gen.max_address = 0x10000;
3202 options->gen.bus_cycles = 3; 3202 options->gen.bus_cycles = 3;
3203 options->gen.clock_divider = clock_divider; 3203 options->gen.clock_divider = clock_divider;
3204 options->gen.watchpoint_range_off = offsetof(z80_context, watchpoint_min);
3204 options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers); 3205 options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers);
3205 options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags); 3206 options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags);
3206 options->gen.ram_flags_shift = 7; 3207 options->gen.ram_flags_shift = 7;
3207 3208
3208 options->flags = 0; 3209 options->flags = 0;
3864 if (native) { 3865 if (native) {
3865 zbreakpoint_patch(context, address, native); 3866 zbreakpoint_patch(context, address, native);
3866 } 3867 }
3867 } 3868 }
3868 } 3869 }
3869
3870 void zremove_breakpoint(z80_context * context, uint16_t address) 3870 void zremove_breakpoint(z80_context * context, uint16_t address)
3871 { 3871 {
3872 context->breakpoint_flags[address / 8] &= ~(1 << (address % 8)); 3872 context->breakpoint_flags[address / 8] &= ~(1 << (address % 8));
3873 uint8_t * native = z80_get_native_address(context, address); 3873 uint8_t * native = z80_get_native_address(context, address);
3874 if (native) { 3874 if (native) {
3876 code_info tmp_code = opts->gen.code; 3876 code_info tmp_code = opts->gen.code;
3877 opts->gen.code.cur = native; 3877 opts->gen.code.cur = native;
3878 opts->gen.code.last = native + 128; 3878 opts->gen.code.last = native + 128;
3879 check_cycles_int(&opts->gen, address); 3879 check_cycles_int(&opts->gen, address);
3880 opts->gen.code = tmp_code; 3880 opts->gen.code = tmp_code;
3881 }
3882 }
3883
3884 static void *z80_watchpoint_check(uint32_t address, void *vcontext, uint8_t value)
3885 {
3886 z80_context *context = vcontext;
3887 z80_watchpoint *watch = NULL;
3888 address &= 0xFFFF;
3889 for (uint32_t i = 0; i < context->num_watchpoints; i++)
3890 {
3891 if (address >= context->watchpoints[i].start && address <= context->watchpoints[i].end) {
3892 watch = context->watchpoints + i;
3893 break;
3894 }
3895 }
3896 if (!watch) {
3897 return vcontext;
3898 }
3899 if (watch->check_change) {
3900 uint8_t old = read_byte(address, (void **)context->mem_pointers, &context->options->gen, context);
3901 if (old == value) {
3902 return vcontext;
3903 }
3904 context->wp_old_value = old;
3905 } else {
3906 context->wp_old_value = value;
3907 }
3908 context->wp_hit_address = address;
3909 context->wp_hit_value = value;
3910 context->wp_hit = 1;
3911 context->target_cycle = context->sync_cycle = context->current_cycle;
3912 system_header *system = context->system;
3913 system->enter_debugger = 1;
3914 return vcontext;
3915 }
3916
3917 static void z80_enable_watchpoints(z80_context *context)
3918 {
3919 if (context->options->gen.check_watchpoints_8) {
3920 //already enabled
3921 return;
3922 }
3923 context->watchpoint_min = 0xFFFF;
3924 context->watchpoint_max = 0;
3925 context->options->gen.check_watchpoints_8 = z80_watchpoint_check;
3926 //re-generate write handlers with watchpoints enabled
3927 code_ptr new_write8 = gen_mem_fun(&context->options->gen, context->options->gen.memmap, context->options->gen.memmap_chunks, WRITE_8, NULL);
3928
3929 //patch old write handlers to point to the new ones
3930 code_info code = {
3931 .cur = context->options->write_8,
3932 .last = context->options->write_8 + 256
3933 };
3934 jmp(&code, new_write8);
3935 context->options->write_8 = new_write8;
3936 }
3937
3938 void z80_add_watchpoint(z80_context *context, uint16_t address, uint16_t size)
3939 {
3940 uint32_t end = address + size - 1;
3941 for (uint32_t i = 0; i < context->num_watchpoints; i++)
3942 {
3943 if (context->watchpoints[i].start == address && context->watchpoints[i].end == end) {
3944 return;
3945 }
3946 }
3947 z80_enable_watchpoints(context);
3948 if (context->wp_storage == context->num_watchpoints) {
3949 context->wp_storage = context->wp_storage ? context->wp_storage * 2 : 4;
3950 context->watchpoints = realloc(context->watchpoints, context->wp_storage * sizeof(z80_watchpoint));
3951 }
3952 const memmap_chunk *chunk = find_map_chunk(address, &context->options->gen, 0, NULL);
3953 context->watchpoints[context->num_watchpoints++] = (z80_watchpoint){
3954 .start = address,
3955 .end = end,
3956 .check_change = chunk && (chunk->flags & MMAP_READ)
3957 };
3958 if (context->watchpoint_min > address) {
3959 context->watchpoint_min = address;
3960 }
3961 if (context->watchpoint_max < end) {
3962 context->watchpoint_max = end;
3963 }
3964 }
3965
3966 void z80_remove_watchpoint(z80_context *context, uint32_t address, uint32_t size)
3967 {
3968 uint32_t end = address + size - 1;
3969 for (uint32_t i = 0; i < context->num_watchpoints; i++)
3970 {
3971 if (context->watchpoints[i].start == address && context->watchpoints[i].end == end) {
3972 context->watchpoints[i] = context->watchpoints[context->num_watchpoints-1];
3973 context->num_watchpoints--;
3974 return;
3975 }
3881 } 3976 }
3882 } 3977 }
3883 3978
3884 void z80_serialize(z80_context *context, serialize_buffer *buf) 3979 void z80_serialize(z80_context *context, serialize_buffer *buf)
3885 { 3980 {