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