Mercurial > repos > blastem
comparison debug.c @ 2720:7dcc84cb14ee
Get uPD78K/II partially hooked up in debugger
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 16 Jul 2025 19:26:38 -0700 |
parents | 829205a9647a |
children | aa1d7118307c |
comparison
equal
deleted
inserted
replaced
2719:f817aedf5e53 | 2720:7dcc84cb14ee |
---|---|
2 #include "genesis.h" | 2 #include "genesis.h" |
3 #include "68kinst.h" | 3 #include "68kinst.h" |
4 #include "segacd.h" | 4 #include "segacd.h" |
5 #include "blastem.h" | 5 #include "blastem.h" |
6 #include "bindings.h" | 6 #include "bindings.h" |
7 #include "upd78k2_dis.h" | |
7 #include <ctype.h> | 8 #include <ctype.h> |
8 #include <math.h> | 9 #include <math.h> |
9 #include <stdlib.h> | 10 #include <stdlib.h> |
10 #include <string.h> | 11 #include <string.h> |
11 #ifndef _WIN32 | 12 #ifndef _WIN32 |
1558 return 0; | 1559 return 0; |
1559 } | 1560 } |
1560 *out = m68k_read_long(*out, context); | 1561 *out = m68k_read_long(*out, context); |
1561 } else { | 1562 } else { |
1562 if (*out & 1) { | 1563 if (*out & 1) { |
1563 fprintf(stderr, "Wword access to odd addresses ($%X) is not allowed\n", *out); | 1564 fprintf(stderr, "Word access to odd addresses ($%X) is not allowed\n", *out); |
1564 return 0; | 1565 return 0; |
1565 } | 1566 } |
1566 *out = m68k_read_word(*out, context); | 1567 *out = m68k_read_word(*out, context); |
1567 } | 1568 } |
1568 return 1; | 1569 return 1; |
2299 static void read_wait_progress(void) | 2300 static void read_wait_progress(void) |
2300 { | 2301 { |
2301 process_events(); | 2302 process_events(); |
2302 #ifndef IS_LIB | 2303 #ifndef IS_LIB |
2303 render_update_display(); | 2304 render_update_display(); |
2304 vdp_context *vdp = current_system->get_vdp(current_system); | 2305 if (current_system->get_vdp) { |
2305 if (vdp) { | 2306 vdp_context *vdp = current_system->get_vdp(current_system); |
2306 vdp_update_per_frame_debug(vdp); | 2307 if (vdp) { |
2308 vdp_update_per_frame_debug(vdp); | |
2309 } | |
2307 } | 2310 } |
2308 #endif | 2311 #endif |
2309 } | 2312 } |
2310 | 2313 |
2311 static uint8_t read_parse_command(debug_root *root, parsed_command *out, int indent_level) | 2314 static uint8_t read_parse_command(debug_root *root, parsed_command *out, int indent_level) |
5031 tern_foreach(root->disasm->labels, symbol_map, root); | 5034 tern_foreach(root->disasm->labels, symbol_map, root); |
5032 } | 5035 } |
5033 return root; | 5036 return root; |
5034 } | 5037 } |
5035 | 5038 |
5039 static uint8_t read_upd_byte(upd78k2_context *upd, uint32_t address) | |
5040 { | |
5041 if (address > 0xFE00 && address < 0xFF00) { | |
5042 return upd->iram[address & 0xFF]; | |
5043 } | |
5044 return read_byte(address, (void **)upd->mem_pointers, &upd->opts->gen, upd); | |
5045 } | |
5046 | |
5047 static uint8_t read_upd(debug_root *root, uint32_t *out, char size) | |
5048 { | |
5049 upd78k2_context *upd = root->cpu_context; | |
5050 uint32_t address = *out; | |
5051 *out = read_upd_byte(upd, address); | |
5052 if (size != 'b') { | |
5053 *out |= read_upd_byte(upd, address + 1) << 8; | |
5054 if (size == 'l') { | |
5055 *out |= read_upd_byte(upd, address + 2) << 16; | |
5056 *out |= read_upd_byte(upd, address + 3) << 24; | |
5057 } | |
5058 } | |
5059 return 1; | |
5060 } | |
5061 | |
5062 static void write_upd_byte(upd78k2_context *upd, uint32_t address, uint8_t value) | |
5063 { | |
5064 if (address > 0xFE00 && address < 0xFF00) { | |
5065 upd->iram[address & 0xFF] = value; | |
5066 } else { | |
5067 write_byte(address, value, (void **)upd->mem_pointers, &upd->opts->gen, upd); | |
5068 } | |
5069 } | |
5070 | |
5071 static uint8_t write_upd(debug_root *root, uint32_t address, uint32_t value, char size) | |
5072 { | |
5073 upd78k2_context *upd = root->cpu_context; | |
5074 write_upd_byte(upd, address, value); | |
5075 if (size != 'b') { | |
5076 write_upd_byte(upd, address + 1, value >> 8); | |
5077 if (size == 'l') { | |
5078 write_upd_byte(upd, address + 2, value >> 16); | |
5079 write_upd_byte(upd, address + 3, value >> 24); | |
5080 } | |
5081 } | |
5082 return 1; | |
5083 } | |
5084 | |
5085 static uint32_t upd_chunk_end(debug_root *root, uint32_t start_address) | |
5086 { | |
5087 upd78k2_context *upd = root->cpu_context; | |
5088 memmap_chunk const *chunk = find_map_chunk(start_address, &upd->opts->gen, 0, NULL); | |
5089 if (!chunk) { | |
5090 return start_address; | |
5091 } | |
5092 if (chunk->mask == upd->opts->gen.address_mask) { | |
5093 return chunk->end; | |
5094 } | |
5095 return (start_address & ~chunk->mask) + chunk->mask + 1; | |
5096 } | |
5097 | |
5098 static debug_val upd_reg_get(debug_var *var) | |
5099 { | |
5100 upd78k2_context *upd = var->ptr; | |
5101 return debug_int(upd->main[var->val.v.u32]); | |
5102 } | |
5103 | |
5104 static void upd_reg_set(debug_var *var, debug_val val) | |
5105 { | |
5106 upd78k2_context *upd = var->ptr; | |
5107 uint32_t ival; | |
5108 if (!debug_cast_int(val, &ival)) { | |
5109 static const char regs[] = "xacbedlh"; | |
5110 fprintf(stderr, "uPD78K/II register %c can only be set to an integer\n", regs[var->val.v.u32]); | |
5111 return; | |
5112 } | |
5113 upd->main[var->val.v.u32] = ival; | |
5114 } | |
5115 | |
5116 static debug_val upd_regpair_get(debug_var *var) | |
5117 { | |
5118 upd78k2_context *upd = var->ptr; | |
5119 uint16_t val = upd->main[var->val.v.u32 * 2]; | |
5120 val |= upd->main[var->val.v.u32 * 2 + 1] << 8; | |
5121 return debug_int(val); | |
5122 } | |
5123 | |
5124 static void upd_regpair_set(debug_var *var, debug_val val) | |
5125 { | |
5126 upd78k2_context *upd = var->ptr; | |
5127 uint32_t ival; | |
5128 if (!debug_cast_int(val, &ival)) { | |
5129 static const char regs[] = "xacbedlh"; | |
5130 fprintf(stderr, "uPD78K/II register %c can only be set to an integer\n", regs[var->val.v.u32]); | |
5131 return; | |
5132 } | |
5133 upd->main[var->val.v.u32 * 2] = ival; | |
5134 upd->main[var->val.v.u32 * 2 + 1] = ival >> 8; | |
5135 } | |
5136 | |
5137 debug_root *find_upd_root(upd78k2_context *upd) | |
5138 { | |
5139 debug_root *root = find_root(upd); | |
5140 if (root && !root->commands) { | |
5141 add_commands(root, common_commands, NUM_COMMON); | |
5142 root->read_mem = read_upd; | |
5143 root->write_mem = write_upd; | |
5144 root->chunk_end = upd_chunk_end; | |
5145 root->disasm = create_upd78k2_disasm(); | |
5146 static const char *regs[] = {"x","a","c","b","e","d","l","h"}; | |
5147 static const char *regpairs[] = {"ax", "bc", "de", "hl"}; | |
5148 debug_var *var; | |
5149 for (int i = 0; i < sizeof(regs)/sizeof(*regs); i++) | |
5150 { | |
5151 var = calloc(1, sizeof(debug_var)); | |
5152 var->get = upd_reg_get; | |
5153 var->set = upd_reg_set; | |
5154 var->ptr = root->cpu_context; | |
5155 var->val.v.u32 = i; | |
5156 root->variables = tern_insert_ptr(root->variables, regs[i], var); | |
5157 } | |
5158 for (int i = 0; i < sizeof(regpairs)/sizeof(*regpairs); i++) | |
5159 { | |
5160 var = calloc(1, sizeof(debug_var)); | |
5161 var->get = upd_regpair_get; | |
5162 var->set = upd_regpair_set; | |
5163 var->ptr = root->cpu_context; | |
5164 var->val.v.u32 = i; | |
5165 root->variables = tern_insert_ptr(root->variables, regpairs[i], var); | |
5166 } | |
5167 } | |
5168 return root; | |
5169 } | |
5170 | |
5036 #ifndef NO_Z80 | 5171 #ifndef NO_Z80 |
5037 #ifdef NEW_CORE | 5172 #ifdef NEW_CORE |
5038 #define Z80_OPTS opts | 5173 #define Z80_OPTS opts |
5039 #else | 5174 #else |
5040 #define Z80_OPTS options | 5175 #define Z80_OPTS options |
5662 m68k_disasm_labels(&inst, input_buf, root->disasm); | 5797 m68k_disasm_labels(&inst, input_buf, root->disasm); |
5663 printf("%X: %s\n", address, input_buf); | 5798 printf("%X: %s\n", address, input_buf); |
5664 debugger_repl(root); | 5799 debugger_repl(root); |
5665 return; | 5800 return; |
5666 } | 5801 } |
5802 | |
5803 static uint8_t upd_debug_fetch(uint16_t address, void *data) | |
5804 { | |
5805 upd78k2_context *upd = data; | |
5806 return read_byte(address, (void **)upd->mem_pointers, &upd->opts->gen, upd); | |
5807 } | |
5808 | |
5809 void upd_debugger(upd78k2_context *upd) | |
5810 { | |
5811 static char last_cmd[1024]; | |
5812 char input_buf[1024]; | |
5813 | |
5814 init_terminal(); | |
5815 | |
5816 debug_root *root = find_upd_root(upd); | |
5817 if (!root) { | |
5818 return; | |
5819 } | |
5820 /* | |
5821 if (upd->pc == root->branch_t) { | |
5822 bp_def ** f_bp = find_breakpoint(&root->breakpoints, root->branch_f, BP_TYPE_CPU); | |
5823 if (!*f_bp) { | |
5824 remove_breakpoint(context, root->branch_f); | |
5825 } | |
5826 root->branch_t = root->branch_f = 0; | |
5827 } else if(upd->pc == root->branch_f) { | |
5828 bp_def ** t_bp = find_breakpoint(&root->breakpoints, root->branch_t, BP_TYPE_CPU); | |
5829 if (!*t_bp) { | |
5830 remove_breakpoint(context, root->branch_t); | |
5831 } | |
5832 root->branch_t = root->branch_f = 0; | |
5833 } | |
5834 */ | |
5835 | |
5836 root->address = upd->pc; | |
5837 int debugging = 1; | |
5838 //Check if this is a user set breakpoint, or just a temporary one | |
5839 bp_def ** this_bp = find_breakpoint(&root->breakpoints, upd->pc, BP_TYPE_CPU); | |
5840 if (*this_bp) { | |
5841 if ((*this_bp)->condition) { | |
5842 debug_val condres; | |
5843 if (eval_expr(root, (*this_bp)->condition, &condres)) { | |
5844 if (!condres.v.u32) { | |
5845 return; | |
5846 } | |
5847 } else { | |
5848 fprintf(stderr, "Failed to eval condition for uPD78K/II breakpoint %u\n", (*this_bp)->index); | |
5849 free_expr((*this_bp)->condition); | |
5850 (*this_bp)->condition = NULL; | |
5851 } | |
5852 } | |
5853 for (uint32_t i = 0; debugging && i < (*this_bp)->num_commands; i++) | |
5854 { | |
5855 debugging = run_command(root, (*this_bp)->commands + i); | |
5856 } | |
5857 if (debugging) { | |
5858 printf("uPD78K/II Breakpoint %d hit\n", (*this_bp)->index); | |
5859 } else { | |
5860 fflush(stdout); | |
5861 return; | |
5862 } | |
5863 } else { | |
5864 //remove_breakpoint(context, address); | |
5865 } | |
5866 upd_address_ref ref; | |
5867 uint16_t after = upd78k2_disasm(input_buf, &ref, upd->pc, upd_debug_fetch, upd, root->disasm); | |
5868 root->after = after; | |
5869 root->inst = &ref; | |
5870 for (disp_def * cur = root->displays; cur; cur = cur->next) { | |
5871 char format_str[8]; | |
5872 make_format_str(format_str, cur->format); | |
5873 for (int i = 0; i < cur->num_args; i++) | |
5874 { | |
5875 eval_expr(root, cur->args[i].parsed, &cur->args[i].value); | |
5876 do_print(root, format_str, cur->args[i].raw, cur->args[i].value); | |
5877 } | |
5878 } | |
5879 printf("%X: %s\n", root->address, input_buf); | |
5880 debugger_repl(root); | |
5881 return; | |
5882 } |