comparison 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
comparison
equal deleted inserted replaced
2395:ebca8ab02701 2396:bf4f1a8d1d48
833 } 833 }
834 834
835 return context; 835 return context;
836 } 836 }
837 837
838 static m68k_watchpoint *m68k_find_watchpoint(uint32_t address, m68k_context *context)
839 {
840 for (uint32_t i = 0; i < context->num_watchpoints; i++)
841 {
842 if (address >= context->watchpoints[i].start && address < context->watchpoints[i].end) {
843 return context->watchpoints + i;
844 }
845 }
846 return NULL;
847 }
848
849 static void *m68k_watchpoint_check16(uint32_t address, void *vcontext, uint16_t value)
850 {
851 m68k_context *context = vcontext;
852 m68k_watchpoint *watch = m68k_find_watchpoint(address, context);
853 if (!watch) {
854 return vcontext;
855 }
856 if (watch->check_change) {
857 uint16_t old = read_word(address, (void **)context->mem_pointers, &context->options->gen, context);
858 if (old == value) {
859 return vcontext;
860 }
861 context->wp_old_value = old;
862 } else {
863 context->wp_old_value = value;
864 }
865 context->wp_hit_address = address;
866 context->wp_hit_value = value;
867 context->wp_hit = 1;
868 context->target_cycle = context->sync_cycle = context->current_cycle;
869 system_header *system = context->system;
870 system->enter_debugger = 1;
871 return vcontext;
872 }
873
874 static void *m68k_watchpoint_check8(uint32_t address, void *vcontext, uint8_t value)
875 {
876 m68k_context *context = vcontext;
877 m68k_watchpoint *watch = m68k_find_watchpoint(address, context);
878 if (!watch) {
879 return vcontext;
880 }
881 if (watch->check_change) {
882 uint8_t old = read_byte(address, (void **)context->mem_pointers, &context->options->gen, context);
883 if (old == value) {
884 return vcontext;
885 }
886 context->wp_old_value = old;
887 } else {
888 context->wp_old_value = value;
889 }
890 context->wp_hit_address = address;
891 context->wp_hit_value = value;
892 context->wp_hit = 1;
893 context->target_cycle = context->sync_cycle = context->current_cycle;
894 system_header *system = context->system;
895 system->enter_debugger = 1;
896 return vcontext;
897 }
898
899 static void m68k_enable_watchpoints(m68k_context *context)
900 {
901 if (context->options->gen.check_watchpoints_16) {
902 //already enabled
903 return;
904 }
905 context->options->gen.check_watchpoints_16 = m68k_watchpoint_check16;
906 context->options->gen.check_watchpoints_8 = m68k_watchpoint_check8;
907 //re-generate write handlers with watchpoints enabled
908 code_ptr new_write16 = gen_mem_fun(&context->options->gen, context->options->gen.memmap, context->options->gen.memmap_chunks, WRITE_16, NULL);
909 code_ptr new_write8 = gen_mem_fun(&context->options->gen, context->options->gen.memmap, context->options->gen.memmap_chunks, WRITE_8, NULL);
910
911 //patch old write handlers to point to the new ones
912 code_info code = {
913 .cur = context->options->write_16,
914 .last = context->options->write_16 + 256
915 };
916 jmp(&code, new_write16);
917 code.cur = context->options->write_8;
918 code.last = code.cur + 256;
919 jmp(&code, new_write8);
920 context->options->write_16 = new_write16;
921 context->options->write_8 = new_write8;
922 }
923
924 void m68k_add_watchpoint(m68k_context *context, uint32_t address, uint32_t size)
925 {
926 uint32_t end = address + size;
927 for (uint32_t i = 0; i < context->num_watchpoints; i++)
928 {
929 if (context->watchpoints[i].start == address && context->watchpoints[i].end == end) {
930 return;
931 }
932 }
933 m68k_enable_watchpoints(context);
934 if (context->wp_storage == context->num_watchpoints) {
935 context->wp_storage = context->wp_storage ? context->wp_storage * 2 : 4;
936 context->watchpoints = realloc(context->watchpoints, context->wp_storage * sizeof(m68k_breakpoint));
937 }
938 const memmap_chunk *chunk = find_map_chunk(address, &context->options->gen, 0, NULL);
939 context->watchpoints[context->num_watchpoints++] = (m68k_watchpoint){
940 .start = address,
941 .end = end,
942 .check_change = chunk && (chunk->flags & MMAP_READ)
943 };
944 if (context->watchpoint_min > address) {
945 context->watchpoint_min = address;
946 }
947 if (context->watchpoint_max < address + size) {
948 context->watchpoint_max = address + size;
949 }
950 }
951
952 void m68k_remove_watchpoint(m68k_context *context, uint32_t address, uint32_t size)
953 {
954 uint32_t end = address + size;
955 for (uint32_t i = 0; i < context->num_watchpoints; i++)
956 {
957 if (context->watchpoints[i].start == address && context->watchpoints[i].end == end) {
958 context->watchpoints[i] = context->watchpoints[context->num_watchpoints-1];
959 context->num_watchpoints--;
960 return;
961 }
962 }
963 }
964
838 typedef enum { 965 typedef enum {
839 RAW_FUNC = 1, 966 RAW_FUNC = 1,
840 BINARY_ARITH, 967 BINARY_ARITH,
841 UNARY_ARITH, 968 UNARY_ARITH,
842 OP_FUNC 969 OP_FUNC