Mercurial > repos > blastem
comparison debug.c @ 2358:4b2ac43c106e
Give debugger expression engine access to VDP and Sub CPU values. Add basic variable support
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 28 Oct 2023 00:52:10 -0700 |
parents | 344c6a3fe8a8 |
children | 04d29635d238 |
comparison
equal
deleted
inserted
replaced
2357:344c6a3fe8a8 | 2358:4b2ac43c106e |
---|---|
631 if (e->op.type == TOKEN_NAME) { | 631 if (e->op.type == TOKEN_NAME) { |
632 if (root->resolve(root, e->op.v.str, out)) { | 632 if (root->resolve(root, e->op.v.str, out)) { |
633 return 1; | 633 return 1; |
634 } | 634 } |
635 tern_val v; | 635 tern_val v; |
636 if (tern_find(root->variables, e->op.v.str, &v)) { | |
637 *out = v.intval; | |
638 return 1; | |
639 } | |
636 if (tern_find(root->symbols, e->op.v.str, &v)) { | 640 if (tern_find(root->symbols, e->op.v.str, &v)) { |
637 *out = v.intval; | 641 *out = v.intval; |
638 return 1; | 642 return 1; |
639 } | 643 } |
640 return 0; | 644 return 0; |
823 } | 827 } |
824 } else if(!strcasecmp(name, "cycle")) { | 828 } else if(!strcasecmp(name, "cycle")) { |
825 *out = context->current_cycle; | 829 *out = context->current_cycle; |
826 } else if (!strcasecmp(name, "pc")) { | 830 } else if (!strcasecmp(name, "pc")) { |
827 *out = root->address; | 831 *out = root->address; |
832 } else if (!strcasecmp(name, "sp")) { | |
833 *out = context->aregs[7]; | |
828 } else if (!strcasecmp(name, "usp")) { | 834 } else if (!strcasecmp(name, "usp")) { |
829 *out = context->status & 0x20 ? context->aregs[8] : context->aregs[7]; | 835 *out = context->status & 0x20 ? context->aregs[8] : context->aregs[7]; |
830 } else if (!strcasecmp(name, "ssp")) { | 836 } else if (!strcasecmp(name, "ssp")) { |
831 *out = context->status & 0x20 ? context->aregs[7] : context->aregs[8]; | 837 *out = context->status & 0x20 ? context->aregs[7] : context->aregs[8]; |
832 } else { | 838 } else { |
845 } else if (!strcasecmp(name, "sr")) { | 851 } else if (!strcasecmp(name, "sr")) { |
846 context->status = value >> 8; | 852 context->status = value >> 8; |
847 for (int flag = 0; flag < 5; flag++) { | 853 for (int flag = 0; flag < 5; flag++) { |
848 context->flags[flag] = (value & (1 << (4 - flag))) != 0; | 854 context->flags[flag] = (value & (1 << (4 - flag))) != 0; |
849 } | 855 } |
856 } else if (!strcasecmp(name, "sp")) { | |
857 context->aregs[7] = value; | |
850 } else if (!strcasecmp(name, "usp")) { | 858 } else if (!strcasecmp(name, "usp")) { |
851 context->aregs[context->status & 0x20 ? 8 : 7] = value; | 859 context->aregs[context->status & 0x20 ? 8 : 7] = value; |
852 } else if (!strcasecmp(name, "ssp")) { | 860 } else if (!strcasecmp(name, "ssp")) { |
853 context->aregs[context->status & 0x20 ? 7 : 8] = value; | 861 context->aregs[context->status & 0x20 ? 7 : 8] = value; |
854 } else { | 862 } else { |
855 return 0; | 863 return 0; |
856 } | 864 } |
857 return 1; | 865 return 1; |
858 } | 866 } |
859 | 867 |
868 static uint8_t resolve_vdp(debug_root *root, const char *name, uint32_t *out) | |
869 { | |
870 m68k_context *m68k = root->cpu_context; | |
871 genesis_context *gen = m68k->system; | |
872 vdp_context *vdp = gen->vdp; | |
873 if (!strcasecmp(name, "vcounter")) { | |
874 *out = vdp->vcounter; | |
875 } else if (!strcasecmp(name, "hcounter")) { | |
876 *out = vdp->hslot; | |
877 } else if (!strcasecmp(name, "address")) { | |
878 *out = vdp->address; | |
879 }else if (!strcasecmp(name, "cd")) { | |
880 *out = vdp->cd; | |
881 } else if (!strcasecmp(name, "status")) { | |
882 *out = vdp_status(vdp); | |
883 } else { | |
884 return 0; | |
885 } | |
886 return 1; | |
887 } | |
888 | |
860 static uint8_t resolve_genesis(debug_root *root, const char *name, uint32_t *out) | 889 static uint8_t resolve_genesis(debug_root *root, const char *name, uint32_t *out) |
861 { | 890 { |
891 | |
892 for (const char *cur = name; *cur; ++cur) | |
893 { | |
894 if (*cur == ':') { | |
895 if (cur - name == 3 && !memcmp(name, "vdp", 3)) { | |
896 return resolve_vdp(root, cur + 1, out); | |
897 } else if (cur - name == 3 && !memcmp(name, "sub", 3)) { | |
898 m68k_context *m68k = root->cpu_context; | |
899 genesis_context *gen = m68k->system; | |
900 if (gen->expansion) { | |
901 segacd_context *cd = gen->expansion; | |
902 root = find_m68k_root(cd->m68k); | |
903 return root->resolve(root, cur + 1, out); | |
904 } else { | |
905 return 0; | |
906 } | |
907 } else { | |
908 return 0; | |
909 } | |
910 } | |
911 } | |
862 if (resolve_m68k(root, name, out)) { | 912 if (resolve_m68k(root, name, out)) { |
863 return 1; | 913 return 1; |
864 } | 914 } |
865 m68k_context *m68k = root->cpu_context; | 915 m68k_context *m68k = root->cpu_context; |
866 genesis_context *gen = m68k->system; | 916 genesis_context *gen = m68k->system; |
1616 value |= old; | 1666 value |= old; |
1617 } | 1667 } |
1618 } | 1668 } |
1619 if (name) { | 1669 if (name) { |
1620 if (!root->set(root, name, value)) { | 1670 if (!root->set(root, name, value)) { |
1621 fprintf(stderr, "Failed to set %s\n", name); | 1671 tern_val v; |
1672 if (tern_find(root->variables, name, &v)) { | |
1673 root->variables = tern_insert_int(root->variables, name, value); | |
1674 } else { | |
1675 fprintf(stderr, "Failed to set %s\n", name); | |
1676 } | |
1622 } | 1677 } |
1623 } else if (!root->write_mem(root, address, value, size)) { | 1678 } else if (!root->write_mem(root, address, value, size)) { |
1624 fprintf(stderr, "Failed to write to address %X\n", address); | 1679 fprintf(stderr, "Failed to write to address %X\n", address); |
1625 } | 1680 } |
1681 return 1; | |
1682 } | |
1683 | |
1684 static uint8_t cmd_variable(debug_root *root, parsed_command *cmd) | |
1685 { | |
1686 if (cmd->args[0].parsed->type != EXPR_SCALAR || cmd->args[0].parsed->op.type != TOKEN_NAME) { | |
1687 fprintf(stderr, "First argument to variable must be a name, got %s\n", expr_type_names[cmd->args[0].parsed->type]); | |
1688 return 1; | |
1689 } | |
1690 uint32_t value = 0; | |
1691 if (cmd->num_args > 1) { | |
1692 if (!eval_expr(root, cmd->args[1].parsed, &cmd->args[1].value)) { | |
1693 fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw); | |
1694 return 1; | |
1695 } | |
1696 value = cmd->args[1].value; | |
1697 } | |
1698 root->variables = tern_insert_int(root->variables, cmd->args[0].parsed->op.v.str, value); | |
1626 return 1; | 1699 return 1; |
1627 } | 1700 } |
1628 | 1701 |
1629 static uint8_t cmd_frames(debug_root *root, parsed_command *cmd) | 1702 static uint8_t cmd_frames(debug_root *root, parsed_command *cmd) |
1630 { | 1703 { |
2141 }, | 2214 }, |
2142 .usage = "set MEM|NAME VALUE", | 2215 .usage = "set MEM|NAME VALUE", |
2143 .desc = "Set a register, symbol or memory location to the result of evaluating VALUE", | 2216 .desc = "Set a register, symbol or memory location to the result of evaluating VALUE", |
2144 .impl = cmd_set, | 2217 .impl = cmd_set, |
2145 .min_args = 2, | 2218 .min_args = 2, |
2219 .max_args = 2, | |
2220 .skip_eval = 1 | |
2221 }, | |
2222 { | |
2223 .names = (const char *[]){ | |
2224 "variable", NULL | |
2225 }, | |
2226 .usage = "variable NAME [VALUE]", | |
2227 .desc = "Create a new variable called NAME and set it to VALUE or 0 if no value provided", | |
2228 .impl = cmd_variable, | |
2229 .min_args = 1, | |
2146 .max_args = 2, | 2230 .max_args = 2, |
2147 .skip_eval = 1 | 2231 .skip_eval = 1 |
2148 }, | 2232 }, |
2149 { | 2233 { |
2150 .names = (const char *[]){ | 2234 .names = (const char *[]){ |