# HG changeset patch # User Michael Pavone # Date 1698479530 25200 # Node ID 4b2ac43c106e857431b6f84baa419e9e916e5224 # Parent 344c6a3fe8a81104d36e5aa934204499e6935a5d Give debugger expression engine access to VDP and Sub CPU values. Add basic variable support diff -r 344c6a3fe8a8 -r 4b2ac43c106e debug.c --- a/debug.c Fri Oct 27 23:49:04 2023 -0700 +++ b/debug.c Sat Oct 28 00:52:10 2023 -0700 @@ -633,6 +633,10 @@ return 1; } tern_val v; + if (tern_find(root->variables, e->op.v.str, &v)) { + *out = v.intval; + return 1; + } if (tern_find(root->symbols, e->op.v.str, &v)) { *out = v.intval; return 1; @@ -825,6 +829,8 @@ *out = context->current_cycle; } else if (!strcasecmp(name, "pc")) { *out = root->address; + } else if (!strcasecmp(name, "sp")) { + *out = context->aregs[7]; } else if (!strcasecmp(name, "usp")) { *out = context->status & 0x20 ? context->aregs[8] : context->aregs[7]; } else if (!strcasecmp(name, "ssp")) { @@ -847,6 +853,8 @@ for (int flag = 0; flag < 5; flag++) { context->flags[flag] = (value & (1 << (4 - flag))) != 0; } + } else if (!strcasecmp(name, "sp")) { + context->aregs[7] = value; } else if (!strcasecmp(name, "usp")) { context->aregs[context->status & 0x20 ? 8 : 7] = value; } else if (!strcasecmp(name, "ssp")) { @@ -857,8 +865,50 @@ return 1; } +static uint8_t resolve_vdp(debug_root *root, const char *name, uint32_t *out) +{ + m68k_context *m68k = root->cpu_context; + genesis_context *gen = m68k->system; + vdp_context *vdp = gen->vdp; + if (!strcasecmp(name, "vcounter")) { + *out = vdp->vcounter; + } else if (!strcasecmp(name, "hcounter")) { + *out = vdp->hslot; + } else if (!strcasecmp(name, "address")) { + *out = vdp->address; + }else if (!strcasecmp(name, "cd")) { + *out = vdp->cd; + } else if (!strcasecmp(name, "status")) { + *out = vdp_status(vdp); + } else { + return 0; + } + return 1; +} + static uint8_t resolve_genesis(debug_root *root, const char *name, uint32_t *out) { + + for (const char *cur = name; *cur; ++cur) + { + if (*cur == ':') { + if (cur - name == 3 && !memcmp(name, "vdp", 3)) { + return resolve_vdp(root, cur + 1, out); + } else if (cur - name == 3 && !memcmp(name, "sub", 3)) { + m68k_context *m68k = root->cpu_context; + genesis_context *gen = m68k->system; + if (gen->expansion) { + segacd_context *cd = gen->expansion; + root = find_m68k_root(cd->m68k); + return root->resolve(root, cur + 1, out); + } else { + return 0; + } + } else { + return 0; + } + } + } if (resolve_m68k(root, name, out)) { return 1; } @@ -1618,7 +1668,12 @@ } if (name) { if (!root->set(root, name, value)) { - fprintf(stderr, "Failed to set %s\n", name); + tern_val v; + if (tern_find(root->variables, name, &v)) { + root->variables = tern_insert_int(root->variables, name, value); + } else { + fprintf(stderr, "Failed to set %s\n", name); + } } } else if (!root->write_mem(root, address, value, size)) { fprintf(stderr, "Failed to write to address %X\n", address); @@ -1626,6 +1681,24 @@ return 1; } +static uint8_t cmd_variable(debug_root *root, parsed_command *cmd) +{ + if (cmd->args[0].parsed->type != EXPR_SCALAR || cmd->args[0].parsed->op.type != TOKEN_NAME) { + fprintf(stderr, "First argument to variable must be a name, got %s\n", expr_type_names[cmd->args[0].parsed->type]); + return 1; + } + uint32_t value = 0; + if (cmd->num_args > 1) { + if (!eval_expr(root, cmd->args[1].parsed, &cmd->args[1].value)) { + fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw); + return 1; + } + value = cmd->args[1].value; + } + root->variables = tern_insert_int(root->variables, cmd->args[0].parsed->op.v.str, value); + return 1; +} + static uint8_t cmd_frames(debug_root *root, parsed_command *cmd) { current_system->enter_debugger_frames = cmd->args[0].value; @@ -2148,6 +2221,17 @@ }, { .names = (const char *[]){ + "variable", NULL + }, + .usage = "variable NAME [VALUE]", + .desc = "Create a new variable called NAME and set it to VALUE or 0 if no value provided", + .impl = cmd_variable, + .min_args = 1, + .max_args = 2, + .skip_eval = 1 + }, + { + .names = (const char *[]){ "frames", NULL }, .usage = "frames EXPRESSION", diff -r 344c6a3fe8a8 -r 4b2ac43c106e debug.h --- a/debug.h Fri Oct 27 23:49:04 2023 -0700 +++ b/debug.h Sat Oct 28 00:52:10 2023 -0700 @@ -117,6 +117,7 @@ disp_def *displays; tern_node *commands; tern_node *symbols; + tern_node *variables; disasm_context *disasm; resolver resolve; reader read_mem; diff -r 344c6a3fe8a8 -r 4b2ac43c106e vdp.c --- a/vdp.c Fri Oct 27 23:49:04 2023 -0700 +++ b/vdp.c Sat Oct 28 00:52:10 2023 -0700 @@ -716,13 +716,10 @@ context->address, context->cd, cd_name(context->cd), (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none", context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false", - (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context)); + (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_status(context)); printf("\nDebug Register: %X | Output disabled: %s, Force Layer: %d\n", context->test_port, (context->test_port & TEST_BIT_DISABLE) ? "true" : "false", context->test_port >> 7 & 3 ); - //restore flags as calling vdp_control_port_read can change them - context->flags = old_flags; - context->flags2 = old_flags2; } static uint8_t is_active(vdp_context *context) @@ -4831,10 +4828,8 @@ context->test_port = value; } -uint16_t vdp_control_port_read(vdp_context * context) +uint16_t vdp_status(vdp_context *context) { - context->flags &= ~FLAG_PENDING; - context->flags2 &= ~FLAG2_BYTE_PENDING; //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00; if (context->fifo_read < 0) { @@ -4848,11 +4843,9 @@ } if (context->flags & FLAG_DOT_OFLOW) { value |= 0x40; - context->flags &= ~FLAG_DOT_OFLOW; } if (context->flags2 & FLAG2_SPRITE_COLLIDE) { value |= 0x20; - context->flags2 &= ~FLAG2_SPRITE_COLLIDE; } if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) { value |= 0x10; @@ -4876,6 +4869,14 @@ if (context->flags2 & FLAG2_REGION_PAL) { value |= 0x1; } + return value; +} + +uint16_t vdp_control_port_read(vdp_context * context) +{ + uint16_t value = vdp_status(context); + context->flags &= ~(FLAG_DOT_OFLOW|FLAG_PENDING); + context->flags2 &= ~(FLAG2_SPRITE_COLLIDE|FLAG2_BYTE_PENDING); //printf("status read at cycle %d returned %X\n", context->cycles, value); return value; } diff -r 344c6a3fe8a8 -r 4b2ac43c106e vdp.h --- a/vdp.h Fri Oct 27 23:49:04 2023 -0700 +++ b/vdp.h Sat Oct 28 00:52:10 2023 -0700 @@ -172,7 +172,15 @@ VDP_TMS9918A }; +typedef struct vdp_context vdp_context; +typedef void (*vdp_hook_fun)(vdp_context *); + typedef struct { + vdp_hook_fun handler; + void *data; +} vdp_hook; + +struct vdp_context { system_header *system; //pointer to current line in framebuffer uint32_t *output; @@ -181,6 +189,9 @@ uint8_t *done_composite; uint32_t *debug_fbs[NUM_DEBUG_TYPES]; char *kmod_msg_buffer; + vdp_hook dma_hook; + vdp_hook vdpreg_hook; + vdp_hook data_hook; uint32_t kmod_buffer_storage; uint32_t kmod_buffer_length; uint32_t timer_start_cycle; @@ -258,7 +269,7 @@ uint8_t cram_latch; int32_t color_map[1 << 12]; uint8_t vdpmem[]; -} vdp_context; +}; @@ -306,5 +317,6 @@ uint16_t read_dma_value(uint32_t address); void vdp_dma_started(void); void vdp_replay_event(vdp_context *context, uint8_t event, event_reader *reader); +uint16_t vdp_status(vdp_context *context); #endif //VDP_H_