Mercurial > repos > blastem
comparison debug.c @ 2362:b6c5a0fa3dfc
Refactor debugger a bit. Allow types other than integers to be passed in expressions and stored in arrays. Better namespace support
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Mon, 06 Nov 2023 22:41:33 -0800 |
parents | 3350b3c8faa8 |
children | b865f33fd47e |
comparison
equal
deleted
inserted
replaced
2361:3350b3c8faa8 | 2362:b6c5a0fa3dfc |
---|---|
22 #define Z80_OPTS opts | 22 #define Z80_OPTS opts |
23 #else | 23 #else |
24 #define Z80_OPTS options | 24 #define Z80_OPTS options |
25 #endif | 25 #endif |
26 | 26 |
27 static debug_root roots[5]; | 27 static debug_root *roots; |
28 static uint32_t num_roots; | 28 static uint32_t num_roots, root_storage; |
29 #define MAX_DEBUG_ROOTS (sizeof(roots)/sizeof(*roots)) | |
30 | 29 |
31 debug_root *find_root(void *cpu) | 30 debug_root *find_root(void *cpu) |
32 { | 31 { |
33 for (uint32_t i = 0; i < num_roots; i++) | 32 for (uint32_t i = 0; i < num_roots; i++) |
34 { | 33 { |
35 if (roots[i].cpu_context == cpu) { | 34 if (roots[i].cpu_context == cpu) { |
36 return roots + i; | 35 return roots + i; |
37 } | 36 } |
38 } | 37 } |
39 if (num_roots < MAX_DEBUG_ROOTS) { | 38 if (num_roots == root_storage) { |
40 num_roots++; | 39 root_storage = root_storage ? root_storage * 2 : 5; |
41 memset(roots + num_roots - 1, 0, sizeof(debug_root)); | 40 roots = realloc(roots, root_storage * sizeof(debug_root)); |
42 roots[num_roots-1].cpu_context = cpu; | 41 } |
43 return roots + num_roots - 1; | 42 num_roots++; |
44 } | 43 memset(roots + num_roots - 1, 0, sizeof(debug_root)); |
45 return NULL; | 44 roots[num_roots-1].cpu_context = cpu; |
45 return roots + num_roots - 1; | |
46 } | 46 } |
47 | 47 |
48 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address, uint8_t type) | 48 bp_def ** find_breakpoint(bp_def ** cur, uint32_t address, uint8_t type) |
49 { | 49 { |
50 while (*cur) { | 50 while (*cur) { |
63 break; | 63 break; |
64 } | 64 } |
65 cur = &((*cur)->next); | 65 cur = &((*cur)->next); |
66 } | 66 } |
67 return cur; | 67 return cur; |
68 } | |
69 | |
70 static debug_array *arrays; | |
71 static uint32_t num_arrays, array_storage; | |
72 static debug_array *alloc_array(void) | |
73 { | |
74 if (num_arrays == array_storage) { | |
75 array_storage = array_storage ? array_storage * 2 : 4; | |
76 arrays = realloc(arrays, sizeof(debug_array) * array_storage); | |
77 } | |
78 return arrays + num_arrays++; | |
79 } | |
80 | |
81 static debug_val new_fixed_array(void *base, debug_array_get get, debug_array_set set, uint32_t size) | |
82 { | |
83 debug_array *array = alloc_array(); | |
84 array->get = get; | |
85 array->set = set; | |
86 array->append = NULL; | |
87 array->base = base; | |
88 array->size = array->storage = size; | |
89 debug_val ret; | |
90 ret.type = DBG_VAL_ARRAY; | |
91 ret.v.u32 = array - arrays; | |
92 return ret; | |
93 } | |
94 | |
95 static debug_val user_array_get(debug_array *array, uint32_t index) | |
96 { | |
97 debug_val *data = array->base; | |
98 return data[index]; | |
99 } | |
100 | |
101 static void user_array_set(debug_array *array, uint32_t index, debug_val value) | |
102 { | |
103 debug_val *data = array->base; | |
104 data[index] = value; | |
105 } | |
106 | |
107 static void user_array_append(debug_array *array, debug_val value) | |
108 { | |
109 if (array->size == array->storage) { | |
110 array->storage *= 2; | |
111 array->base = realloc(array->base, sizeof(debug_val) * array->storage); | |
112 } | |
113 debug_val *data = array->base; | |
114 data[array->size++] = value; | |
115 } | |
116 | |
117 static debug_val new_user_array(uint32_t size) | |
118 { | |
119 debug_array *array = alloc_array(); | |
120 array->get = user_array_get; | |
121 array->set = user_array_set; | |
122 array->append = user_array_append; | |
123 array->size = size; | |
124 array->storage = size ? size : 4; | |
125 debug_val ret; | |
126 ret.type = DBG_VAL_ARRAY; | |
127 ret.v.u32 = array - arrays; | |
128 return ret; | |
129 } | |
130 | |
131 debug_array *get_array(debug_val val) | |
132 { | |
133 if (val.type != DBG_VAL_ARRAY) { | |
134 return NULL; | |
135 } | |
136 return arrays + val.v.u32; | |
137 } | |
138 | |
139 debug_val user_var_get(debug_var *var) | |
140 { | |
141 return var->val; | |
142 } | |
143 | |
144 void user_var_set(debug_var *var, debug_val val) | |
145 { | |
146 var->val = val; | |
147 } | |
148 | |
149 static void new_user_variable(debug_root *root, const char *name, debug_val val) | |
150 { | |
151 debug_var *var = calloc(1, sizeof(debug_var)); | |
152 var->get = user_var_get; | |
153 var->set = user_var_set; | |
154 var->val = val; | |
155 root->variables = tern_insert_ptr(root->variables, name, var); | |
156 } | |
157 | |
158 static void new_readonly_variable(debug_root *root, const char *name, debug_val val) | |
159 { | |
160 debug_var *var = calloc(1, sizeof(debug_var)); | |
161 var->get = user_var_get; | |
162 var->set = NULL; | |
163 var->val = val; | |
164 root->variables = tern_insert_ptr(root->variables, name, var); | |
165 } | |
166 | |
167 static debug_val debug_int(uint32_t i) | |
168 { | |
169 debug_val ret; | |
170 ret.type = DBG_VAL_U32; | |
171 ret.v.u32 = i; | |
172 return ret; | |
68 } | 173 } |
69 | 174 |
70 static const char *token_type_names[] = { | 175 static const char *token_type_names[] = { |
71 "TOKEN_NONE", | 176 "TOKEN_NONE", |
72 "TOKEN_NUM", | 177 "TOKEN_NUM", |
225 } | 330 } |
226 | 331 |
227 static expr *parse_scalar_or_muldiv(char *start, char **end); | 332 static expr *parse_scalar_or_muldiv(char *start, char **end); |
228 static expr *parse_expression(char *start, char **end); | 333 static expr *parse_expression(char *start, char **end); |
229 | 334 |
335 static void handle_namespace(expr *e) | |
336 { | |
337 if (e->op.type != TOKEN_NAME && e->op.type != TOKEN_ARRAY) { | |
338 return; | |
339 } | |
340 char *start = e->op.v.str; | |
341 char *orig_start = start; | |
342 for (char *cur = start; *cur; ++cur) | |
343 { | |
344 if (*cur == ':') { | |
345 char *ns = malloc(cur - start + 1); | |
346 memcpy(ns, start, cur - start); | |
347 ns[cur - start] = 0; | |
348 expr *inner = calloc(1, sizeof(expr)); | |
349 inner->type = EXPR_SCALAR; | |
350 inner->op.type = TOKEN_NAME; | |
351 start = cur + 1; | |
352 inner->op.v.str = start; | |
353 e->left = inner; | |
354 e->type = EXPR_NAMESPACE; | |
355 e->op.v.str = ns; | |
356 e = inner; | |
357 } | |
358 } | |
359 if (start != orig_start) { | |
360 //We've split the original string up into | |
361 //a bunch of individually allocated fragments | |
362 //this is just a little stup of the original | |
363 e->op.v.str = strdup(e->op.v.str); | |
364 free(orig_start); | |
365 } | |
366 } | |
367 | |
230 static expr *parse_scalar(char *start, char **end) | 368 static expr *parse_scalar(char *start, char **end) |
231 { | 369 { |
232 char *after_first; | 370 char *after_first; |
233 token first = parse_token(start, &after_first); | 371 token first = parse_token(start, &after_first); |
234 if (!first.type) { | 372 if (!first.type) { |
259 //consume the bracket token | 397 //consume the bracket token |
260 parse_token(after_first, &after_first); | 398 parse_token(after_first, &after_first); |
261 ret->right = calloc(1, sizeof(expr)); | 399 ret->right = calloc(1, sizeof(expr)); |
262 ret->right->type = EXPR_SCALAR; | 400 ret->right->type = EXPR_SCALAR; |
263 ret->right->op = first; | 401 ret->right->op = first; |
402 handle_namespace(ret->right); | |
264 } | 403 } |
265 | 404 |
266 ret->left = parse_expression(after_first, end); | 405 ret->left = parse_expression(after_first, end); |
267 if (!ret->left) { | 406 if (!ret->left) { |
268 fprintf(stderr, "Expression expected after `[`\n"); | 407 fprintf(stderr, "Expression expected after `[`\n"); |
304 token second = parse_token(after_first, end); | 443 token second = parse_token(after_first, end); |
305 if (second.type != TOKEN_SIZE) { | 444 if (second.type != TOKEN_SIZE) { |
306 expr *ret = calloc(1, sizeof(expr)); | 445 expr *ret = calloc(1, sizeof(expr)); |
307 ret->type = EXPR_SCALAR; | 446 ret->type = EXPR_SCALAR; |
308 ret->op = first; | 447 ret->op = first; |
448 handle_namespace(ret); | |
309 *end = after_first; | 449 *end = after_first; |
310 return ret; | 450 return ret; |
311 } | 451 } |
312 expr *ret = calloc(1, sizeof(expr)); | 452 expr *ret = calloc(1, sizeof(expr)); |
313 ret->type = EXPR_SIZE; | 453 ret->type = EXPR_SIZE; |
314 ret->left = calloc(1, sizeof(expr)); | 454 ret->left = calloc(1, sizeof(expr)); |
315 ret->left->type = EXPR_SCALAR; | 455 ret->left->type = EXPR_SCALAR; |
316 ret->left->op = second; | 456 ret->left->op = second; |
457 handle_namespace(ret->left); | |
317 ret->op = first; | 458 ret->op = first; |
318 return ret; | 459 return ret; |
319 } | 460 } |
320 | 461 |
321 static expr *maybe_binary(expr *left, char *start, char **end) | 462 static expr *maybe_binary(expr *left, char *start, char **end) |
415 //consume the bracket token | 556 //consume the bracket token |
416 parse_token(after_first, &after_first); | 557 parse_token(after_first, &after_first); |
417 ret->right = calloc(1, sizeof(expr)); | 558 ret->right = calloc(1, sizeof(expr)); |
418 ret->right->type = EXPR_SCALAR; | 559 ret->right->type = EXPR_SCALAR; |
419 ret->right->op = first; | 560 ret->right->op = first; |
561 handle_namespace(ret->right); | |
420 } | 562 } |
421 | 563 |
422 ret->left = parse_expression(after_first, end); | 564 ret->left = parse_expression(after_first, end); |
423 if (!ret->left) { | 565 if (!ret->left) { |
424 fprintf(stderr, "Expression expected after `[`\n"); | 566 fprintf(stderr, "Expression expected after `[`\n"); |
464 expr *bin = calloc(1, sizeof(expr)); | 606 expr *bin = calloc(1, sizeof(expr)); |
465 bin->type = EXPR_BINARY; | 607 bin->type = EXPR_BINARY; |
466 bin->left = calloc(1, sizeof(expr)); | 608 bin->left = calloc(1, sizeof(expr)); |
467 bin->left->type = EXPR_SCALAR; | 609 bin->left->type = EXPR_SCALAR; |
468 bin->left->op = first; | 610 bin->left->op = first; |
611 handle_namespace(bin->left); | |
469 bin->op = second; | 612 bin->op = second; |
470 switch (second.v.op[0]) | 613 switch (second.v.op[0]) |
471 { | 614 { |
472 case '*': | 615 case '*': |
473 case '/': | 616 case '/': |
497 value->type = EXPR_SIZE; | 640 value->type = EXPR_SIZE; |
498 value->op = second; | 641 value->op = second; |
499 value->left = calloc(1, sizeof(expr)); | 642 value->left = calloc(1, sizeof(expr)); |
500 value->left->type = EXPR_SCALAR; | 643 value->left->type = EXPR_SCALAR; |
501 value->left->op = first; | 644 value->left->op = first; |
645 handle_namespace(value->left); | |
502 return maybe_muldiv(value, after_second, end); | 646 return maybe_muldiv(value, after_second, end); |
503 } else { | 647 } else { |
504 expr *ret = calloc(1, sizeof(expr)); | 648 expr *ret = calloc(1, sizeof(expr)); |
505 ret->type = EXPR_SCALAR; | 649 ret->type = EXPR_SCALAR; |
506 ret->op = first; | 650 ret->op = first; |
651 handle_namespace(ret); | |
507 *end = after_first; | 652 *end = after_first; |
508 return ret; | 653 return ret; |
509 } | 654 } |
510 } | 655 } |
511 | 656 |
540 //consume the bracket token | 685 //consume the bracket token |
541 parse_token(after_first, &after_first); | 686 parse_token(after_first, &after_first); |
542 ret->right = calloc(1, sizeof(expr)); | 687 ret->right = calloc(1, sizeof(expr)); |
543 ret->right->type = EXPR_SCALAR; | 688 ret->right->type = EXPR_SCALAR; |
544 ret->right->op = first; | 689 ret->right->op = first; |
690 handle_namespace(ret->right); | |
545 } | 691 } |
546 | 692 |
547 ret->left = parse_expression(after_first, end); | 693 ret->left = parse_expression(after_first, end); |
548 if (!ret->left) { | 694 if (!ret->left) { |
549 fprintf(stderr, "Expression expected after `[`\n"); | 695 fprintf(stderr, "Expression expected after `[`\n"); |
588 expr *bin = calloc(1, sizeof(expr)); | 734 expr *bin = calloc(1, sizeof(expr)); |
589 bin->type = EXPR_BINARY; | 735 bin->type = EXPR_BINARY; |
590 bin->left = calloc(1, sizeof(expr)); | 736 bin->left = calloc(1, sizeof(expr)); |
591 bin->left->type = EXPR_SCALAR; | 737 bin->left->type = EXPR_SCALAR; |
592 bin->left->op = first; | 738 bin->left->op = first; |
739 handle_namespace(bin->left); | |
593 bin->op = second; | 740 bin->op = second; |
594 switch (second.v.op[0]) | 741 switch (second.v.op[0]) |
595 { | 742 { |
596 case '*': | 743 case '*': |
597 case '/': | 744 case '/': |
636 value->type = EXPR_SIZE; | 783 value->type = EXPR_SIZE; |
637 value->op = second; | 784 value->op = second; |
638 value->left = calloc(1, sizeof(expr)); | 785 value->left = calloc(1, sizeof(expr)); |
639 value->left->type = EXPR_SCALAR; | 786 value->left->type = EXPR_SCALAR; |
640 value->left->op = first; | 787 value->left->op = first; |
788 handle_namespace(value->left); | |
641 return maybe_binary(value, after_second, end); | 789 return maybe_binary(value, after_second, end); |
642 } else { | 790 } else { |
643 if (second.type == TOKEN_NAME) { | 791 if (second.type == TOKEN_NAME) { |
644 free(second.v.str); | 792 free(second.v.str); |
645 } | 793 } |
646 expr *ret = calloc(1, sizeof(expr)); | 794 expr *ret = calloc(1, sizeof(expr)); |
647 ret->type = EXPR_SCALAR; | 795 ret->type = EXPR_SCALAR; |
648 ret->op = first; | 796 ret->op = first; |
797 handle_namespace(ret); | |
649 *end = after_first; | 798 *end = after_first; |
650 return ret; | 799 return ret; |
651 } | 800 } |
652 } | 801 } |
653 | 802 |
654 static debug_array* full_array_resolve(debug_root *root, const char *name) | 803 uint8_t eval_expr(debug_root *root, expr *e, debug_val *out) |
655 { | 804 { |
656 debug_array *ret = root->array_resolve(root, name); | 805 debug_val right; |
657 if (!ret) { | |
658 ret = tern_find_ptr(root->arrays, name); | |
659 } | |
660 return ret; | |
661 } | |
662 | |
663 uint8_t eval_expr(debug_root *root, expr *e, uint32_t *out) | |
664 { | |
665 uint32_t right; | |
666 switch(e->type) | 806 switch(e->type) |
667 { | 807 { |
668 case EXPR_SCALAR: | 808 case EXPR_SCALAR: |
669 if (e->op.type == TOKEN_NAME) { | 809 if (e->op.type == TOKEN_NAME || e->op.type == TOKEN_ARRAY) { |
670 if (root->resolve(root, e->op.v.str, out)) { | 810 debug_var *var = tern_find_ptr(root->variables, e->op.v.str); |
671 return 1; | 811 if (!var) { |
672 } | 812 return 0; |
673 tern_val v; | 813 } |
674 if (tern_find(root->variables, e->op.v.str, &v)) { | 814 *out = var->get(var); |
675 *out = v.intval; | 815 return 1; |
676 return 1; | |
677 } | |
678 if (tern_find(root->symbols, e->op.v.str, &v)) { | |
679 *out = v.intval; | |
680 return 1; | |
681 } | |
682 return 0; | |
683 } else { | 816 } else { |
684 *out = e->op.v.num; | 817 *out = debug_int(e->op.v.num); |
685 return 1; | 818 return 1; |
686 } | 819 } |
687 case EXPR_UNARY: | 820 case EXPR_UNARY: |
688 if (!eval_expr(root, e->left, out)) { | 821 if (!eval_expr(root, e->left, out)) { |
689 return 0; | 822 return 0; |
690 } | 823 } |
691 switch (e->op.v.op[0]) | 824 switch (e->op.v.op[0]) |
692 { | 825 { |
693 case '!': | 826 case '!': |
694 *out = !*out; | 827 if (out->type != DBG_VAL_U32) { fprintf(stderr, "operator ! is only defined for integers"); return 0; } |
828 out->v.u32 = !out->v.u32; | |
695 break; | 829 break; |
696 case '~': | 830 case '~': |
697 *out = ~*out; | 831 if (out->type != DBG_VAL_U32) { fprintf(stderr, "operator ~ is only defined for integers"); return 0; } |
832 out->v.u32 = ~out->v.u32; | |
698 break; | 833 break; |
699 case '-': | 834 case '-': |
700 *out = -*out; | 835 if (out->type == DBG_VAL_U32) { |
836 out->v.u32 = -out->v.u32; | |
837 } else if (out->type == DBG_VAL_F32) { | |
838 out->v.f32 = -out->v.f32; | |
839 } else { | |
840 fprintf(stderr, "operator ~ is only defined for integers and floats"); | |
841 return 0; | |
842 } | |
701 break; | 843 break; |
702 default: | 844 default: |
703 return 0; | 845 return 0; |
704 } | 846 } |
705 return 1; | 847 return 1; |
706 case EXPR_BINARY: | 848 case EXPR_BINARY: |
707 if (!eval_expr(root, e->left, out) || !eval_expr(root, e->right, &right)) { | 849 if (!eval_expr(root, e->left, out) || !eval_expr(root, e->right, &right)) { |
708 return 0; | 850 return 0; |
709 } | 851 } |
710 switch (e->op.v.op[0]) | 852 if (out->type != right.type) { |
711 { | 853 if (out->type == DBG_VAL_F32) { |
712 case '+': | 854 if (right.type == DBG_VAL_U32) { |
713 *out += right; | 855 right.type = DBG_VAL_F32; |
714 break; | 856 float v = right.v.u32; |
715 case '-': | 857 right.v.f32 = v; |
716 *out -= right; | 858 } else { |
717 break; | 859 fprintf(stderr, "Invalid type on right side of binary operator\n"); |
718 case '*': | 860 return 0; |
719 *out *= right; | 861 } |
720 break; | 862 } else if (out->type == DBG_VAL_U32) { |
721 case '/': | 863 if (right.type == DBG_VAL_F32) { |
722 *out /= right; | 864 out->type = DBG_VAL_F32; |
723 break; | 865 float v = out->v.u32; |
724 case '&': | 866 out->v.f32 = v; |
725 *out &= right; | 867 } else { |
726 break; | 868 fprintf(stderr, "Invalid type on right side of binary operator\n"); |
727 case '|': | 869 return 0; |
728 *out |= right; | 870 } |
729 break; | 871 } |
730 case '^': | 872 } |
731 *out ^= right; | 873 if (out->type == DBG_VAL_U32) { |
732 break; | 874 switch (e->op.v.op[0]) |
733 case '=': | 875 { |
734 *out = *out == right; | 876 case '+': |
735 break; | 877 out->v.u32 += right.v.u32; |
736 case '!': | 878 break; |
737 *out = *out != right; | 879 case '-': |
738 break; | 880 out->v.u32 -= right.v.u32; |
739 case '>': | 881 break; |
740 *out = e->op.v.op[1] ? *out >= right : *out > right; | 882 case '*': |
741 break; | 883 out->v.u32 *= right.v.u32; |
742 case '<': | 884 break; |
743 *out = e->op.v.op[1] ? *out <= right : *out < right; | 885 case '/': |
744 break; | 886 out->v.u32 /= right.v.u32; |
745 default: | 887 break; |
746 return 0; | 888 case '&': |
889 out->v.u32 &= right.v.u32; | |
890 break; | |
891 case '|': | |
892 out->v.u32 |= right.v.u32; | |
893 break; | |
894 case '^': | |
895 out->v.u32 ^= right.v.u32; | |
896 break; | |
897 case '=': | |
898 out->v.u32 = out->v.u32 == right.v.u32; | |
899 break; | |
900 case '!': | |
901 out->v.u32 = out->v.u32 != right.v.u32; | |
902 break; | |
903 case '>': | |
904 out->v.u32 = e->op.v.op[1] ? out->v.u32 >= right.v.u32 : out->v.u32 > right.v.u32; | |
905 break; | |
906 case '<': | |
907 out->v.u32 = e->op.v.op[1] ? out->v.u32 <= right.v.u32 : out->v.u32 < right.v.u32; | |
908 break; | |
909 default: | |
910 return 0; | |
911 } | |
912 } else if (out->type == DBG_VAL_F32) { | |
913 switch (e->op.v.op[0]) | |
914 { | |
915 case '+': | |
916 out->v.f32 += right.v.f32; | |
917 break; | |
918 case '-': | |
919 out->v.f32 -= right.v.f32; | |
920 break; | |
921 case '*': | |
922 out->v.f32 *= right.v.f32; | |
923 break; | |
924 case '/': | |
925 out->v.f32 /= right.v.f32; | |
926 break; | |
927 case '=': | |
928 out->v.u32 = out->v.f32 == right.v.f32; | |
929 out->type = DBG_VAL_U32; | |
930 break; | |
931 case '!': | |
932 out->v.u32 = out->v.f32 != right.v.f32; | |
933 out->type = DBG_VAL_U32; | |
934 break; | |
935 case '>': | |
936 out->v.u32 = e->op.v.op[1] ? out->v.f32 >= right.v.f32 : out->v.f32 > right.v.f32; | |
937 out->type = DBG_VAL_U32; | |
938 break; | |
939 case '<': | |
940 out->v.u32 = e->op.v.op[1] ? out->v.f32 <= right.v.f32 : out->v.f32 < right.v.f32; | |
941 out->type = DBG_VAL_U32; | |
942 break; | |
943 default: | |
944 return 0; | |
945 } | |
747 } | 946 } |
748 return 1; | 947 return 1; |
749 case EXPR_SIZE: | 948 case EXPR_SIZE: |
750 if (!eval_expr(root, e->left, out)) { | 949 if (!eval_expr(root, e->left, out)) { |
751 return 0; | 950 return 0; |
752 } | 951 } |
952 if (out->type != DBG_VAL_U32) { fprintf(stderr, "Size expressions are only defined for integers"); return 0; } | |
753 switch (e->op.v.op[0]) | 953 switch (e->op.v.op[0]) |
754 { | 954 { |
755 case 'b': | 955 case 'b': |
756 *out &= 0xFF; | 956 out->v.u32 &= 0xFF; |
757 break; | 957 break; |
758 case 'w': | 958 case 'w': |
759 *out &= 0xFFFF; | 959 out->v.u32 &= 0xFFFF; |
760 break; | 960 break; |
761 } | 961 } |
762 return 1; | 962 return 1; |
763 case EXPR_MEM: | 963 case EXPR_MEM: |
764 if (!eval_expr(root, e->left, out)) { | 964 if (!eval_expr(root, e->left, out)) { |
765 return 0; | 965 return 0; |
766 } | 966 } |
967 if (out->type != DBG_VAL_U32) { fprintf(stderr, "Array index must be integer"); return 0; } | |
767 if (e->right) { | 968 if (e->right) { |
768 debug_array *array = full_array_resolve(root, e->right->op.v.str); | 969 if (!eval_expr(root, e->right, &right)) { |
769 if (!array || *out >= array->size) { | |
770 return 0; | 970 return 0; |
771 } | 971 } |
772 *out = array->get(root, array, *out); | 972 debug_array *array = get_array(right); |
973 if (!array) { | |
974 fprintf(stderr, "Attempt to index into value that is not an array"); | |
975 return 0; | |
976 } | |
977 if (out->v.u32 >= array->size) { | |
978 return 0; | |
979 } | |
980 *out = array->get(array, out->v.u32); | |
773 return 1; | 981 return 1; |
774 } | 982 } |
775 return root->read_mem(root, out, e->op.v.op[0]); | 983 return root->read_mem(root, &out->v.u32, e->op.v.op[0]); |
984 case EXPR_NAMESPACE: | |
985 root = tern_find_ptr(root->other_roots, e->op.v.str); | |
986 if (!root) { | |
987 fprintf(stderr, "%s is not a valid namespace\n", e->op.v.str); | |
988 return 0; | |
989 } | |
990 return eval_expr(root, e->left, out); | |
776 default: | 991 default: |
777 return 0; | 992 return 0; |
778 } | 993 } |
779 } | 994 } |
780 | 995 |
857 write_word(address, value, (void **)context->mem_pointers, &context->options->gen, context); | 1072 write_word(address, value, (void **)context->mem_pointers, &context->options->gen, context); |
858 } | 1073 } |
859 return 1; | 1074 return 1; |
860 } | 1075 } |
861 | 1076 |
862 static uint8_t resolve_m68k(debug_root *root, const char *name, uint32_t *out) | 1077 static uint8_t debug_cast_int(debug_val val, uint32_t *out) |
863 { | 1078 { |
864 m68k_context *context = root->cpu_context; | 1079 if (val.type == DBG_VAL_U32) { |
865 if ((name[0] == 'd' || name[0] == 'D') && name[1] >= '0' && name[1] <= '7' && !name[2]) { | 1080 *out = val.v.u32; |
866 *out = context->dregs[name[1]-'0']; | |
867 } else if ((name[0] == 'a' || name[0] == 'A') && name[1] >= '0' && name[1] <= '7' && !name[2]) { | |
868 *out = context->aregs[name[1]-'0']; | |
869 } else if (!strcasecmp(name, "sr")) { | |
870 *out = context->status << 8; | |
871 for (int flag = 0; flag < 5; flag++) { | |
872 *out |= context->flags[flag] << (4-flag); | |
873 } | |
874 } else if(!strcasecmp(name, "cycle")) { | |
875 *out = context->current_cycle; | |
876 } else if (!strcasecmp(name, "pc")) { | |
877 *out = root->address; | |
878 } else if (!strcasecmp(name, "sp")) { | |
879 *out = context->aregs[7]; | |
880 } else if (!strcasecmp(name, "usp")) { | |
881 *out = context->status & 0x20 ? context->aregs[8] : context->aregs[7]; | |
882 } else if (!strcasecmp(name, "ssp")) { | |
883 *out = context->status & 0x20 ? context->aregs[7] : context->aregs[8]; | |
884 } else { | |
885 return 0; | |
886 } | |
887 return 1; | |
888 } | |
889 | |
890 static uint8_t set_m68k(debug_root *root, const char *name, uint32_t value) | |
891 { | |
892 m68k_context *context = root->cpu_context; | |
893 if ((name[0] == 'd' || name[0] == 'D') && name[1] >= '0' && name[1] <= '7' && !name[2]) { | |
894 context->dregs[name[1]-'0'] = value; | |
895 } else if ((name[0] == 'a' || name[0] == 'A') && name[1] >= '0' && name[1] <= '7' && !name[2]) { | |
896 context->aregs[name[1]-'0'] = value; | |
897 } else if (!strcasecmp(name, "sr")) { | |
898 context->status = value >> 8; | |
899 for (int flag = 0; flag < 5; flag++) { | |
900 context->flags[flag] = (value & (1 << (4 - flag))) != 0; | |
901 } | |
902 } else if (!strcasecmp(name, "sp")) { | |
903 context->aregs[7] = value; | |
904 } else if (!strcasecmp(name, "usp")) { | |
905 context->aregs[context->status & 0x20 ? 8 : 7] = value; | |
906 } else if (!strcasecmp(name, "ssp")) { | |
907 context->aregs[context->status & 0x20 ? 7 : 8] = value; | |
908 } else { | |
909 return 0; | |
910 } | |
911 return 1; | |
912 } | |
913 | |
914 static uint8_t resolve_vdp(debug_root *root, const char *name, uint32_t *out) | |
915 { | |
916 m68k_context *m68k = root->cpu_context; | |
917 genesis_context *gen = m68k->system; | |
918 vdp_context *vdp = gen->vdp; | |
919 if (!strcasecmp(name, "vcounter")) { | |
920 *out = vdp->vcounter; | |
921 } else if (!strcasecmp(name, "hcounter")) { | |
922 *out = vdp->hslot; | |
923 } else if (!strcasecmp(name, "address")) { | |
924 *out = vdp->address; | |
925 }else if (!strcasecmp(name, "cd")) { | |
926 *out = vdp->cd; | |
927 } else if (!strcasecmp(name, "status")) { | |
928 *out = vdp_status(vdp); | |
929 } else { | |
930 return 0; | |
931 } | |
932 return 1; | |
933 } | |
934 | |
935 static uint8_t resolve_genesis(debug_root *root, const char *name, uint32_t *out) | |
936 { | |
937 | |
938 for (const char *cur = name; *cur; ++cur) | |
939 { | |
940 if (*cur == ':') { | |
941 if (cur - name == 3 && !memcmp(name, "vdp", 3)) { | |
942 return resolve_vdp(root, cur + 1, out); | |
943 } else if (cur - name == 3 && !memcmp(name, "sub", 3)) { | |
944 m68k_context *m68k = root->cpu_context; | |
945 genesis_context *gen = m68k->system; | |
946 if (gen->expansion) { | |
947 segacd_context *cd = gen->expansion; | |
948 root = find_m68k_root(cd->m68k); | |
949 return root->resolve(root, cur + 1, out); | |
950 } else { | |
951 return 0; | |
952 } | |
953 } else { | |
954 return 0; | |
955 } | |
956 } | |
957 } | |
958 if (resolve_m68k(root, name, out)) { | |
959 return 1; | 1081 return 1; |
960 } | 1082 } |
961 m68k_context *m68k = root->cpu_context; | 1083 if (val.type == DBG_VAL_F32) { |
962 genesis_context *gen = m68k->system; | 1084 *out = val.v.f32; |
963 if (!strcmp(name, "f") || !strcmp(name, "frame")) { | |
964 *out = gen->vdp->frame; | |
965 return 1; | 1085 return 1; |
966 } | 1086 } |
967 return 0; | 1087 return 0; |
968 } | 1088 } |
969 | 1089 |
970 static uint32_t debug_vram_get(debug_root *root, debug_array *array, uint32_t index) | 1090 static uint8_t debug_cast_bool(debug_val val) |
971 { | 1091 { |
972 m68k_context *m68k = root->cpu_context; | 1092 switch(val.type) |
973 genesis_context *gen = m68k->system; | 1093 { |
974 return gen->vdp->vdpmem[index]; | 1094 case DBG_VAL_U32: return val.v.u32 != 0; |
975 } | 1095 case DBG_VAL_F32: return val.v.f32 != 0.0f; |
976 | 1096 case DBG_VAL_ARRAY: return get_array(val)->size != 0; |
977 static void debug_vram_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1097 default: return 1; |
978 { | 1098 } |
979 m68k_context *m68k = root->cpu_context; | 1099 } |
980 genesis_context *gen = m68k->system; | 1100 |
981 gen->vdp->vdpmem[index] = value; | 1101 static debug_val m68k_dreg_get(debug_var *var) |
982 } | 1102 { |
983 | 1103 m68k_context *context = var->ptr; |
984 static uint32_t debug_vsram_get(debug_root *root, debug_array *array, uint32_t index) | 1104 return debug_int(context->dregs[var->val.v.u32]); |
985 { | 1105 } |
986 m68k_context *m68k = root->cpu_context; | 1106 |
987 genesis_context *gen = m68k->system; | 1107 static void m68k_dreg_set(debug_var *var, debug_val val) |
988 return gen->vdp->vsram[index] & VSRAM_BITS; | 1108 { |
989 } | 1109 m68k_context *context = var->ptr; |
990 | 1110 uint32_t ival; |
991 static void debug_vsram_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1111 if (!debug_cast_int(val, &ival)) { |
992 { | 1112 fprintf(stderr, "M68K register d%d can only be set to an integer\n", var->val.v.u32); |
993 m68k_context *m68k = root->cpu_context; | 1113 return; |
994 genesis_context *gen = m68k->system; | 1114 } |
995 gen->vdp->vsram[index] = value; | 1115 context->dregs[var->val.v.u32] = ival; |
996 } | 1116 } |
997 | 1117 |
998 static uint32_t debug_cram_get(debug_root *root, debug_array *array, uint32_t index) | 1118 static debug_val m68k_areg_get(debug_var *var) |
999 { | 1119 { |
1000 m68k_context *m68k = root->cpu_context; | 1120 m68k_context *context = var->ptr; |
1001 genesis_context *gen = m68k->system; | 1121 return debug_int(context->aregs[var->val.v.u32]); |
1002 return gen->vdp->cram[index] & CRAM_BITS; | 1122 } |
1003 } | 1123 |
1004 | 1124 static void m68k_areg_set(debug_var *var, debug_val val) |
1005 static void debug_cram_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1125 { |
1006 { | 1126 m68k_context *context = var->ptr; |
1007 m68k_context *m68k = root->cpu_context; | 1127 uint32_t ival; |
1008 genesis_context *gen = m68k->system; | 1128 if (!debug_cast_int(val, &ival)) { |
1009 gen->vdp->cram[index] = value; | 1129 fprintf(stderr, "M68K register a%d can only be set to an integer\n", var->val.v.u32); |
1010 } | 1130 return; |
1011 | 1131 } |
1012 static uint32_t debug_vreg_get(debug_root *root, debug_array *array, uint32_t index) | 1132 context->aregs[var->val.v.u32] = ival; |
1013 { | 1133 } |
1014 m68k_context *m68k = root->cpu_context; | 1134 |
1015 genesis_context *gen = m68k->system; | 1135 static debug_val m68k_sr_get(debug_var *var) |
1016 return gen->vdp->regs[index]; | 1136 { |
1017 } | 1137 m68k_context *context = var->ptr; |
1018 | 1138 debug_val ret; |
1019 static void debug_vreg_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1139 ret.v.u32 = context->status << 8; |
1020 { | 1140 for (int flag = 0; flag < 5; flag++) |
1021 m68k_context *m68k = root->cpu_context; | 1141 { |
1022 genesis_context *gen = m68k->system; | 1142 ret.v.u32 |= context->flags[flag] << (4-flag); |
1023 vdp_reg_write(gen->vdp, index, value); | 1143 } |
1024 } | 1144 ret.type = DBG_VAL_U32; |
1025 | 1145 return ret; |
1026 static debug_array* resolve_vdp_array(debug_root *root, const char *name) | 1146 } |
1027 { | 1147 |
1028 static debug_array vram = { | 1148 static void m68k_sr_set(debug_var *var, debug_val val) |
1029 .get = debug_vram_get, .set = debug_vram_set, | 1149 { |
1030 .size = VRAM_SIZE, .storage = VRAM_SIZE | 1150 m68k_context *context = var->ptr; |
1031 }; | 1151 uint32_t ival; |
1032 static debug_array vsram = { | 1152 if (!debug_cast_int(val, &ival)) { |
1033 .get = debug_vsram_get, .set = debug_vsram_set, | 1153 fprintf(stderr, "M68K register sr can only be set to an integer\n"); |
1034 }; | 1154 return; |
1035 static debug_array cram = { | 1155 } |
1036 .get = debug_cram_get, .set = debug_cram_set, | 1156 context->status = ival >> 8; |
1037 .storage = CRAM_SIZE, .size = CRAM_SIZE | 1157 for (int flag = 0; flag < 5; flag++) { |
1038 }; | 1158 context->flags[flag] = (ival & (1 << (4 - flag))) != 0; |
1039 static debug_array regs = { | 1159 } |
1040 .get = debug_vreg_get, .set = debug_vreg_set, | 1160 } |
1041 .storage = VDP_REGS, .size = VDP_REGS | 1161 |
1042 }; | 1162 static debug_val m68k_cycle_get(debug_var *var) |
1043 if (!strcasecmp(name, "vram")) { | 1163 { |
1044 return &vram; | 1164 m68k_context *context = var->ptr; |
1045 } | 1165 return debug_int(context->current_cycle); |
1046 if (!strcasecmp(name, "vsram")) { | 1166 } |
1047 m68k_context *m68k = root->cpu_context; | 1167 |
1048 genesis_context *gen = m68k->system; | 1168 static debug_val m68k_usp_get(debug_var *var) |
1049 vsram.storage = vsram.size = gen->vdp->vsram_size; | 1169 { |
1050 return &vsram; | 1170 m68k_context *context = var->ptr; |
1051 } | 1171 return debug_int(context->status & 0x20 ? context->aregs[8] : context->aregs[7]); |
1052 if (!strcasecmp(name, "cram")) { | 1172 } |
1053 return &cram; | 1173 |
1054 } | 1174 static void m68k_usp_set(debug_var *var, debug_val val) |
1055 if (!strcasecmp(name, "reg")) { | 1175 { |
1056 return ®s; | 1176 m68k_context *context = var->ptr; |
1057 } | 1177 uint32_t ival; |
1058 return NULL; | 1178 if (!debug_cast_int(val, &ival)) { |
1059 } | 1179 fprintf(stderr, "M68K register usp can only be set to an integer\n"); |
1060 | 1180 return; |
1061 static uint32_t debug_part1_get(debug_root *root, debug_array *array, uint32_t index) | 1181 } |
1062 { | 1182 context->aregs[context->status & 0x20 ? 8 : 7] = ival; |
1063 m68k_context *m68k = root->cpu_context; | 1183 } |
1064 genesis_context *gen = m68k->system; | 1184 |
1065 return gen->ym->part1_regs[index]; | 1185 static debug_val m68k_ssp_get(debug_var *var) |
1066 } | 1186 { |
1067 | 1187 m68k_context *context = var->ptr; |
1068 static void debug_part1_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1188 return debug_int(context->status & 0x20 ? context->aregs[7] : context->aregs[8]); |
1069 { | 1189 } |
1070 m68k_context *m68k = root->cpu_context; | 1190 |
1071 genesis_context *gen = m68k->system; | 1191 static void m68k_ssp_set(debug_var *var, debug_val val) |
1072 uint8_t old_part = gen->ym->selected_part; | 1192 { |
1073 uint8_t old_reg = gen->ym->selected_reg; | 1193 m68k_context *context = var->ptr; |
1074 gen->ym->selected_part = 0; | 1194 uint32_t ival; |
1075 gen->ym->selected_reg = index; | 1195 if (!debug_cast_int(val, &ival)) { |
1076 ym_data_write(gen->ym, value); | 1196 fprintf(stderr, "M68K register ssp can only be set to an integer\n"); |
1077 gen->ym->selected_part = old_part; | 1197 return; |
1078 gen->ym->selected_reg = old_reg; | 1198 } |
1079 } | 1199 context->aregs[context->status & 0x20 ? 7 : 8] = ival; |
1080 | 1200 } |
1081 static uint32_t debug_part2_get(debug_root *root, debug_array *array, uint32_t index) | 1201 |
1082 { | 1202 static debug_val root_address_get(debug_var *var) |
1083 m68k_context *m68k = root->cpu_context; | 1203 { |
1084 genesis_context *gen = m68k->system; | 1204 debug_root *root = var->ptr; |
1085 return gen->ym->part2_regs[index]; | 1205 return debug_int(root->address); |
1086 } | 1206 } |
1087 | 1207 |
1088 static void debug_part2_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1208 static void m68k_names(debug_root *root) |
1089 { | 1209 { |
1090 m68k_context *m68k = root->cpu_context; | 1210 debug_var *var; |
1091 genesis_context *gen = m68k->system; | 1211 for (char i = 0; i < 8; i++) |
1092 uint8_t old_part = gen->ym->selected_part; | 1212 { |
1093 uint8_t old_reg = gen->ym->selected_reg; | 1213 char rname[3] = {'d', '0' + i, 0}; |
1094 gen->ym->selected_part = 1; | 1214 var = calloc(1, sizeof(debug_var)); |
1095 gen->ym->selected_reg = index; | 1215 var->get = m68k_dreg_get; |
1096 ym_data_write(gen->ym, value); | 1216 var->set = m68k_dreg_set; |
1097 gen->ym->selected_part = old_part; | 1217 var->ptr = root->cpu_context; |
1098 gen->ym->selected_reg = old_reg; | 1218 var->val.v.u32 = i; |
1099 } | 1219 root->variables = tern_insert_ptr(root->variables, rname, var); |
1100 | 1220 rname[0] = 'D'; |
1101 static debug_array* resolve_ym2612_array(debug_root *root, const char *name) | 1221 root->variables = tern_insert_ptr(root->variables, rname, var); |
1102 { | 1222 |
1103 static debug_array part1 = { | 1223 var = calloc(1, sizeof(debug_var)); |
1104 .get = debug_part1_get, .set = debug_part1_set, | 1224 var->get = m68k_areg_get; |
1105 .storage = YM_REG_END, .size = YM_REG_END | 1225 var->set = m68k_areg_set; |
1106 }; | 1226 var->ptr = root->cpu_context; |
1107 static debug_array part2 = { | 1227 var->val.v.u32 = i; |
1108 .get = debug_part2_get, .set = debug_part2_set, | 1228 rname[0] = 'a'; |
1109 .storage = YM_REG_END, .size = YM_REG_END | 1229 root->variables = tern_insert_ptr(root->variables, rname, var); |
1110 }; | 1230 rname[0] = 'A'; |
1111 if (!strcasecmp(name, "part1")) { | 1231 root->variables = tern_insert_ptr(root->variables, rname, var); |
1112 return &part1; | 1232 if (i == 7) { |
1113 } | 1233 root->variables = tern_insert_ptr(root->variables, "sp", var); |
1114 if (!strcasecmp(name, "part2")) { | 1234 root->variables = tern_insert_ptr(root->variables, "SP", var); |
1115 return &part2; | 1235 } |
1116 } | 1236 } |
1117 return NULL; | 1237 |
1118 } | 1238 var = calloc(1, sizeof(debug_var)); |
1119 | 1239 var->get = m68k_sr_get; |
1120 static uint32_t debug_psgfreq_get(debug_root *root, debug_array *array, uint32_t index) | 1240 var->set = m68k_sr_set; |
1121 { | 1241 var->ptr = root->cpu_context; |
1122 m68k_context *m68k = root->cpu_context; | 1242 root->variables = tern_insert_ptr(root->variables, "sr", var); |
1123 genesis_context *gen = m68k->system; | 1243 root->variables = tern_insert_ptr(root->variables, "SR", var); |
1124 return gen->psg->counter_load[index]; | 1244 |
1125 } | 1245 var = calloc(1, sizeof(debug_var)); |
1126 | 1246 var->get = root_address_get; |
1127 static void debug_psgfreq_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1247 var->ptr = root; |
1128 { | 1248 root->variables = tern_insert_ptr(root->variables, "pc", var); |
1129 m68k_context *m68k = root->cpu_context; | 1249 root->variables = tern_insert_ptr(root->variables, "PC", var); |
1130 genesis_context *gen = m68k->system; | 1250 |
1131 gen->psg->counter_load[index] = value; | 1251 var = calloc(1, sizeof(debug_var)); |
1132 } | 1252 var->get = m68k_usp_get; |
1133 | 1253 var->set = m68k_usp_set; |
1134 static uint32_t debug_psgcount_get(debug_root *root, debug_array *array, uint32_t index) | 1254 var->ptr = root->cpu_context; |
1135 { | 1255 root->variables = tern_insert_ptr(root->variables, "usp", var); |
1136 m68k_context *m68k = root->cpu_context; | 1256 root->variables = tern_insert_ptr(root->variables, "USP", var); |
1137 genesis_context *gen = m68k->system; | 1257 |
1138 return gen->psg->counters[index]; | 1258 var = calloc(1, sizeof(debug_var)); |
1139 } | 1259 var->get = m68k_ssp_get; |
1140 | 1260 var->set = m68k_ssp_set; |
1141 static void debug_psgcount_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1261 var->ptr = root->cpu_context; |
1142 { | 1262 root->variables = tern_insert_ptr(root->variables, "ssp", var); |
1143 m68k_context *m68k = root->cpu_context; | 1263 root->variables = tern_insert_ptr(root->variables, "SSP", var); |
1144 genesis_context *gen = m68k->system; | 1264 |
1145 gen->psg->counters[index] = value; | 1265 var = calloc(1, sizeof(debug_var)); |
1146 } | 1266 var->get = m68k_cycle_get; |
1147 | 1267 var->ptr = root->cpu_context; |
1148 static uint32_t debug_psgvol_get(debug_root *root, debug_array *array, uint32_t index) | 1268 root->variables = tern_insert_ptr(root->variables, "cycle", var); |
1149 { | 1269 } |
1150 m68k_context *m68k = root->cpu_context; | 1270 |
1151 genesis_context *gen = m68k->system; | 1271 static debug_val vcounter_get(debug_var *var) |
1152 return gen->psg->volume[index]; | 1272 { |
1153 } | 1273 vdp_context *vdp = var->ptr; |
1154 | 1274 return debug_int(vdp->vcounter); |
1155 static void debug_psgvol_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | 1275 } |
1156 { | 1276 |
1157 m68k_context *m68k = root->cpu_context; | 1277 static debug_val hcounter_get(debug_var *var) |
1158 genesis_context *gen = m68k->system; | 1278 { |
1159 gen->psg->volume[index] = value; | 1279 vdp_context *vdp = var->ptr; |
1160 } | 1280 return debug_int(vdp->hslot); |
1161 | 1281 } |
1162 static debug_array* resolve_psg_array(debug_root *root, const char *name) | 1282 |
1163 { | 1283 static debug_val vdp_address_get(debug_var *var) |
1164 static debug_array freq = { | 1284 { |
1165 .get = debug_psgfreq_get, .set = debug_psgfreq_set, | 1285 vdp_context *vdp = var->ptr; |
1166 .storage = 4, .size = 4 | 1286 return debug_int(vdp->address); |
1167 }; | 1287 } |
1168 static debug_array counter = { | 1288 |
1169 .get = debug_psgcount_get, .set = debug_psgcount_set, | 1289 static void vdp_address_set(debug_var *var, debug_val val) |
1170 .storage = 4, .size = 4 | 1290 { |
1171 }; | 1291 vdp_context *vdp = var->ptr; |
1172 static debug_array volume = { | 1292 uint32_t ival; |
1173 .get = debug_psgvol_get, .set = debug_psgvol_set, | 1293 if (!debug_cast_int(val, &ival)) { |
1174 .storage = 4, .size = 4 | 1294 fprintf(stderr, "vdp address can only be set to an integer\n"); |
1175 }; | 1295 return; |
1176 if (!strcasecmp("frequency", name)) { | 1296 } |
1177 return &freq; | 1297 vdp->address = ival & 0x1FFFF; |
1178 } | 1298 } |
1179 if (!strcasecmp("counter", name)) { | 1299 |
1180 return &counter; | 1300 static debug_val vdp_cd_get(debug_var *var) |
1181 } | 1301 { |
1182 if (!strcasecmp("volume", name)) { | 1302 vdp_context *vdp = var->ptr; |
1183 return &volume; | 1303 return debug_int(vdp->cd); |
1184 } | 1304 } |
1185 return NULL; | 1305 |
1186 } | 1306 static void vdp_cd_set(debug_var *var, debug_val val) |
1187 | 1307 { |
1188 static debug_array* resolve_genesis_array(debug_root *root, const char *name) | 1308 vdp_context *vdp = var->ptr; |
1189 { | 1309 uint32_t ival; |
1190 for (const char *cur = name; *cur; ++cur) | 1310 if (!debug_cast_int(val, &ival)) { |
1191 { | 1311 fprintf(stderr, "vdp cd can only be set to an integer\n"); |
1192 if (*cur == ':') { | 1312 return; |
1193 if (cur - name == 3 && !memcmp(name, "vdp", 3)) { | 1313 } |
1194 return resolve_vdp_array(root, cur + 1); | 1314 vdp->cd = ival & 0x3F; |
1195 } else if (cur - name == 2 && !memcmp(name, "ym", 2)) { | 1315 } |
1196 return resolve_ym2612_array(root, cur + 1); | 1316 |
1197 } else if (cur - name == 3 && !memcmp(name, "psg", 3)) { | 1317 static debug_val vdp_status_get(debug_var *var) |
1198 return resolve_psg_array(root, cur + 1); | 1318 { |
1199 } /*else if (cur - name == 3 && !memcmp(name, "sub", 3)) { | 1319 vdp_context *vdp = var->ptr; |
1200 m68k_context *m68k = root->cpu_context; | 1320 return debug_int(vdp_status(vdp)); |
1201 genesis_context *gen = m68k->system; | 1321 } |
1202 if (gen->expansion) { | 1322 |
1203 segacd_context *cd = gen->expansion; | 1323 static debug_val debug_vram_get(debug_array *array, uint32_t index) |
1204 root = find_m68k_root(cd->m68k); | 1324 { |
1205 return root->resolve(root, cur + 1, out); | 1325 vdp_context *vdp = array->base; |
1206 } else { | 1326 return debug_int(vdp->vdpmem[index]); |
1207 return NULL; | 1327 } |
1208 } | 1328 |
1209 }*/ else { | 1329 static void debug_vram_set(debug_array *array, uint32_t index, debug_val val) |
1210 return NULL; | 1330 { |
1211 } | 1331 uint32_t ival; |
1212 } | 1332 if (!debug_cast_int(val, &ival)) { |
1213 } | 1333 fprintf(stderr, "vram can only be set to integers\n"); |
1214 return NULL; | 1334 return; |
1215 } | 1335 } |
1216 | 1336 vdp_context *vdp = array->base; |
1217 static debug_array* resolve_null_array(debug_root *root, const char *name) | 1337 vdp->vdpmem[index] = ival; |
1218 { | 1338 } |
1219 return NULL; | 1339 |
1340 static debug_val debug_vsram_get(debug_array *array, uint32_t index) | |
1341 { | |
1342 vdp_context *vdp = array->base; | |
1343 return debug_int(vdp->vsram[index] & VSRAM_BITS); | |
1344 } | |
1345 | |
1346 static void debug_vsram_set(debug_array *array, uint32_t index, debug_val val) | |
1347 { | |
1348 uint32_t ival; | |
1349 if (!debug_cast_int(val, &ival)) { | |
1350 fprintf(stderr, "vsram can only be set to integers\n"); | |
1351 return; | |
1352 } | |
1353 vdp_context *vdp = array->base; | |
1354 vdp->vsram[index] = ival; | |
1355 } | |
1356 | |
1357 static debug_val debug_cram_get(debug_array *array, uint32_t index) | |
1358 { | |
1359 vdp_context *vdp = array->base; | |
1360 return debug_int(vdp->cram[index] & CRAM_BITS); | |
1361 } | |
1362 | |
1363 static void debug_cram_set(debug_array *array, uint32_t index, debug_val val) | |
1364 { | |
1365 uint32_t ival; | |
1366 if (!debug_cast_int(val, &ival)) { | |
1367 fprintf(stderr, "cram can only be set to integers\n"); | |
1368 return; | |
1369 } | |
1370 vdp_context *vdp = array->base; | |
1371 vdp->cram[index] = ival; | |
1372 } | |
1373 | |
1374 static debug_val debug_vreg_get(debug_array *array, uint32_t index) | |
1375 { | |
1376 vdp_context *vdp = array->base; | |
1377 return debug_int(vdp->regs[index]); | |
1378 } | |
1379 | |
1380 static void debug_vreg_set(debug_array *array, uint32_t index, debug_val val) | |
1381 { | |
1382 vdp_context *vdp = array->base; | |
1383 uint32_t ival; | |
1384 if (!debug_cast_int(val, &ival)) { | |
1385 fprintf(stderr, "vdp registers can only be set to integers\n"); | |
1386 return; | |
1387 } | |
1388 vdp_reg_write(vdp, index, ival); | |
1389 } | |
1390 | |
1391 static debug_root* find_vdp_root(vdp_context *context) | |
1392 { | |
1393 debug_root *root = find_root(context); | |
1394 debug_var *var = calloc(1, sizeof(debug_var)); | |
1395 var->get = vcounter_get; | |
1396 var->ptr = context; | |
1397 root->variables = tern_insert_ptr(root->variables, "vcounter", var); | |
1398 | |
1399 var = calloc(1, sizeof(debug_var)); | |
1400 var->get = hcounter_get; | |
1401 var->ptr = context; | |
1402 root->variables = tern_insert_ptr(root->variables, "hcounter", var); | |
1403 | |
1404 var = calloc(1, sizeof(debug_var)); | |
1405 var->get = vdp_address_get; | |
1406 var->set = vdp_address_set; | |
1407 var->ptr = context; | |
1408 root->variables = tern_insert_ptr(root->variables, "address", var); | |
1409 | |
1410 var = calloc(1, sizeof(debug_var)); | |
1411 var->get = vdp_cd_get; | |
1412 var->set = vdp_cd_set; | |
1413 var->ptr = context; | |
1414 root->variables = tern_insert_ptr(root->variables, "cd", var); | |
1415 | |
1416 new_readonly_variable(root, "vram", new_fixed_array(context, debug_vram_get, debug_vram_set, VRAM_SIZE)); | |
1417 new_readonly_variable(root, "vsram", new_fixed_array(context, debug_vsram_get, debug_vsram_set, context->vsram_size)); | |
1418 new_readonly_variable(root, "cram", new_fixed_array(context, debug_cram_get, debug_cram_set, CRAM_SIZE)); | |
1419 new_readonly_variable(root, "reg", new_fixed_array(context, debug_vreg_get, debug_vreg_set, VDP_REGS)); | |
1420 | |
1421 return root; | |
1422 } | |
1423 | |
1424 static debug_val debug_part1_get(debug_array *array, uint32_t index) | |
1425 { | |
1426 ym2612_context *ym = array->base; | |
1427 return debug_int(ym->part1_regs[index]); | |
1428 } | |
1429 | |
1430 static void debug_part1_set(debug_array *array, uint32_t index, debug_val val) | |
1431 { | |
1432 uint32_t ival; | |
1433 if (!debug_cast_int(val, &ival)) { | |
1434 fprintf(stderr, "ym2612 registers can only be set to integers\n"); | |
1435 return; | |
1436 } | |
1437 ym2612_context *ym = array->base; | |
1438 uint8_t old_part = ym->selected_part; | |
1439 uint8_t old_reg = ym->selected_reg; | |
1440 ym->selected_part = 0; | |
1441 ym->selected_reg = index; | |
1442 ym_data_write(ym, ival); | |
1443 ym->selected_part = old_part; | |
1444 ym->selected_reg = old_reg; | |
1445 } | |
1446 | |
1447 static debug_val debug_part2_get(debug_array *array, uint32_t index) | |
1448 { | |
1449 ym2612_context *ym = array->base; | |
1450 return debug_int(ym->part2_regs[index]); | |
1451 } | |
1452 | |
1453 static void debug_part2_set(debug_array *array, uint32_t index, debug_val val) | |
1454 { | |
1455 uint32_t ival; | |
1456 if (!debug_cast_int(val, &ival)) { | |
1457 fprintf(stderr, "ym2612 registers can only be set to integers\n"); | |
1458 return; | |
1459 } | |
1460 ym2612_context *ym = array->base; | |
1461 uint8_t old_part = ym->selected_part; | |
1462 uint8_t old_reg = ym->selected_reg; | |
1463 ym->selected_part = 1; | |
1464 ym->selected_reg = index; | |
1465 ym_data_write(ym, ival); | |
1466 ym->selected_part = old_part; | |
1467 ym->selected_reg = old_reg; | |
1468 } | |
1469 | |
1470 static debug_root* find_ym2612_root(ym2612_context *context) | |
1471 { | |
1472 debug_root *root = find_root(context); | |
1473 | |
1474 new_readonly_variable(root, "part1", new_fixed_array(context, debug_part1_get, debug_part1_set, YM_REG_END)); | |
1475 new_readonly_variable(root, "part2", new_fixed_array(context, debug_part2_get, debug_part2_set, YM_REG_END)); | |
1476 | |
1477 return root; | |
1478 } | |
1479 | |
1480 | |
1481 static debug_val debug_psgfreq_get(debug_array *array, uint32_t index) | |
1482 { | |
1483 psg_context *psg = array->base; | |
1484 return debug_int(psg->counter_load[index]); | |
1485 } | |
1486 | |
1487 static void debug_psgfreq_set(debug_array *array, uint32_t index, debug_val val) | |
1488 { | |
1489 uint32_t ival; | |
1490 if (!debug_cast_int(val, &ival)) { | |
1491 fprintf(stderr, "psg registers can only be set to integers\n"); | |
1492 return; | |
1493 } | |
1494 psg_context *psg = array->base; | |
1495 psg->counter_load[index] = ival; | |
1496 } | |
1497 | |
1498 static debug_val debug_psgcount_get(debug_array *array, uint32_t index) | |
1499 { | |
1500 psg_context *psg = array->base; | |
1501 return debug_int(psg->counters[index]); | |
1502 } | |
1503 | |
1504 static void debug_psgcount_set(debug_array *array, uint32_t index, debug_val val) | |
1505 { | |
1506 uint32_t ival; | |
1507 if (!debug_cast_int(val, &ival)) { | |
1508 fprintf(stderr, "psg registers can only be set to integers\n"); | |
1509 return; | |
1510 } | |
1511 psg_context *psg = array->base; | |
1512 psg->counters[index] = ival; | |
1513 } | |
1514 | |
1515 static debug_val debug_psgvol_get(debug_array *array, uint32_t index) | |
1516 { | |
1517 psg_context *psg = array->base; | |
1518 return debug_int(psg->volume[index]); | |
1519 } | |
1520 | |
1521 static void debug_psgvol_set(debug_array *array, uint32_t index, debug_val val) | |
1522 { | |
1523 uint32_t ival; | |
1524 if (!debug_cast_int(val, &ival)) { | |
1525 fprintf(stderr, "psg registers can only be set to integers\n"); | |
1526 return; | |
1527 } | |
1528 psg_context *psg = array->base; | |
1529 psg->volume[index] = ival; | |
1530 } | |
1531 | |
1532 debug_root *find_psg_root(psg_context *psg) | |
1533 { | |
1534 debug_root *root = find_root(psg); | |
1535 | |
1536 new_readonly_variable(root, "frequency", new_fixed_array(psg, debug_psgfreq_get, debug_psgfreq_set, 4)); | |
1537 new_readonly_variable(root, "counter", new_fixed_array(psg, debug_psgcount_get, debug_psgcount_set, 4)); | |
1538 new_readonly_variable(root, "volume", new_fixed_array(psg, debug_psgvol_get, debug_psgvol_set, 4)); | |
1539 | |
1540 return root; | |
1220 } | 1541 } |
1221 | 1542 |
1222 void ambiguous_iter(char *key, tern_val val, uint8_t valtype, void *data) | 1543 void ambiguous_iter(char *key, tern_val val, uint8_t valtype, void *data) |
1223 { | 1544 { |
1224 char *prefix = data; | 1545 char *prefix = data; |
1658 fprintf(stderr, "Unrecognized format character: %c\n", format[0]); | 1979 fprintf(stderr, "Unrecognized format character: %c\n", format[0]); |
1659 } | 1980 } |
1660 } | 1981 } |
1661 } | 1982 } |
1662 | 1983 |
1663 static void do_print(debug_root *root, char *format_str, char *raw, uint32_t value) | 1984 static void do_print(debug_root *root, char *format_str, char *raw, debug_val value) |
1664 { | 1985 { |
1665 if (format_str[5] == 's') { | 1986 switch(value.type) |
1666 char tmp[128]; | 1987 { |
1667 int j; | 1988 case DBG_VAL_U32: |
1668 uint32_t addr = value; | 1989 if (format_str[5] == 's') { |
1669 for (j = 0; j < sizeof(tmp)-1; j++, addr++) | 1990 char tmp[128]; |
1670 { | 1991 int j; |
1671 uint32_t tmp_addr = addr; | 1992 uint32_t addr = value.v.u32; |
1672 root->read_mem(root, &tmp_addr, 'b'); | 1993 for (j = 0; j < sizeof(tmp)-1; j++, addr++) |
1673 char c = tmp_addr; | 1994 { |
1674 if (c < 0x20 || c > 0x7F) { | 1995 uint32_t tmp_addr = addr; |
1675 break; | 1996 root->read_mem(root, &tmp_addr, 'b'); |
1676 } | 1997 char c = tmp_addr; |
1677 tmp[j] = c; | 1998 if (c < 0x20 || c > 0x7F) { |
1678 } | 1999 break; |
1679 tmp[j] = 0; | 2000 } |
1680 printf(format_str, raw, tmp); | 2001 tmp[j] = c; |
1681 } else { | 2002 } |
1682 printf(format_str, raw, value); | 2003 tmp[j] = 0; |
2004 printf(format_str, raw, tmp); | |
2005 } else { | |
2006 printf(format_str, raw, value.v.u32); | |
2007 } | |
2008 break; | |
2009 case DBG_VAL_F32: { | |
2010 char tmp = format_str[5]; | |
2011 format_str[5] = 'f'; | |
2012 printf(format_str, raw, value.v.f32); | |
2013 format_str[5] = tmp; | |
2014 break; | |
2015 } | |
1683 } | 2016 } |
1684 } | 2017 } |
1685 | 2018 |
1686 static uint8_t cmd_print(debug_root *root, parsed_command *cmd) | 2019 static uint8_t cmd_print(debug_root *root, parsed_command *cmd) |
1687 { | 2020 { |
1764 expr *arg = parse_expression(param, ¶m); | 2097 expr *arg = parse_expression(param, ¶m); |
1765 if (!arg) { | 2098 if (!arg) { |
1766 free(fmt); | 2099 free(fmt); |
1767 return 1; | 2100 return 1; |
1768 } | 2101 } |
1769 uint32_t val; | 2102 debug_val val; |
1770 if (!eval_expr(root, arg, &val)) { | 2103 if (!eval_expr(root, arg, &val)) { |
1771 free(fmt); | 2104 free(fmt); |
1772 return 1; | 2105 return 1; |
1773 } | 2106 } |
1774 if (cur[1] == 's') { | 2107 if (cur[1] == 's') { |
1775 char tmp[128]; | 2108 if (val.type == DBG_VAL_STRING) { |
1776 int j; | 2109 //TODO: implement me |
1777 for (j = 0; j < sizeof(tmp)-1; j++, val++) | 2110 } else { |
1778 { | 2111 char tmp[128]; |
1779 uint32_t addr = val; | 2112 uint32_t address; |
1780 root->read_mem(root, &addr, 'b'); | 2113 if (!debug_cast_int(val, &address)) { |
1781 char c = addr; | 2114 fprintf(stderr, "Format char 's' accepts only integers and strings\n"); |
1782 if (c < 0x20 || c > 0x7F) { | 2115 free(fmt); |
1783 break; | 2116 return 1; |
1784 } | 2117 } |
1785 tmp[j] = c; | 2118 int j; |
2119 for (j = 0; j < sizeof(tmp)-1; j++, address++) | |
2120 { | |
2121 uint32_t addr = address; | |
2122 root->read_mem(root, &addr, 'b'); | |
2123 char c = addr; | |
2124 if (c < 0x20 || c > 0x7F) { | |
2125 break; | |
2126 } | |
2127 tmp[j] = c; | |
2128 } | |
2129 tmp[j] = 0; | |
2130 printf(format_str, tmp); | |
1786 } | 2131 } |
1787 tmp[j] = 0; | |
1788 printf(format_str, tmp); | |
1789 } else { | 2132 } else { |
1790 printf(format_str, val); | 2133 uint32_t ival; |
2134 if (!debug_cast_int(val, &ival)) { | |
2135 fprintf(stderr, "Format char '%c' only accepts integers\n", cur[1]); | |
2136 free(fmt); | |
2137 return 1; | |
2138 } | |
2139 printf(format_str, ival); | |
1791 } | 2140 } |
1792 cur += 2; | 2141 cur += 2; |
1793 } else { | 2142 } else { |
1794 putchar(*cur); | 2143 putchar(*cur); |
1795 ++cur; | 2144 ++cur; |
1815 } | 2164 } |
1816 | 2165 |
1817 static uint8_t cmd_delete_display(debug_root *root, parsed_command *cmd) | 2166 static uint8_t cmd_delete_display(debug_root *root, parsed_command *cmd) |
1818 { | 2167 { |
1819 disp_def **cur = &root->displays; | 2168 disp_def **cur = &root->displays; |
2169 uint32_t index; | |
2170 if (!debug_cast_int(cmd->args[0].value, &index)) { | |
2171 fprintf(stderr, "Argument to deletedisplay must be an integer\n"); | |
2172 return 1; | |
2173 } | |
1820 while (*cur) | 2174 while (*cur) |
1821 { | 2175 { |
1822 if ((*cur)->index == cmd->args[0].value) { | 2176 if ((*cur)->index == index) { |
1823 disp_def *del_disp = *cur; | 2177 disp_def *del_disp = *cur; |
1824 *cur = del_disp->next; | 2178 *cur = del_disp->next; |
1825 free(del_disp->format); | 2179 free(del_disp->format); |
1826 for (int i = 0; i < del_disp->num_args; i++) | 2180 for (int i = 0; i < del_disp->num_args; i++) |
1827 { | 2181 { |
1849 } | 2203 } |
1850 } | 2204 } |
1851 | 2205 |
1852 static uint8_t cmd_command(debug_root *root, parsed_command *cmd) | 2206 static uint8_t cmd_command(debug_root *root, parsed_command *cmd) |
1853 { | 2207 { |
1854 bp_def **target = find_breakpoint_idx(&root->breakpoints, cmd->args[0].value); | 2208 uint32_t index; |
2209 if (!debug_cast_int(cmd->args[0].value, &index)) { | |
2210 fprintf(stderr, "Argument to commands must be an integer\n"); | |
2211 return 1; | |
2212 } | |
2213 bp_def **target = find_breakpoint_idx(&root->breakpoints, index); | |
1855 if (!target) { | 2214 if (!target) { |
1856 fprintf(stderr, "Breakpoint %d does not exist!\n", cmd->args[0].value); | 2215 fprintf(stderr, "Breakpoint %d does not exist!\n", index); |
1857 return 1; | 2216 return 1; |
1858 } | 2217 } |
1859 for (uint32_t i = 0; i < (*target)->num_commands; i++) | 2218 for (uint32_t i = 0; i < (*target)->num_commands; i++) |
1860 { | 2219 { |
1861 free_parsed_command((*target)->commands + i); | 2220 free_parsed_command((*target)->commands + i); |
1878 return debugging; | 2237 return debugging; |
1879 } | 2238 } |
1880 | 2239 |
1881 static uint8_t cmd_if(debug_root *root, parsed_command *cmd) | 2240 static uint8_t cmd_if(debug_root *root, parsed_command *cmd) |
1882 { | 2241 { |
1883 return execute_block(root, cmd->args[0].value ? &cmd->block : &cmd->else_block); | 2242 return execute_block(root, debug_cast_bool(cmd->args[0].value) ? &cmd->block : &cmd->else_block); |
1884 } | 2243 } |
1885 | 2244 |
1886 static uint8_t cmd_while(debug_root *root, parsed_command *cmd) | 2245 static uint8_t cmd_while(debug_root *root, parsed_command *cmd) |
1887 { | 2246 { |
1888 if (!cmd->args[0].value) { | 2247 if (!debug_cast_bool(cmd->args[0].value)) { |
1889 return execute_block(root, &cmd->else_block); | 2248 return execute_block(root, &cmd->else_block); |
1890 } | 2249 } |
1891 int debugging = 1; | 2250 int debugging = 1; |
1892 do { | 2251 do { |
1893 debugging = execute_block(root, &cmd->block) && debugging; | 2252 debugging = execute_block(root, &cmd->block) && debugging; |
1894 if (!eval_expr(root, cmd->args[0].parsed, &cmd->args[0].value)) { | 2253 if (!eval_expr(root, cmd->args[0].parsed, &cmd->args[0].value)) { |
1895 fprintf(stderr, "Failed to eval %s\n", cmd->args[0].raw); | 2254 fprintf(stderr, "Failed to eval %s\n", cmd->args[0].raw); |
1896 return 1; | 2255 return 1; |
1897 } | 2256 } |
1898 } while (cmd->args[0].value); | 2257 } while (debug_cast_bool(cmd->args[0].value)); |
1899 return debugging; | 2258 return debugging; |
1900 } | 2259 } |
1901 | 2260 |
1902 const char *expr_type_names[] = { | 2261 const char *expr_type_names[] = { |
1903 "EXPR_NONE", | 2262 "EXPR_NONE", |
1910 | 2269 |
1911 static uint8_t cmd_set(debug_root *root, parsed_command *cmd) | 2270 static uint8_t cmd_set(debug_root *root, parsed_command *cmd) |
1912 { | 2271 { |
1913 char *name = NULL; | 2272 char *name = NULL; |
1914 char size = 0; | 2273 char size = 0; |
1915 uint32_t address; | 2274 debug_root *set_root = root; |
2275 expr *set_expr = cmd->args[0].parsed; | |
2276 while (set_expr->type == EXPR_NAMESPACE) | |
2277 { | |
2278 set_root = tern_find_ptr(set_root->other_roots, set_expr->op.v.str); | |
2279 if (!set_root) { | |
2280 fprintf(stderr, "%s is not a valid namespace\n", set_expr->op.v.str); | |
2281 return 1; | |
2282 } | |
2283 set_expr = set_expr->left; | |
2284 } | |
2285 debug_val address; | |
1916 debug_array *array = NULL; | 2286 debug_array *array = NULL; |
1917 switch (cmd->args[0].parsed->type) | 2287 switch (set_expr->type) |
1918 { | 2288 { |
1919 case EXPR_SCALAR: | 2289 case EXPR_SCALAR: |
1920 if (cmd->args[0].parsed->op.type == TOKEN_NAME) { | 2290 if (set_expr->op.type == TOKEN_NAME) { |
1921 name = cmd->args[0].parsed->op.v.str; | 2291 name = set_expr->op.v.str; |
1922 } else { | 2292 } else { |
1923 fputs("First argument to set must be a name or memory expression, not a number", stderr); | 2293 fputs("First argument to set must be a name or memory expression, not a number", stderr); |
1924 return 1; | 2294 return 1; |
1925 } | 2295 } |
1926 break; | 2296 break; |
1927 case EXPR_SIZE: | 2297 case EXPR_SIZE: |
1928 size = cmd->args[0].parsed->op.v.op[0]; | 2298 size = set_expr->op.v.op[0]; |
1929 if (cmd->args[0].parsed->left->op.type == TOKEN_NAME) { | 2299 if (set_expr->left->op.type == TOKEN_NAME) { |
1930 name = cmd->args[0].parsed->left->op.v.str; | 2300 name = set_expr->left->op.v.str; |
1931 } else { | 2301 } else { |
1932 fputs("First argument to set must be a name or memory expression, not a number", stderr); | 2302 fputs("First argument to set must be a name or memory expression, not a number", stderr); |
1933 return 1; | 2303 return 1; |
1934 } | 2304 } |
1935 break; | 2305 break; |
1936 case EXPR_MEM: | 2306 case EXPR_MEM: |
1937 size = cmd->args[0].parsed->op.v.op[0]; | 2307 size = set_expr->op.v.op[0]; |
1938 if (!eval_expr(root, cmd->args[0].parsed->left, &address)) { | 2308 if (!eval_expr(root, set_expr->left, &address)) { |
1939 fprintf(stderr, "Failed to eval %s\n", cmd->args[0].raw); | 2309 fprintf(stderr, "Failed to eval %s\n", cmd->args[0].raw); |
1940 return 1; | 2310 return 1; |
1941 } | 2311 } |
1942 if (cmd->args[0].parsed->right) { | 2312 if (address.type != DBG_VAL_U32) { |
1943 array = full_array_resolve(root, cmd->args[0].parsed->right->op.v.str); | 2313 fprintf(stderr, "Index in array expression must be integer\n"); |
2314 return 1; | |
2315 } | |
2316 if (set_expr->right) { | |
2317 debug_val right; | |
2318 if (!eval_expr(root, set_expr->right, &right)) { | |
2319 return 1; | |
2320 } | |
2321 array = get_array(right); | |
1944 if (!array) { | 2322 if (!array) { |
1945 fprintf(stderr, "Failed to resolve array %s\n", cmd->args[0].parsed->right->op.v.str); | 2323 fprintf(stderr, "%s does not refer to an array\n", cmd->args[0].raw); |
1946 return 1; | 2324 return 1; |
1947 } | 2325 } |
1948 if (!array->set) { | 2326 if (!array->set) { |
1949 fprintf(stderr, "Array %s is read-only\n", cmd->args[0].parsed->right->op.v.str); | 2327 fprintf(stderr, "Array %s is read-only\n", set_expr->right->op.v.str); |
1950 return 1; | 2328 return 1; |
1951 } | 2329 } |
1952 if (address >= array->size) { | 2330 if (address.v.u32 >= array->size) { |
1953 fprintf(stderr, "Address %X is out of bounds for array %s\n", address, cmd->args[0].parsed->right->op.v.str); | 2331 fprintf(stderr, "Address %X is out of bounds for array %s\n", address.v.u32, set_expr->right->op.v.str); |
1954 return 1; | 2332 return 1; |
1955 } | 2333 } |
1956 } | 2334 } |
1957 break; | 2335 break; |
1958 default: | 2336 default: |
1959 fprintf(stderr, "First argument to set must be a name or memory expression, got %s\n", expr_type_names[cmd->args[0].parsed->type]); | 2337 fprintf(stderr, "First argument to set must be a name or memory expression, got %s\n", expr_type_names[set_expr->type]); |
1960 return 1; | 2338 return 1; |
1961 } | 2339 } |
1962 if (!eval_expr(root, cmd->args[1].parsed, &cmd->args[1].value)) { | 2340 if (!eval_expr(root, cmd->args[1].parsed, &cmd->args[1].value)) { |
1963 fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw); | 2341 fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw); |
1964 return 1; | 2342 return 1; |
1965 } | 2343 } |
1966 uint32_t value = cmd->args[1].value; | 2344 debug_val value = cmd->args[1].value; |
1967 if (name && size && size != 'l') { | 2345 if (name) { |
1968 uint32_t old; | 2346 debug_var *var = tern_find_ptr(set_root->variables, name); |
1969 if (!root->resolve(root, name, &old)) { | 2347 if (!var) { |
1970 fprintf(stderr, "Failed to eval %s\n", name); | 2348 fprintf(stderr, "%s is not defined\n", name); |
1971 return 1; | 2349 return 1; |
1972 } | 2350 } |
1973 if (size == 'b') { | 2351 if (!var->set) { |
1974 old &= 0xFFFFFF00; | 2352 fprintf(stderr, "%s is read-only\n", name); |
1975 value &= 0xFF; | 2353 return 1; |
1976 value |= old; | 2354 } |
1977 } else { | 2355 if (size && size != 'l') { |
1978 old &= 0xFFFF0000; | 2356 debug_val old = var->get(var); |
1979 value &= 0xFFFF; | 2357 if (size == 'b') { |
1980 value |= old; | 2358 old.v.u32 &= 0xFFFFFF00; |
1981 } | 2359 value.v.u32 &= 0xFF; |
1982 } | 2360 value.v.u32 |= old.v.u32; |
1983 if (name) { | |
1984 if (!root->set(root, name, value)) { | |
1985 tern_val v; | |
1986 if (tern_find(root->variables, name, &v)) { | |
1987 root->variables = tern_insert_int(root->variables, name, value); | |
1988 } else { | 2361 } else { |
1989 fprintf(stderr, "Failed to set %s\n", name); | 2362 old.v.u32 &= 0xFFFF0000; |
1990 } | 2363 value.v.u32 &= 0xFFFF; |
1991 } | 2364 value.v.u32 |= old.v.u32; |
2365 } | |
2366 } | |
2367 var->set(var, value); | |
1992 } else if (array) { | 2368 } else if (array) { |
1993 array->set(root, array, address, value); | 2369 array->set(array, address.v.u32, value); |
1994 } else if (!root->write_mem(root, address, value, size)) { | 2370 } else if (!root->write_mem(root, address.v.u32, value.v.u32, size)) { |
1995 fprintf(stderr, "Failed to write to address %X\n", address); | 2371 fprintf(stderr, "Failed to write to address %X\n", address.v.u32); |
1996 } | 2372 } |
1997 return 1; | 2373 return 1; |
1998 } | 2374 } |
1999 | 2375 |
2000 static uint8_t cmd_variable(debug_root *root, parsed_command *cmd) | 2376 static uint8_t cmd_variable(debug_root *root, parsed_command *cmd) |
2001 { | 2377 { |
2002 if (cmd->args[0].parsed->type != EXPR_SCALAR || cmd->args[0].parsed->op.type != TOKEN_NAME) { | 2378 debug_root *set_root = root; |
2003 fprintf(stderr, "First argument to variable must be a name, got %s\n", expr_type_names[cmd->args[0].parsed->type]); | 2379 expr *set_expr = cmd->args[0].parsed; |
2380 while (set_expr->type == EXPR_NAMESPACE) | |
2381 { | |
2382 set_root = tern_find_ptr(set_root->other_roots, set_expr->op.v.str); | |
2383 if (!set_root) { | |
2384 fprintf(stderr, "%s is not a valid namespace\n", set_expr->op.v.str); | |
2385 return 1; | |
2386 } | |
2387 set_expr = set_expr->left; | |
2388 } | |
2389 if (set_expr->type != EXPR_SCALAR || set_expr->op.type != TOKEN_NAME) { | |
2390 fprintf(stderr, "First argument to variable must be a name, got %s\n", expr_type_names[set_expr->type]); | |
2004 return 1; | 2391 return 1; |
2005 } | 2392 } |
2006 uint32_t value = 0; | 2393 debug_var *var = tern_find_ptr(set_root->variables, set_expr->op.v.str); |
2394 if (var) { | |
2395 fprintf(stderr, "%s is already defined\n", set_expr->op.v.str); | |
2396 return 1; | |
2397 } | |
2398 debug_val value; | |
2399 value.type = DBG_VAL_U32; | |
2400 value.v.u32 = 0; | |
2007 if (cmd->num_args > 1) { | 2401 if (cmd->num_args > 1) { |
2008 if (!eval_expr(root, cmd->args[1].parsed, &cmd->args[1].value)) { | 2402 if (!eval_expr(root, cmd->args[1].parsed, &cmd->args[1].value)) { |
2009 fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw); | 2403 fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw); |
2010 return 1; | 2404 return 1; |
2011 } | 2405 } |
2012 value = cmd->args[1].value; | 2406 value = cmd->args[1].value; |
2013 } | 2407 } |
2014 root->variables = tern_insert_int(root->variables, cmd->args[0].parsed->op.v.str, value); | 2408 new_user_variable(set_root, set_expr->op.v.str, value); |
2015 return 1; | 2409 return 1; |
2016 } | 2410 } |
2017 | 2411 |
2018 static uint32_t user_array_get(debug_root *root, debug_array *array, uint32_t index) | |
2019 { | |
2020 return array->data[index]; | |
2021 } | |
2022 | |
2023 static void user_array_set(debug_root *root, debug_array *array, uint32_t index, uint32_t value) | |
2024 { | |
2025 array->data[index] = value; | |
2026 } | |
2027 | |
2028 static void user_array_append(debug_root *root, debug_array *array, uint32_t value) | |
2029 { | |
2030 if (array->size == array->storage) { | |
2031 array->storage *= 2; | |
2032 array->data = realloc(array->data, sizeof(uint32_t) * array->storage); | |
2033 } | |
2034 array->data[array->size++] = value; | |
2035 } | |
2036 | |
2037 static uint8_t cmd_array(debug_root *root, parsed_command *cmd) | 2412 static uint8_t cmd_array(debug_root *root, parsed_command *cmd) |
2038 { | 2413 { |
2039 if (cmd->args[0].parsed->type != EXPR_SCALAR || cmd->args[0].parsed->op.type != TOKEN_NAME) { | 2414 debug_root *set_root = root; |
2040 fprintf(stderr, "First argument to array must be a name, got %s\n", expr_type_names[cmd->args[0].parsed->type]); | 2415 expr *set_expr = cmd->args[0].parsed; |
2416 while (set_expr->type == EXPR_NAMESPACE) | |
2417 { | |
2418 set_root = tern_find_ptr(set_root->other_roots, set_expr->op.v.str); | |
2419 if (!set_root) { | |
2420 fprintf(stderr, "%s is not a valid namespace\n", set_expr->op.v.str); | |
2421 return 1; | |
2422 } | |
2423 set_expr = set_expr->left; | |
2424 } | |
2425 if (set_expr->type != EXPR_SCALAR || set_expr->op.type != TOKEN_NAME) { | |
2426 fprintf(stderr, "First argument to array must be a name, got %s\n", expr_type_names[set_expr->type]); | |
2041 return 1; | 2427 return 1; |
2042 } | 2428 } |
2043 debug_array *array = tern_find_ptr(root->arrays, cmd->args[0].parsed->op.v.str); | 2429 debug_var *var = tern_find_ptr(set_root->variables, set_expr->op.v.str); |
2044 if (!array) { | 2430 debug_array *array; |
2045 array = calloc(1, sizeof(debug_array)); | 2431 if (var) { |
2046 array->get = user_array_get; | 2432 debug_val val = var->get(var); |
2047 array->set = user_array_set; | 2433 array = get_array(val); |
2048 array->append = user_array_append; | 2434 if (!array) { |
2049 array->storage = cmd->num_args > 1 ? cmd->num_args - 1 : 4; | 2435 fprintf(stderr, "%s is already defined as a non-array value\n", set_expr->op.v.str); |
2050 array->data = calloc(array->storage, sizeof(uint32_t)); | 2436 return 1; |
2051 root->arrays = tern_insert_ptr(root->arrays, cmd->args[0].parsed->op.v.str, array); | 2437 } |
2052 } | 2438 } else { |
2053 array->size = cmd->num_args - 1; | 2439 var = calloc(1, sizeof(debug_var)); |
2054 for (uint32_t i = 1; i < cmd->num_args; i++) | 2440 var->get = user_var_get; |
2441 var->set = user_var_set; | |
2442 var->val = new_user_array(cmd->num_args - 1); | |
2443 set_root->variables = tern_insert_ptr(set_root->variables, set_expr->op.v.str, var); | |
2444 array = get_array(var->val); | |
2445 } | |
2446 if (array->set == user_array_set) { | |
2447 array->size = cmd->num_args - 1; | |
2448 if (array->storage < array->size) { | |
2449 array->storage = array->size; | |
2450 array->base = realloc(array->base, sizeof(debug_val) * array->storage); | |
2451 } | |
2452 } | |
2453 for (uint32_t i = 1; i < cmd->num_args && i < array->size; i++) | |
2055 { | 2454 { |
2056 if (!eval_expr(root, cmd->args[i].parsed, &cmd->args[i].value)) { | 2455 if (!eval_expr(root, cmd->args[i].parsed, &cmd->args[i].value)) { |
2057 fprintf(stderr, "Failed to eval %s\n", cmd->args[i].raw); | 2456 fprintf(stderr, "Failed to eval %s\n", cmd->args[i].raw); |
2058 return 1; | 2457 return 1; |
2059 } | 2458 } |
2060 array->set(root, array, i - 1, cmd->args[i].value); | 2459 array->set(array, i - 1, cmd->args[i].value); |
2061 } | 2460 } |
2062 return 1; | 2461 return 1; |
2063 } | 2462 } |
2064 | 2463 |
2065 static uint8_t cmd_append(debug_root *root, parsed_command *cmd) | 2464 static uint8_t cmd_append(debug_root *root, parsed_command *cmd) |
2066 { | 2465 { |
2067 if (cmd->args[0].parsed->type != EXPR_SCALAR || cmd->args[0].parsed->op.type != TOKEN_NAME) { | 2466 debug_array *array = get_array(cmd->args[0].value); |
2068 fprintf(stderr, "First argument to append must be a name, got %s\n", expr_type_names[cmd->args[0].parsed->type]); | 2467 if (!array) { |
2468 fprintf(stderr, "%s is not an array\n", cmd->args[0].raw); | |
2069 return 1; | 2469 return 1; |
2070 } | 2470 } |
2071 debug_array *array = full_array_resolve(root, cmd->args[0].parsed->op.v.str); | 2471 if (!array->append) { |
2072 if (!array) { | 2472 fprintf(stderr, "Array %s doesn't support appending\n", cmd->args[0].raw); |
2073 fprintf(stderr, "Failed to resolve array %s\n", cmd->args[0].parsed->op.v.str); | |
2074 return 1; | 2473 return 1; |
2075 } | 2474 } |
2076 if (!array->append) { | 2475 array->append(array, cmd->args[1].value); |
2077 fprintf(stderr, "Array %s doesn't support appending\n", cmd->args[0].parsed->op.v.str); | 2476 return 1; |
2477 } | |
2478 | |
2479 static uint8_t cmd_frames(debug_root *root, parsed_command *cmd) | |
2480 { | |
2481 uint32_t frames; | |
2482 if (!debug_cast_int(cmd->args[0].value, &frames)) { | |
2483 fprintf(stderr, "Argument to frames must be an integer\n"); | |
2078 return 1; | 2484 return 1; |
2079 } | 2485 } |
2080 if (!eval_expr(root, cmd->args[1].parsed, &cmd->args[1].value)) { | 2486 current_system->enter_debugger_frames = frames; |
2081 fprintf(stderr, "Failed to eval %s\n", cmd->args[1].raw); | |
2082 return 1; | |
2083 } | |
2084 array->append(root, array, cmd->args[1].value); | |
2085 return 1; | |
2086 } | |
2087 | |
2088 static uint8_t cmd_frames(debug_root *root, parsed_command *cmd) | |
2089 { | |
2090 current_system->enter_debugger_frames = cmd->args[0].value; | |
2091 return 0; | 2487 return 0; |
2092 } | 2488 } |
2093 | 2489 |
2094 static uint8_t cmd_bindup(debug_root *root, parsed_command *cmd) | 2490 static uint8_t cmd_bindup(debug_root *root, parsed_command *cmd) |
2095 { | 2491 { |
2111 { | 2507 { |
2112 if (!eval_expr(root, cmd->args[0].parsed, &cmd->args[0].value)) { | 2508 if (!eval_expr(root, cmd->args[0].parsed, &cmd->args[0].value)) { |
2113 fprintf(stderr, "Failed to evaluate breakpoint number: %s\n", cmd->args[0].raw); | 2509 fprintf(stderr, "Failed to evaluate breakpoint number: %s\n", cmd->args[0].raw); |
2114 return 1; | 2510 return 1; |
2115 } | 2511 } |
2116 bp_def **target = find_breakpoint_idx(&root->breakpoints, cmd->args[0].value); | 2512 uint32_t index; |
2513 if (!debug_cast_int(cmd->args[0].value, &index)) { | |
2514 fprintf(stderr, "First argument to condition must be an integer\n"); | |
2515 return 1; | |
2516 } | |
2517 bp_def **target = find_breakpoint_idx(&root->breakpoints, index); | |
2117 if (!*target) { | 2518 if (!*target) { |
2118 fprintf(stderr, "Failed to find breakpoint %u\n", cmd->args[0].value); | 2519 fprintf(stderr, "Failed to find breakpoint %u\n", index); |
2119 return 1; | 2520 return 1; |
2120 } | 2521 } |
2121 free_expr((*target)->condition); | 2522 free_expr((*target)->condition); |
2122 if (cmd->num_args > 1 && cmd->args[1].parsed) { | 2523 if (cmd->num_args > 1 && cmd->args[1].parsed) { |
2123 (*target)->condition = cmd->args[1].parsed; | 2524 (*target)->condition = cmd->args[1].parsed; |
2184 return 1; | 2585 return 1; |
2185 } | 2586 } |
2186 | 2587 |
2187 static uint8_t cmd_delete_m68k(debug_root *root, parsed_command *cmd) | 2588 static uint8_t cmd_delete_m68k(debug_root *root, parsed_command *cmd) |
2188 { | 2589 { |
2189 bp_def **this_bp = find_breakpoint_idx(&root->breakpoints, cmd->args[0].value); | 2590 uint32_t index; |
2591 if (!debug_cast_int(cmd->args[0].value, &index)) { | |
2592 fprintf(stderr, "Argument to delete must be an integer\n"); | |
2593 return 1; | |
2594 } | |
2595 bp_def **this_bp = find_breakpoint_idx(&root->breakpoints, index); | |
2190 if (!*this_bp) { | 2596 if (!*this_bp) { |
2191 fprintf(stderr, "Breakpoint %d does not exist\n", cmd->args[0].value); | 2597 fprintf(stderr, "Breakpoint %d does not exist\n", index); |
2192 return 1; | 2598 return 1; |
2193 } | 2599 } |
2194 bp_def *tmp = *this_bp; | 2600 bp_def *tmp = *this_bp; |
2195 if (tmp->type == BP_TYPE_CPU) { | 2601 if (tmp->type == BP_TYPE_CPU) { |
2196 remove_breakpoint(root->cpu_context, tmp->address); | 2602 remove_breakpoint(root->cpu_context, tmp->address); |
2207 return 1; | 2613 return 1; |
2208 } | 2614 } |
2209 | 2615 |
2210 static uint8_t cmd_breakpoint_m68k(debug_root *root, parsed_command *cmd) | 2616 static uint8_t cmd_breakpoint_m68k(debug_root *root, parsed_command *cmd) |
2211 { | 2617 { |
2212 insert_breakpoint(root->cpu_context, cmd->args[0].value, debugger); | 2618 uint32_t address; |
2619 if (!debug_cast_int(cmd->args[0].value, &address)) { | |
2620 fprintf(stderr, "Argument to breakpoint must be an integer\n"); | |
2621 return 1; | |
2622 } | |
2623 insert_breakpoint(root->cpu_context, address, debugger); | |
2213 bp_def *new_bp = calloc(1, sizeof(bp_def)); | 2624 bp_def *new_bp = calloc(1, sizeof(bp_def)); |
2214 new_bp->next = root->breakpoints; | 2625 new_bp->next = root->breakpoints; |
2215 new_bp->address = cmd->args[0].value; | 2626 new_bp->address = address; |
2216 new_bp->mask = 0xFFFFFF; | 2627 new_bp->mask = 0xFFFFFF; |
2217 new_bp->index = root->bp_index++; | 2628 new_bp->index = root->bp_index++; |
2218 new_bp->type = BP_TYPE_CPU; | 2629 new_bp->type = BP_TYPE_CPU; |
2219 root->breakpoints = new_bp; | 2630 root->breakpoints = new_bp; |
2220 printf("68K Breakpoint %d set at %X\n", new_bp->index, cmd->args[0].value); | 2631 printf("68K Breakpoint %d set at %X\n", new_bp->index, address); |
2221 return 1; | 2632 return 1; |
2222 } | 2633 } |
2223 | 2634 |
2224 static void on_vdp_reg_write(vdp_context *context, uint16_t reg, uint16_t value) | 2635 static void on_vdp_reg_write(vdp_context *context, uint16_t reg, uint16_t value) |
2225 { | 2636 { |
2231 debug_root *root = find_m68k_root(gen->m68k); | 2642 debug_root *root = find_m68k_root(gen->m68k); |
2232 bp_def **this_bp = find_breakpoint(&root->breakpoints, reg, BP_TYPE_VDPREG); | 2643 bp_def **this_bp = find_breakpoint(&root->breakpoints, reg, BP_TYPE_VDPREG); |
2233 int debugging = 1; | 2644 int debugging = 1; |
2234 if (*this_bp) { | 2645 if (*this_bp) { |
2235 if ((*this_bp)->condition) { | 2646 if ((*this_bp)->condition) { |
2236 uint32_t condres; | 2647 debug_val condres; |
2237 if (eval_expr(root, (*this_bp)->condition, &condres)) { | 2648 if (eval_expr(root, (*this_bp)->condition, &condres)) { |
2238 if (!condres) { | 2649 if (!condres.v.u32) { |
2239 return; | 2650 return; |
2240 } | 2651 } |
2241 } else { | 2652 } else { |
2242 fprintf(stderr, "Failed to eval condition for VDP Register Breakpoint %u\n", (*this_bp)->index); | 2653 fprintf(stderr, "Failed to eval condition for VDP Register Breakpoint %u\n", (*this_bp)->index); |
2243 free_expr((*this_bp)->condition); | 2654 free_expr((*this_bp)->condition); |
2264 static uint8_t cmd_vdp_reg_break(debug_root *root, parsed_command *cmd) | 2675 static uint8_t cmd_vdp_reg_break(debug_root *root, parsed_command *cmd) |
2265 { | 2676 { |
2266 bp_def *new_bp = calloc(1, sizeof(bp_def)); | 2677 bp_def *new_bp = calloc(1, sizeof(bp_def)); |
2267 new_bp->next = root->breakpoints; | 2678 new_bp->next = root->breakpoints; |
2268 if (cmd->num_args) { | 2679 if (cmd->num_args) { |
2269 new_bp->address = cmd->args[0].value; | 2680 if (!debug_cast_int(cmd->args[0].value, &new_bp->address)) { |
2270 new_bp->mask = cmd->num_args > 1 ? cmd->args[1].value : 0xFF; | 2681 fprintf(stderr, "Arguments to vdpregbreak must be integers if provided\n"); |
2682 return 1; | |
2683 } | |
2684 if (cmd->num_args > 1) { | |
2685 if (!debug_cast_int(cmd->args[1].value, &new_bp->mask)) { | |
2686 fprintf(stderr, "Arguments to vdpregbreak must be integers if provided\n"); | |
2687 return 1; | |
2688 } | |
2689 } else { | |
2690 new_bp->mask = 0xFF; | |
2691 } | |
2271 } | 2692 } |
2272 new_bp->index = root->bp_index++; | 2693 new_bp->index = root->bp_index++; |
2273 new_bp->type = BP_TYPE_VDPREG; | 2694 new_bp->type = BP_TYPE_VDPREG; |
2274 root->breakpoints = new_bp; | 2695 root->breakpoints = new_bp; |
2275 m68k_context *m68k = root->cpu_context; | 2696 m68k_context *m68k = root->cpu_context; |
2279 return 1; | 2700 return 1; |
2280 } | 2701 } |
2281 | 2702 |
2282 static uint8_t cmd_advance_m68k(debug_root *root, parsed_command *cmd) | 2703 static uint8_t cmd_advance_m68k(debug_root *root, parsed_command *cmd) |
2283 { | 2704 { |
2284 insert_breakpoint(root->cpu_context, cmd->args[0].value, debugger); | 2705 uint32_t address; |
2706 if (!debug_cast_int(cmd->args[0].value, &address)) { | |
2707 fprintf(stderr, "Argument to advance must be an integer\n"); | |
2708 return 1; | |
2709 } | |
2710 insert_breakpoint(root->cpu_context, address, debugger); | |
2285 return 0; | 2711 return 0; |
2286 } | 2712 } |
2287 | 2713 |
2288 static uint8_t cmd_step_m68k(debug_root *root, parsed_command *cmd) | 2714 static uint8_t cmd_step_m68k(debug_root *root, parsed_command *cmd) |
2289 { | 2715 { |
2415 static uint8_t cmd_disassemble_m68k(debug_root *root, parsed_command *cmd) | 2841 static uint8_t cmd_disassemble_m68k(debug_root *root, parsed_command *cmd) |
2416 { | 2842 { |
2417 m68k_context *context = root->cpu_context; | 2843 m68k_context *context = root->cpu_context; |
2418 uint32_t address = root->address; | 2844 uint32_t address = root->address; |
2419 if (cmd->num_args) { | 2845 if (cmd->num_args) { |
2420 address = cmd->args[0].value; | 2846 if (!debug_cast_int(cmd->args[0].value, &address)) { |
2847 fprintf(stderr, "Argument to disassemble must be an integer if provided\n"); | |
2848 return 1; | |
2849 } | |
2421 } | 2850 } |
2422 char disasm_buf[1024]; | 2851 char disasm_buf[1024]; |
2423 m68kinst inst; | 2852 m68kinst inst; |
2424 do { | 2853 do { |
2425 label_def *def = find_label(root->disasm, address); | 2854 label_def *def = find_label(root->disasm, address); |
2456 static uint8_t cmd_ym_channel(debug_root *root, parsed_command *cmd) | 2885 static uint8_t cmd_ym_channel(debug_root *root, parsed_command *cmd) |
2457 { | 2886 { |
2458 m68k_context *context = root->cpu_context; | 2887 m68k_context *context = root->cpu_context; |
2459 genesis_context * gen = context->system; | 2888 genesis_context * gen = context->system; |
2460 if (cmd->num_args) { | 2889 if (cmd->num_args) { |
2461 ym_print_channel_info(gen->ym, cmd->args[0].value - 1); | 2890 ym_print_channel_info(gen->ym, cmd->args[0].value.v.u32 - 1); |
2462 } else { | 2891 } else { |
2463 for (int i = 0; i < 6; i++) { | 2892 for (int i = 0; i < 6; i++) { |
2464 ym_print_channel_info(gen->ym, i); | 2893 ym_print_channel_info(gen->ym, i); |
2465 } | 2894 } |
2466 } | 2895 } |
2695 }, | 3124 }, |
2696 .usage = "append NAME VALUE", | 3125 .usage = "append NAME VALUE", |
2697 .desc = "Increase the size of array NAME by 1 and set the last element to VALUE", | 3126 .desc = "Increase the size of array NAME by 1 and set the last element to VALUE", |
2698 .impl = cmd_append, | 3127 .impl = cmd_append, |
2699 .min_args = 2, | 3128 .min_args = 2, |
2700 .max_args = 2, | 3129 .max_args = 2 |
2701 .skip_eval = 1 | |
2702 }, | 3130 }, |
2703 { | 3131 { |
2704 .names = (const char *[]){ | 3132 .names = (const char *[]){ |
2705 "frames", NULL | 3133 "frames", NULL |
2706 }, | 3134 }, |
2968 | 3396 |
2969 #ifndef NO_Z80 | 3397 #ifndef NO_Z80 |
2970 | 3398 |
2971 static uint8_t cmd_delete_z80(debug_root *root, parsed_command *cmd) | 3399 static uint8_t cmd_delete_z80(debug_root *root, parsed_command *cmd) |
2972 { | 3400 { |
2973 bp_def **this_bp = find_breakpoint_idx(&root->breakpoints, cmd->args[0].value); | 3401 uint32_t index; |
3402 if (!debug_cast_int(cmd->args[0].value, &index)) { | |
3403 fprintf(stderr, "Argument to delete must be an integer\n"); | |
3404 return 1; | |
3405 } | |
3406 bp_def **this_bp = find_breakpoint_idx(&root->breakpoints, index); | |
2974 if (!*this_bp) { | 3407 if (!*this_bp) { |
2975 fprintf(stderr, "Breakpoint %d does not exist\n", cmd->args[0].value); | 3408 fprintf(stderr, "Breakpoint %d does not exist\n", index); |
2976 return 1; | 3409 return 1; |
2977 } | 3410 } |
2978 bp_def *tmp = *this_bp; | 3411 bp_def *tmp = *this_bp; |
2979 zremove_breakpoint(root->cpu_context, tmp->address); | 3412 zremove_breakpoint(root->cpu_context, tmp->address); |
2980 *this_bp = (*this_bp)->next; | 3413 *this_bp = (*this_bp)->next; |
2989 return 1; | 3422 return 1; |
2990 } | 3423 } |
2991 | 3424 |
2992 static uint8_t cmd_breakpoint_z80(debug_root *root, parsed_command *cmd) | 3425 static uint8_t cmd_breakpoint_z80(debug_root *root, parsed_command *cmd) |
2993 { | 3426 { |
2994 zinsert_breakpoint(root->cpu_context, cmd->args[0].value, (uint8_t *)zdebugger); | 3427 uint32_t address; |
3428 if (!debug_cast_int(cmd->args[0].value, &address)) { | |
3429 fprintf(stderr, "Argument to breakpoint must be an integer\n"); | |
3430 return 1; | |
3431 } | |
3432 zinsert_breakpoint(root->cpu_context, address, (uint8_t *)zdebugger); | |
2995 bp_def *new_bp = calloc(1, sizeof(bp_def)); | 3433 bp_def *new_bp = calloc(1, sizeof(bp_def)); |
2996 new_bp->next = root->breakpoints; | 3434 new_bp->next = root->breakpoints; |
2997 new_bp->address = cmd->args[0].value; | 3435 new_bp->address = address; |
2998 new_bp->mask = 0xFFFF; | 3436 new_bp->mask = 0xFFFF; |
2999 new_bp->type = BP_TYPE_CPU; | 3437 new_bp->type = BP_TYPE_CPU; |
3000 new_bp->index = root->bp_index++; | 3438 new_bp->index = root->bp_index++; |
3001 root->breakpoints = new_bp; | 3439 root->breakpoints = new_bp; |
3002 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, cmd->args[0].value); | 3440 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, address); |
3003 return 1; | 3441 return 1; |
3004 } | 3442 } |
3005 | 3443 |
3006 static uint8_t cmd_advance_z80(debug_root *root, parsed_command *cmd) | 3444 static uint8_t cmd_advance_z80(debug_root *root, parsed_command *cmd) |
3007 { | 3445 { |
3008 zinsert_breakpoint(root->cpu_context, cmd->args[0].value, (uint8_t *)zdebugger); | 3446 uint32_t address; |
3447 if (!debug_cast_int(cmd->args[0].value, &address)) { | |
3448 fprintf(stderr, "Argument to advance must be an integer\n"); | |
3449 return 1; | |
3450 } | |
3451 zinsert_breakpoint(root->cpu_context, address, (uint8_t *)zdebugger); | |
3009 return 0; | 3452 return 0; |
3010 } | 3453 } |
3011 | 3454 |
3012 static uint8_t cmd_step_z80(debug_root *root, parsed_command *cmd) | 3455 static uint8_t cmd_step_z80(debug_root *root, parsed_command *cmd) |
3013 { | 3456 { |
3116 static uint8_t cmd_disassemble_z80(debug_root *root, parsed_command *cmd) | 3559 static uint8_t cmd_disassemble_z80(debug_root *root, parsed_command *cmd) |
3117 { | 3560 { |
3118 z80_context *context = root->cpu_context; | 3561 z80_context *context = root->cpu_context; |
3119 uint32_t address = root->address; | 3562 uint32_t address = root->address; |
3120 if (cmd->num_args) { | 3563 if (cmd->num_args) { |
3121 address = cmd->args[0].value; | 3564 if (!debug_cast_int(cmd->args[0].value, &address)) { |
3565 fprintf(stderr, "Argument to disassemble must be an integer if provided\n"); | |
3566 return 1; | |
3567 } | |
3122 } | 3568 } |
3123 char disasm_buf[1024]; | 3569 char disasm_buf[1024]; |
3124 z80inst inst; | 3570 z80inst inst; |
3125 do { | 3571 do { |
3126 label_def *def = find_label(root->disasm, address); | 3572 label_def *def = find_label(root->disasm, address); |
3330 { | 3776 { |
3331 root->symbols = tern_insert_int(root->symbols, label->labels[i], label->full_address); | 3777 root->symbols = tern_insert_int(root->symbols, label->labels[i], label->full_address); |
3332 } | 3778 } |
3333 } | 3779 } |
3334 | 3780 |
3781 static debug_val debug_frame_get(debug_var *var) | |
3782 { | |
3783 vdp_context *vdp = var->ptr; | |
3784 return debug_int(vdp->frame); | |
3785 } | |
3786 | |
3335 debug_root *find_m68k_root(m68k_context *context) | 3787 debug_root *find_m68k_root(m68k_context *context) |
3336 { | 3788 { |
3337 debug_root *root = find_root(context); | 3789 debug_root *root = find_root(context); |
3338 if (root && !root->commands) { | 3790 if (root && !root->commands) { |
3339 add_commands(root, common_commands, NUM_COMMON); | 3791 add_commands(root, common_commands, NUM_COMMON); |
3340 add_commands(root, m68k_commands, NUM_68K); | 3792 add_commands(root, m68k_commands, NUM_68K); |
3341 root->read_mem = read_m68k; | 3793 root->read_mem = read_m68k; |
3342 root->write_mem = write_m68k; | 3794 root->write_mem = write_m68k; |
3343 root->set = set_m68k; | |
3344 root->disasm = create_68000_disasm(); | 3795 root->disasm = create_68000_disasm(); |
3796 m68k_names(root); | |
3797 debug_var *var; | |
3345 switch (current_system->type) | 3798 switch (current_system->type) |
3346 { | 3799 { |
3347 case SYSTEM_GENESIS: | 3800 case SYSTEM_GENESIS: |
3348 case SYSTEM_SEGACD: | 3801 case SYSTEM_SEGACD: |
3349 //check if this is the main CPU | 3802 //check if this is the main CPU |
3350 if (context->system == current_system) { | 3803 if (context->system == current_system) { |
3351 root->resolve = resolve_genesis; | 3804 genesis_context *gen = context->system; |
3352 root->array_resolve = resolve_genesis_array; | 3805 root->other_roots = tern_insert_ptr(root->other_roots, "z80", find_z80_root(gen->z80)); |
3806 root->other_roots = tern_insert_ptr(root->other_roots, "vdp", find_vdp_root(gen->vdp)); | |
3807 root->other_roots = tern_insert_ptr(root->other_roots, "ym", find_ym2612_root(gen->ym)); | |
3808 root->other_roots = tern_insert_ptr(root->other_roots, "psg", find_psg_root(gen->psg)); | |
3353 add_commands(root, genesis_commands, NUM_GENESIS); | 3809 add_commands(root, genesis_commands, NUM_GENESIS); |
3810 var = calloc(1, sizeof(debug_var)); | |
3811 var->get = debug_frame_get; | |
3812 var->ptr = gen->vdp; | |
3813 root->variables = tern_insert_ptr(root->variables, "frame", var); | |
3354 if (current_system->type == SYSTEM_SEGACD) { | 3814 if (current_system->type == SYSTEM_SEGACD) { |
3355 add_segacd_maincpu_labels(root->disasm); | 3815 add_segacd_maincpu_labels(root->disasm); |
3356 add_commands(root, scd_main_commands, NUM_SCD_MAIN); | 3816 add_commands(root, scd_main_commands, NUM_SCD_MAIN); |
3817 segacd_context *scd = gen->expansion; | |
3818 root->other_roots = tern_insert_ptr(root->other_roots, "sub", find_m68k_root(scd->m68k)); | |
3357 } | 3819 } |
3358 break; | 3820 break; |
3359 } else { | 3821 } else { |
3360 add_segacd_subcpu_labels(root->disasm); | 3822 add_segacd_subcpu_labels(root->disasm); |
3361 add_commands(root, scd_sub_commands, NUM_SCD_SUB); | 3823 add_commands(root, scd_sub_commands, NUM_SCD_SUB); |
3824 segacd_context *scd = context->system; | |
3825 root->other_roots = tern_insert_ptr(root->other_roots, "main", find_m68k_root(scd->genesis->m68k)); | |
3362 } | 3826 } |
3363 default: | 3827 default: |
3364 root->resolve = resolve_m68k; | 3828 break; |
3365 root->array_resolve = resolve_null_array; | |
3366 } | 3829 } |
3367 tern_foreach(root->disasm->labels, symbol_map, root); | 3830 tern_foreach(root->disasm->labels, symbol_map, root); |
3368 } | 3831 } |
3369 return root; | 3832 return root; |
3370 } | 3833 } |
3390 write_byte(address + 1, value >> 8, (void **)context->mem_pointers, &context->options->gen, context); | 3853 write_byte(address + 1, value >> 8, (void **)context->mem_pointers, &context->options->gen, context); |
3391 } | 3854 } |
3392 return 1; | 3855 return 1; |
3393 } | 3856 } |
3394 | 3857 |
3395 static uint8_t resolve_z80(debug_root *root, const char *name, uint32_t *out) | 3858 static debug_val z80_reg8_get(debug_var *var) |
3396 { | 3859 { |
3397 z80_context *context = root->cpu_context; | 3860 z80_context *context = var->ptr; |
3398 switch (tolower(name[0])) | 3861 return debug_int(context->regs[var->val.v.u32]); |
3399 { | 3862 } |
3400 case 'a': | 3863 |
3401 if (!name[1]) { | 3864 static void z80_reg8_set(debug_var *var, debug_val val) |
3402 *out = context->regs[Z80_A]; | 3865 { |
3403 } else if (name[1] == '\'' && !name[2]) { | 3866 z80_context *context = var->ptr; |
3404 *out = context->alt_regs[Z80_A]; | 3867 uint32_t ival; |
3405 } else if (tolower(name[1]) == 'f') { | 3868 if (!debug_cast_int(val, &ival)) { |
3406 if (!name[2]) { | 3869 fprintf(stderr, "Z80 register %s can only be set to an integer\n", z80_regs[var->val.v.u32]); |
3407 *out = context->regs[Z80_A] << 8; | 3870 return; |
3408 *out |= context->flags[ZF_S] << 7; | 3871 } |
3409 *out |= context->flags[ZF_Z] << 6; | 3872 context->regs[var->val.v.u32] = ival; |
3410 *out |= context->flags[ZF_H] << 4; | 3873 } |
3411 *out |= context->flags[ZF_PV] << 2; | 3874 |
3412 *out |= context->flags[ZF_N] << 1; | 3875 |
3413 *out |= context->flags[ZF_C]; | 3876 static debug_val z80_alt_reg8_get(debug_var *var) |
3414 } else if (name[2] == '\'' && !name[3]) { | 3877 { |
3415 *out = context->alt_regs[Z80_A] << 8; | 3878 z80_context *context = var->ptr; |
3416 *out |= context->alt_flags[ZF_S] << 7; | 3879 return debug_int(context->alt_regs[var->val.v.u32]); |
3417 *out |= context->alt_flags[ZF_Z] << 6; | 3880 } |
3418 *out |= context->alt_flags[ZF_H] << 4; | 3881 |
3419 *out |= context->alt_flags[ZF_PV] << 2; | 3882 static void z80_alt_reg8_set(debug_var *var, debug_val val) |
3420 *out |= context->alt_flags[ZF_N] << 1; | 3883 { |
3421 *out |= context->alt_flags[ZF_C]; | 3884 z80_context *context = var->ptr; |
3885 uint32_t ival; | |
3886 if (!debug_cast_int(val, &ival)) { | |
3887 fprintf(stderr, "Z80 register %s' can only be set to an integer\n", z80_regs[var->val.v.u32]); | |
3888 return; | |
3889 } | |
3890 context->alt_regs[var->val.v.u32] = ival; | |
3891 } | |
3892 | |
3893 static debug_val z80_flags_get(debug_var *var) | |
3894 { | |
3895 z80_context *context = var->ptr; | |
3896 debug_val ret; | |
3897 ret.type = DBG_VAL_U32; | |
3898 ret.v.u32 = context->flags[ZF_S] << 7; | |
3899 ret.v.u32 |= context->flags[ZF_Z] << 6; | |
3900 ret.v.u32 |= context->flags[ZF_H] << 4; | |
3901 ret.v.u32 |= context->flags[ZF_PV] << 2; | |
3902 ret.v.u32 |= context->flags[ZF_N] << 1; | |
3903 ret.v.u32 |= context->flags[ZF_C]; | |
3904 return ret; | |
3905 } | |
3906 | |
3907 static debug_val z80_alt_flags_get(debug_var *var) | |
3908 { | |
3909 z80_context *context = var->ptr; | |
3910 debug_val ret; | |
3911 ret.type = DBG_VAL_U32; | |
3912 ret.v.u32 = context->alt_flags[ZF_S] << 7; | |
3913 ret.v.u32 |= context->alt_flags[ZF_Z] << 6; | |
3914 ret.v.u32 |= context->alt_flags[ZF_H] << 4; | |
3915 ret.v.u32 |= context->alt_flags[ZF_PV] << 2; | |
3916 ret.v.u32 |= context->alt_flags[ZF_N] << 1; | |
3917 ret.v.u32 |= context->alt_flags[ZF_C]; | |
3918 return ret; | |
3919 } | |
3920 | |
3921 static void z80_flags_set(debug_var *var, debug_val val) | |
3922 { | |
3923 z80_context *context = var->ptr; | |
3924 uint32_t ival; | |
3925 if (!debug_cast_int(val, &ival)) { | |
3926 fprintf(stderr, "Z80 register F can only be set to an integer\n"); | |
3927 return; | |
3928 } | |
3929 context->flags[ZF_S] = ival >> 7 & 1; | |
3930 context->flags[ZF_Z] = ival >> 6 & 1; | |
3931 context->flags[ZF_H] = ival >> 4 & 1; | |
3932 context->flags[ZF_PV] = ival >> 2 & 1; | |
3933 context->flags[ZF_N] = ival >> 1 & 1; | |
3934 context->flags[ZF_C] = ival & 1; | |
3935 } | |
3936 | |
3937 static void z80_alt_flags_set(debug_var *var, debug_val val) | |
3938 { | |
3939 z80_context *context = var->ptr; | |
3940 uint32_t ival; | |
3941 if (!debug_cast_int(val, &ival)) { | |
3942 fprintf(stderr, "Z80 register F' can only be set to an integer\n"); | |
3943 return; | |
3944 } | |
3945 context->alt_flags[ZF_S] = ival >> 7 & 1; | |
3946 context->alt_flags[ZF_Z] = ival >> 6 & 1; | |
3947 context->alt_flags[ZF_H] = ival >> 4 & 1; | |
3948 context->alt_flags[ZF_PV] = ival >> 2 & 1; | |
3949 context->alt_flags[ZF_N] = ival >> 1 & 1; | |
3950 context->alt_flags[ZF_C] = ival & 1; | |
3951 } | |
3952 | |
3953 static debug_val z80_regpair_get(debug_var *var) | |
3954 { | |
3955 z80_context *context = var->ptr; | |
3956 debug_val ret; | |
3957 if (var->val.v.u32 == Z80_AF) { | |
3958 ret = z80_flags_get(var); | |
3959 ret.v.u32 |= context->regs[Z80_A] << 8; | |
3960 } else { | |
3961 ret = debug_int(context->regs[z80_high_reg(var->val.v.u32)] << 8 | context->regs[z80_low_reg(var->val.v.u32)]); | |
3962 } | |
3963 return ret; | |
3964 } | |
3965 | |
3966 static void z80_regpair_set(debug_var *var, debug_val val) | |
3967 { | |
3968 z80_context *context = var->ptr; | |
3969 uint32_t ival; | |
3970 if (!debug_cast_int(val, &ival)) { | |
3971 fprintf(stderr, "Z80 register %s can only be set to an integer\n", z80_regs[var->val.v.u32]); | |
3972 return; | |
3973 } | |
3974 if (var->val.v.u32 == Z80_AF) { | |
3975 context->regs[Z80_A] = ival >> 8; | |
3976 z80_flags_set(var, val); | |
3977 } else { | |
3978 context->regs[z80_high_reg(var->val.v.u32)] = ival >> 8; | |
3979 context->regs[z80_low_reg(var->val.v.u32)] = ival; | |
3980 } | |
3981 } | |
3982 | |
3983 static debug_val z80_alt_regpair_get(debug_var *var) | |
3984 { | |
3985 z80_context *context = var->ptr; | |
3986 debug_val ret; | |
3987 if (var->val.v.u32 == Z80_AF) { | |
3988 ret = z80_alt_flags_get(var); | |
3989 ret.v.u32 |= context->alt_regs[Z80_A] << 8; | |
3990 } else { | |
3991 ret = debug_int(context->alt_regs[z80_high_reg(var->val.v.u32)] << 8 | context->alt_regs[z80_low_reg(var->val.v.u32)]); | |
3992 } | |
3993 return ret; | |
3994 } | |
3995 | |
3996 static void z80_alt_regpair_set(debug_var *var, debug_val val) | |
3997 { | |
3998 z80_context *context = var->ptr; | |
3999 uint32_t ival; | |
4000 if (!debug_cast_int(val, &ival)) { | |
4001 fprintf(stderr, "Z80 register %s' can only be set to an integer\n", z80_regs[var->val.v.u32]); | |
4002 return; | |
4003 } | |
4004 if (var->val.v.u32 == Z80_AF) { | |
4005 context->regs[Z80_A] = ival >> 8; | |
4006 z80_alt_flags_set(var, val); | |
4007 } else { | |
4008 context->alt_regs[z80_high_reg(var->val.v.u32)] = ival >> 8; | |
4009 context->alt_regs[z80_low_reg(var->val.v.u32)] = ival; | |
4010 } | |
4011 } | |
4012 | |
4013 static debug_val z80_sp_get(debug_var *var) | |
4014 { | |
4015 z80_context *context = var->ptr; | |
4016 return debug_int(context->sp); | |
4017 } | |
4018 | |
4019 static void z80_sp_set(debug_var *var, debug_val val) | |
4020 { | |
4021 z80_context *context = var->ptr; | |
4022 uint32_t ival; | |
4023 if (!debug_cast_int(val, &ival)) { | |
4024 fprintf(stderr, "Z80 register sp can only be set to an integer\n"); | |
4025 return; | |
4026 } | |
4027 context->sp = ival; | |
4028 } | |
4029 | |
4030 static debug_val z80_im_get(debug_var *var) | |
4031 { | |
4032 z80_context *context = var->ptr; | |
4033 return debug_int(context->im); | |
4034 } | |
4035 | |
4036 static void z80_im_set(debug_var *var, debug_val val) | |
4037 { | |
4038 z80_context *context = var->ptr; | |
4039 uint32_t ival; | |
4040 if (!debug_cast_int(val, &ival)) { | |
4041 fprintf(stderr, "Z80 register im can only be set to an integer\n"); | |
4042 return; | |
4043 } | |
4044 context->im = ival & 3; | |
4045 } | |
4046 | |
4047 static debug_val z80_iff1_get(debug_var *var) | |
4048 { | |
4049 z80_context *context = var->ptr; | |
4050 return debug_int(context->iff1); | |
4051 } | |
4052 | |
4053 static void z80_iff1_set(debug_var *var, debug_val val) | |
4054 { | |
4055 z80_context *context = var->ptr; | |
4056 context->iff1 = debug_cast_bool(val); | |
4057 } | |
4058 | |
4059 static debug_val z80_iff2_get(debug_var *var) | |
4060 { | |
4061 z80_context *context = var->ptr; | |
4062 return debug_int(context->iff2); | |
4063 } | |
4064 | |
4065 static void z80_iff2_set(debug_var *var, debug_val val) | |
4066 { | |
4067 z80_context *context = var->ptr; | |
4068 context->iff2 = debug_cast_bool(val); | |
4069 } | |
4070 | |
4071 static debug_val z80_cycle_get(debug_var *var) | |
4072 { | |
4073 z80_context *context = var->ptr; | |
4074 return debug_int(context->current_cycle); | |
4075 } | |
4076 | |
4077 static debug_val z80_pc_get(debug_var *var) | |
4078 { | |
4079 z80_context *context = var->ptr; | |
4080 return debug_int(context->pc); | |
4081 } | |
4082 | |
4083 static void z80_names(debug_root *root) | |
4084 { | |
4085 debug_var *var; | |
4086 for (int i = 0; i < Z80_UNUSED; i++) | |
4087 { | |
4088 var = calloc(1, sizeof(debug_var)); | |
4089 var->ptr = root->cpu_context; | |
4090 if (i < Z80_BC) { | |
4091 var->get = z80_reg8_get; | |
4092 var->set = z80_reg8_set; | |
4093 } else if (i == Z80_SP) { | |
4094 var->get = z80_sp_get; | |
4095 var->set = z80_sp_set; | |
4096 } else { | |
4097 var->get = z80_regpair_get; | |
4098 var->set = z80_regpair_set; | |
4099 } | |
4100 var->val.v.u32 = i; | |
4101 root->variables = tern_insert_ptr(root->variables, z80_regs[i], var); | |
4102 size_t name_size = strlen(z80_regs[i]); | |
4103 char *name = malloc(name_size + 2); | |
4104 char *d = name; | |
4105 for (const char *c = z80_regs[i]; *c; c++, d++) | |
4106 { | |
4107 *d = toupper(*c); | |
4108 } | |
4109 name[name_size] = 0; | |
4110 root->variables = tern_insert_ptr(root->variables, name, var); | |
4111 | |
4112 if (i < Z80_IXL || (i > Z80_R && i < Z80_IX && i != Z80_SP)) { | |
4113 memcpy(name, z80_regs[i], name_size); | |
4114 name[name_size] = '\''; | |
4115 name[name_size + 1] = 0; | |
4116 var = calloc(1, sizeof(debug_var)); | |
4117 var->ptr = root->cpu_context; | |
4118 if (i < Z80_BC) { | |
4119 var->get = z80_alt_reg8_get; | |
4120 var->set = z80_alt_reg8_set; | |
3422 } else { | 4121 } else { |
3423 return 0; | 4122 var->get = z80_alt_regpair_get; |
3424 } | 4123 var->set = z80_alt_regpair_set; |
3425 } else { | 4124 } |
3426 return 0; | 4125 var->val.v.u32 = i; |
3427 } | 4126 root->variables = tern_insert_ptr(root->variables, name, var); |
3428 break; | 4127 d = name; |
3429 case 'b': | 4128 for (const char *c = z80_regs[i]; *c; c++, d++) |
3430 if (!name[1]) { | |
3431 *out = context->regs[Z80_B]; | |
3432 } else if (name[1] == '\'' && !name[2]) { | |
3433 *out = context->alt_regs[Z80_B]; | |
3434 } else if (tolower(name[1]) == 'c') { | |
3435 if (!name[2]) { | |
3436 *out = context->regs[Z80_B] << 8 | context->regs[Z80_C]; | |
3437 } else if (name[2] == '\'' && !name[3]) { | |
3438 *out = context->alt_regs[Z80_B] << 8 | context->alt_regs[Z80_C]; | |
3439 } else { | |
3440 return 0; | |
3441 } | |
3442 } | |
3443 break; | |
3444 case 'c': | |
3445 if (!name[1]) { | |
3446 *out = context->regs[Z80_C]; | |
3447 } else if (name[1] == '\'' && !name[2]) { | |
3448 *out = context->alt_regs[Z80_C]; | |
3449 } else if (!strcmp(name + 1, "ycle")) { | |
3450 *out = context->current_cycle; | |
3451 } else { | |
3452 return 0; | |
3453 } | |
3454 break; | |
3455 case 'd': | |
3456 if (!name[1]) { | |
3457 *out = context->regs[Z80_D]; | |
3458 } else if (name[1] == '\'' && !name[2]) { | |
3459 *out = context->alt_regs[Z80_D]; | |
3460 } else if (tolower(name[1]) == 'e') { | |
3461 if (!name[2]) { | |
3462 *out = context->regs[Z80_D] << 8 | context->regs[Z80_E]; | |
3463 } else if (name[2] == '\'' && !name[3]) { | |
3464 *out = context->alt_regs[Z80_D] << 8 | context->alt_regs[Z80_E]; | |
3465 } else { | |
3466 return 0; | |
3467 } | |
3468 } | |
3469 break; | |
3470 case 'e': | |
3471 if (!name[1]) { | |
3472 *out = context->regs[Z80_E]; | |
3473 } else if (name[1] == '\'' && !name[2]) { | |
3474 *out = context->alt_regs[Z80_E]; | |
3475 } else { | |
3476 return 0; | |
3477 } | |
3478 break; | |
3479 case 'f': | |
3480 if (!name[1]) { | |
3481 *out = context->flags[ZF_S] << 7; | |
3482 *out |= context->flags[ZF_Z] << 6; | |
3483 *out |= context->flags[ZF_H] << 4; | |
3484 *out |= context->flags[ZF_PV] << 2; | |
3485 *out |= context->flags[ZF_N] << 1; | |
3486 *out |= context->flags[ZF_C]; | |
3487 } else if (name[1] == '\'' && !name[2]) { | |
3488 *out = context->alt_flags[ZF_S] << 7; | |
3489 *out |= context->alt_flags[ZF_Z] << 6; | |
3490 *out |= context->alt_flags[ZF_H] << 4; | |
3491 *out |= context->alt_flags[ZF_PV] << 2; | |
3492 *out |= context->alt_flags[ZF_N] << 1; | |
3493 *out |= context->alt_flags[ZF_C]; | |
3494 } else { | |
3495 return 0; | |
3496 } | |
3497 break; | |
3498 case 'h': | |
3499 if (!name[1]) { | |
3500 *out = context->regs[Z80_H]; | |
3501 } else if (name[1] == '\'' && !name[2]) { | |
3502 *out = context->alt_regs[Z80_H]; | |
3503 } else if (tolower(name[1]) == 'l') { | |
3504 if (!name[2]) { | |
3505 *out = context->regs[Z80_H] << 8 | context->regs[Z80_L]; | |
3506 } else if (name[2] == '\'' && !name[3]) { | |
3507 *out = context->alt_regs[Z80_H] << 8 | context->alt_regs[Z80_L]; | |
3508 } else { | |
3509 return 0; | |
3510 } | |
3511 } | |
3512 break; | |
3513 case 'i': | |
3514 switch (tolower(name[1])) | |
3515 { | |
3516 case 0: | |
3517 *out = context->regs[Z80_I]; | |
3518 break; | |
3519 case 'f': | |
3520 if (name[2] != 'f' || name[3] < '1' || name[4]) { | |
3521 return 0; | |
3522 } | |
3523 if (name[3] == '1') { | |
3524 *out = context->iff1; | |
3525 } else if (name[3] == '2') { | |
3526 *out = context->iff2; | |
3527 } else { | |
3528 return 0; | |
3529 } | |
3530 break; | |
3531 case 'm': | |
3532 if (name[2]) { | |
3533 return 0; | |
3534 } | |
3535 *out = context->im; | |
3536 break; | |
3537 case 'n': | |
3538 if (strcasecmp(name +2, "t_cycle")) { | |
3539 return 0; | |
3540 } | |
3541 *out = context->int_cycle; | |
3542 break; | |
3543 case 'r': | |
3544 if (name[2]) { | |
3545 return 0; | |
3546 } | |
3547 *out = context->regs[Z80_I] << 8 | context->regs[Z80_R]; | |
3548 break; | |
3549 case 'x': | |
3550 switch (tolower(name[2])) | |
3551 { | 4129 { |
3552 case 0: | 4130 *d = toupper(*c); |
3553 *out = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL]; | 4131 } |
3554 break; | 4132 root->variables = tern_insert_ptr(root->variables, name, var); |
3555 case 'h': | 4133 } |
3556 if (name[3]) { | 4134 free(name); |
3557 return 0; | 4135 } |
3558 } | 4136 var = calloc(1, sizeof(debug_var)); |
3559 *out = context->regs[Z80_IXH]; | 4137 var->ptr = root->cpu_context; |
3560 case 'l': | 4138 var->get = z80_flags_get; |
3561 if (name[3]) { | 4139 var->set = z80_flags_set; |
3562 return 0; | 4140 root->variables = tern_insert_ptr(root->variables, "f", var); |
3563 } | 4141 root->variables = tern_insert_ptr(root->variables, "F", var); |
3564 *out = context->regs[Z80_IXL]; | 4142 var = calloc(1, sizeof(debug_var)); |
3565 default: | 4143 var->ptr = root->cpu_context; |
3566 return 0; | 4144 var->get = z80_alt_flags_get; |
3567 } | 4145 var->set = z80_alt_flags_set; |
3568 break; | 4146 root->variables = tern_insert_ptr(root->variables, "f'", var); |
3569 case 'y': | 4147 root->variables = tern_insert_ptr(root->variables, "F'", var); |
3570 switch (tolower(name[2])) | 4148 var = calloc(1, sizeof(debug_var)); |
3571 { | 4149 var->ptr = root->cpu_context; |
3572 case 0: | 4150 var->get = z80_im_get; |
3573 *out = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL]; | 4151 var->set = z80_im_set; |
3574 break; | 4152 root->variables = tern_insert_ptr(root->variables, "im", var); |
3575 case 'h': | 4153 root->variables = tern_insert_ptr(root->variables, "IM", var); |
3576 if (name[3]) { | 4154 var = calloc(1, sizeof(debug_var)); |
3577 return 0; | 4155 var->ptr = root->cpu_context; |
3578 } | 4156 var->get = z80_iff1_get; |
3579 *out = context->regs[Z80_IYH]; | 4157 var->set = z80_iff1_set; |
3580 case 'l': | 4158 root->variables = tern_insert_ptr(root->variables, "iff1", var); |
3581 if (name[3]) { | 4159 var = calloc(1, sizeof(debug_var)); |
3582 return 0; | 4160 var->ptr = root->cpu_context; |
3583 } | 4161 var->get = z80_iff2_get; |
3584 *out = context->regs[Z80_IYL]; | 4162 var->set = z80_iff2_set; |
3585 default: | 4163 root->variables = tern_insert_ptr(root->variables, "iff2", var); |
3586 return 0; | 4164 var = calloc(1, sizeof(debug_var)); |
3587 } | 4165 var->ptr = root->cpu_context; |
3588 break; | 4166 var->get = z80_cycle_get; |
3589 default: | 4167 root->variables = tern_insert_ptr(root->variables, "cycle", var); |
3590 return 0; | 4168 var = calloc(1, sizeof(debug_var)); |
3591 } | 4169 var->ptr = root->cpu_context; |
3592 break; | 4170 var->get = z80_pc_get; |
3593 case 'l': | 4171 root->variables = tern_insert_ptr(root->variables, "pc", var); |
3594 if (!name[1]) { | 4172 root->variables = tern_insert_ptr(root->variables, "PC", var); |
3595 *out = context->regs[Z80_L]; | |
3596 } else if (name[1] == '\'' && !name[2]) { | |
3597 *out = context->alt_regs[Z80_L]; | |
3598 } else { | |
3599 return 0; | |
3600 } | |
3601 break; | |
3602 case 'p': | |
3603 if (tolower(name[1]) != 'c' || name[2]) { | |
3604 return 0; | |
3605 } | |
3606 *out = root->address; | |
3607 break; | |
3608 case 'r': | |
3609 if (name[1]) { | |
3610 return 0; | |
3611 } | |
3612 *out = context->regs[Z80_R]; | |
3613 case 's': | |
3614 if (tolower(name[1]) != 'p' || name[2]) { | |
3615 return 0; | |
3616 } | |
3617 *out = context->sp; | |
3618 break; | |
3619 default: | |
3620 return 0; | |
3621 } | |
3622 return 1; | |
3623 } | |
3624 | |
3625 static uint8_t resolve_sms(debug_root *root, const char *name, uint32_t *out) | |
3626 { | |
3627 if (resolve_z80(root, name, out)) { | |
3628 return 1; | |
3629 } | |
3630 z80_context *z80 = root->cpu_context; | |
3631 sms_context *sms = z80->system; | |
3632 if (!strcmp(name, "f") || !strcmp(name, "frame")) { | |
3633 *out = sms->vdp->frame; | |
3634 return 1; | |
3635 } | |
3636 return 0; | |
3637 } | |
3638 | |
3639 static uint8_t set_z80(debug_root *root, const char *name, uint32_t value) | |
3640 { | |
3641 z80_context *context = root->cpu_context; | |
3642 switch (tolower(name[0])) | |
3643 { | |
3644 case 'a': | |
3645 if (!name[1]) { | |
3646 context->regs[Z80_A] = value; | |
3647 } else if (name[1] == '\'' && !name[2]) { | |
3648 context->alt_regs[Z80_A] = value; | |
3649 } else if (tolower(name[1]) == 'f') { | |
3650 if (!name[2]) { | |
3651 context->regs[Z80_A] = value >> 8; | |
3652 context->flags[ZF_S] = value >> 7 & 1; | |
3653 context->flags[ZF_Z] = value >> 6 & 1; | |
3654 context->flags[ZF_H] = value >> 4 & 1; | |
3655 context->flags[ZF_PV] = value >> 2 & 1; | |
3656 context->flags[ZF_N] = value >> 1 & 1; | |
3657 context->flags[ZF_C] = value & 1; | |
3658 } else if (name[2] == '\'' && !name[3]) { | |
3659 context->alt_regs[Z80_A] = value >> 8; | |
3660 context->alt_flags[ZF_S] = value >> 7 & 1; | |
3661 context->alt_flags[ZF_Z] = value >> 6 & 1; | |
3662 context->alt_flags[ZF_H] = value >> 4 & 1; | |
3663 context->alt_flags[ZF_PV] = value >> 2 & 1; | |
3664 context->alt_flags[ZF_N] = value >> 1 & 1; | |
3665 context->alt_flags[ZF_C] = value & 1; | |
3666 } else { | |
3667 return 0; | |
3668 } | |
3669 } else { | |
3670 return 0; | |
3671 } | |
3672 break; | |
3673 case 'b': | |
3674 if (!name[1]) { | |
3675 context->regs[Z80_B] = value; | |
3676 } else if (name[1] == '\'' && !name[2]) { | |
3677 context->alt_regs[Z80_B] = value; | |
3678 } else if (tolower(name[1]) == 'c') { | |
3679 if (!name[2]) { | |
3680 context->regs[Z80_B] = value >> 8; | |
3681 context->regs[Z80_C] = value; | |
3682 } else if (name[2] == '\'' && !name[3]) { | |
3683 context->alt_regs[Z80_B] = value >> 8; | |
3684 context->alt_regs[Z80_C] = value; | |
3685 } else { | |
3686 return 0; | |
3687 } | |
3688 } | |
3689 break; | |
3690 case 'c': | |
3691 if (!name[1]) { | |
3692 context->regs[Z80_C] = value; | |
3693 } else if (name[1] == '\'' && !name[2]) { | |
3694 context->alt_regs[Z80_C] = value; | |
3695 } else { | |
3696 return 0; | |
3697 } | |
3698 break; | |
3699 case 'd': | |
3700 if (!name[1]) { | |
3701 context->regs[Z80_D] = value; | |
3702 } else if (name[1] == '\'' && !name[2]) { | |
3703 context->alt_regs[Z80_D] = value; | |
3704 } else if (tolower(name[1]) == 'e') { | |
3705 if (!name[2]) { | |
3706 context->regs[Z80_D] = value >> 8; | |
3707 context->regs[Z80_E] = value; | |
3708 } else if (name[2] == '\'' && !name[3]) { | |
3709 context->alt_regs[Z80_D] = value >> 8; | |
3710 context->alt_regs[Z80_E] = value; | |
3711 } else { | |
3712 return 0; | |
3713 } | |
3714 } | |
3715 break; | |
3716 case 'e': | |
3717 if (!name[1]) { | |
3718 context->regs[Z80_E] = value; | |
3719 } else if (name[1] == '\'' && !name[2]) { | |
3720 context->alt_regs[Z80_E] = value; | |
3721 } else { | |
3722 return 0; | |
3723 } | |
3724 break; | |
3725 case 'f': | |
3726 if (!name[1]) { | |
3727 context->flags[ZF_S] = value >> 7 & 1; | |
3728 context->flags[ZF_Z] = value >> 6 & 1; | |
3729 context->flags[ZF_H] = value >> 4 & 1; | |
3730 context->flags[ZF_PV] = value >> 2 & 1; | |
3731 context->flags[ZF_N] = value >> 1 & 1; | |
3732 context->flags[ZF_C] = value & 1; | |
3733 } else if (name[1] == '\'' && !name[2]) { | |
3734 context->alt_flags[ZF_S] = value >> 7 & 1; | |
3735 context->alt_flags[ZF_Z] = value >> 6 & 1; | |
3736 context->alt_flags[ZF_H] = value >> 4 & 1; | |
3737 context->alt_flags[ZF_PV] = value >> 2 & 1; | |
3738 context->alt_flags[ZF_N] = value >> 1 & 1; | |
3739 context->alt_flags[ZF_C] = value & 1; | |
3740 } else { | |
3741 return 0; | |
3742 } | |
3743 break; | |
3744 case 'h': | |
3745 if (!name[1]) { | |
3746 context->regs[Z80_H] = value; | |
3747 } else if (name[1] == '\'' && !name[2]) { | |
3748 context->alt_regs[Z80_H] = value; | |
3749 } else if (tolower(name[1]) == 'e') { | |
3750 if (!name[2]) { | |
3751 context->regs[Z80_H] = value >> 8; | |
3752 context->regs[Z80_L] = value; | |
3753 } else if (name[2] == '\'' && !name[3]) { | |
3754 context->alt_regs[Z80_H] = value >> 8; | |
3755 context->alt_regs[Z80_L] = value; | |
3756 } else { | |
3757 return 0; | |
3758 } | |
3759 } | |
3760 break; | |
3761 case 'i': | |
3762 switch (tolower(name[1])) | |
3763 { | |
3764 case 0: | |
3765 context->regs[Z80_I] = value; | |
3766 break; | |
3767 case 'f': | |
3768 if (name[2] != 'f' || name[3] < '1' || name[4]) { | |
3769 return 0; | |
3770 } | |
3771 if (name[3] == '1') { | |
3772 context->iff1 = value != 0; | |
3773 } else if (name[3] == '2') { | |
3774 context->iff2 = value != 0; | |
3775 } else { | |
3776 return 0; | |
3777 } | |
3778 break; | |
3779 case 'm': | |
3780 if (name[2]) { | |
3781 return 0; | |
3782 } | |
3783 context->im = value & 3; | |
3784 break; | |
3785 case 'r': | |
3786 if (name[2]) { | |
3787 return 0; | |
3788 } | |
3789 context->regs[Z80_I] = value >> 8; | |
3790 context->regs[Z80_R] = value; | |
3791 break; | |
3792 case 'x': | |
3793 switch (tolower(name[2])) | |
3794 { | |
3795 case 0: | |
3796 context->regs[Z80_IXH] = value >> 8; | |
3797 context->regs[Z80_IXL] = value; | |
3798 break; | |
3799 case 'h': | |
3800 if (name[3]) { | |
3801 return 0; | |
3802 } | |
3803 context->regs[Z80_IXH] = value; | |
3804 case 'l': | |
3805 if (name[3]) { | |
3806 return 0; | |
3807 } | |
3808 context->regs[Z80_IXL] = value; | |
3809 default: | |
3810 return 0; | |
3811 } | |
3812 break; | |
3813 case 'y': | |
3814 switch (tolower(name[2])) | |
3815 { | |
3816 case 0: | |
3817 context->regs[Z80_IYH] = value >> 8; | |
3818 context->regs[Z80_IYL] = value; | |
3819 break; | |
3820 case 'h': | |
3821 if (name[3]) { | |
3822 return 0; | |
3823 } | |
3824 context->regs[Z80_IYH] = value; | |
3825 case 'l': | |
3826 if (name[3]) { | |
3827 return 0; | |
3828 } | |
3829 context->regs[Z80_IYL] = value; | |
3830 default: | |
3831 return 0; | |
3832 } | |
3833 break; | |
3834 default: | |
3835 return 0; | |
3836 } | |
3837 break; | |
3838 case 'l': | |
3839 if (!name[1]) { | |
3840 context->regs[Z80_L] = value; | |
3841 } else if (name[1] == '\'' && !name[2]) { | |
3842 context->alt_regs[Z80_L] = value; | |
3843 } else { | |
3844 return 0; | |
3845 } | |
3846 break; | |
3847 case 'r': | |
3848 if (name[1]) { | |
3849 return 0; | |
3850 } | |
3851 context->regs[Z80_R] = value; | |
3852 case 's': | |
3853 if (tolower(name[1]) != 'p' || name[2]) { | |
3854 return 0; | |
3855 } | |
3856 context->sp = value; | |
3857 break; | |
3858 default: | |
3859 return 0; | |
3860 } | |
3861 return 1; | |
3862 } | 4173 } |
3863 | 4174 |
3864 debug_root *find_z80_root(z80_context *context) | 4175 debug_root *find_z80_root(z80_context *context) |
3865 { | 4176 { |
3866 debug_root *root = find_root(context); | 4177 debug_root *root = find_root(context); |
3867 if (root && !root->commands) { | 4178 if (root && !root->commands) { |
3868 add_commands(root, common_commands, NUM_COMMON); | 4179 add_commands(root, common_commands, NUM_COMMON); |
3869 add_commands(root, z80_commands, NUM_Z80); | 4180 add_commands(root, z80_commands, NUM_Z80); |
4181 z80_names(root); | |
4182 genesis_context *gen; | |
4183 sms_context *sms; | |
4184 debug_var *var; | |
4185 //TODO: populate names | |
3870 switch (current_system->type) | 4186 switch (current_system->type) |
3871 { | 4187 { |
3872 case SYSTEM_GENESIS: | 4188 case SYSTEM_GENESIS: |
3873 case SYSTEM_SEGACD: | 4189 case SYSTEM_SEGACD: |
4190 gen = context->system; | |
3874 add_commands(root, gen_z80_commands, NUM_GEN_Z80); | 4191 add_commands(root, gen_z80_commands, NUM_GEN_Z80); |
3875 root->resolve = resolve_z80; | 4192 root->other_roots = tern_insert_ptr(root->other_roots, "m68k", find_m68k_root(gen->m68k)); |
4193 //root->resolve = resolve_z80; | |
3876 break; | 4194 break; |
3877 case SYSTEM_SMS: | 4195 case SYSTEM_SMS: |
3878 root->resolve = resolve_sms; | 4196 sms = context->system; |
3879 add_commands(root, sms_commands, NUM_SMS); | 4197 add_commands(root, sms_commands, NUM_SMS); |
4198 root->other_roots = tern_insert_ptr(root->other_roots, "vdp", find_vdp_root(sms->vdp)); | |
4199 root->other_roots = tern_insert_ptr(root->other_roots, "psg", find_psg_root(sms->psg)); | |
4200 var = calloc(1, sizeof(debug_var)); | |
4201 var->get = debug_frame_get; | |
4202 var->ptr = sms->vdp; | |
4203 root->variables = tern_insert_ptr(root->variables, "frame", var); | |
3880 break; | 4204 break; |
3881 default: | 4205 //default: |
3882 root->resolve = resolve_z80; | 4206 //root->resolve = resolve_z80; |
3883 } | 4207 } |
3884 root->array_resolve = resolve_null_array; | |
3885 root->read_mem = read_z80; | 4208 root->read_mem = read_z80; |
3886 root->write_mem = write_z80; | 4209 root->write_mem = write_z80; |
3887 root->set = set_z80; | |
3888 root->disasm = create_z80_disasm(); | 4210 root->disasm = create_z80_disasm(); |
3889 } | 4211 } |
3890 return root; | 4212 return root; |
3891 } | 4213 } |
3892 | 4214 |
3904 root->address = address; | 4226 root->address = address; |
3905 //Check if this is a user set breakpoint, or just a temporary one | 4227 //Check if this is a user set breakpoint, or just a temporary one |
3906 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address, BP_TYPE_CPU); | 4228 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address, BP_TYPE_CPU); |
3907 if (*this_bp) { | 4229 if (*this_bp) { |
3908 if ((*this_bp)->condition) { | 4230 if ((*this_bp)->condition) { |
3909 uint32_t condres; | 4231 debug_val condres; |
3910 if (eval_expr(root, (*this_bp)->condition, &condres)) { | 4232 if (eval_expr(root, (*this_bp)->condition, &condres)) { |
3911 if (!condres) { | 4233 if (!condres.v.u32) { |
3912 return context; | 4234 return context; |
3913 } | 4235 } |
3914 } else { | 4236 } else { |
3915 fprintf(stderr, "Failed to eval condition for Z80 breakpoint %u\n", (*this_bp)->index); | 4237 fprintf(stderr, "Failed to eval condition for Z80 breakpoint %u\n", (*this_bp)->index); |
3916 free_expr((*this_bp)->condition); | 4238 free_expr((*this_bp)->condition); |
3993 int debugging = 1; | 4315 int debugging = 1; |
3994 //Check if this is a user set breakpoint, or just a temporary one | 4316 //Check if this is a user set breakpoint, or just a temporary one |
3995 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address, BP_TYPE_CPU); | 4317 bp_def ** this_bp = find_breakpoint(&root->breakpoints, address, BP_TYPE_CPU); |
3996 if (*this_bp) { | 4318 if (*this_bp) { |
3997 if ((*this_bp)->condition) { | 4319 if ((*this_bp)->condition) { |
3998 uint32_t condres; | 4320 debug_val condres; |
3999 if (eval_expr(root, (*this_bp)->condition, &condres)) { | 4321 if (eval_expr(root, (*this_bp)->condition, &condres)) { |
4000 if (!condres) { | 4322 if (!condres.v.u32) { |
4001 return; | 4323 return; |
4002 } | 4324 } |
4003 } else { | 4325 } else { |
4004 fprintf(stderr, "Failed to eval condition for M68K breakpoint %u\n", (*this_bp)->index); | 4326 fprintf(stderr, "Failed to eval condition for M68K breakpoint %u\n", (*this_bp)->index); |
4005 free_expr((*this_bp)->condition); | 4327 free_expr((*this_bp)->condition); |