|
|
1.1 root 1: /*
2: * Code to test Hatari conditional breakpoints in src/debug/breakcond.c
1.1.1.2 root 3: * (both matching and setting CPU and DSP breakpoints)
1.1 root 4: */
5: #include "main.h"
6: #include "dsp.h"
7: #include "debugcpu.h"
8: #include "breakcond.h"
9: #include "stMemory.h"
10: #include "newcpu.h"
11:
12: #define BITMASK(x) ((1<<(x))-1)
13:
14: /* BreakCond_Command() command strings */
15: #define CMD_LIST NULL
16: #define CMD_REMOVE_ALL "all"
17:
18:
19: static bool SetCpuRegister(const char *regname, Uint32 value)
20: {
21: Uint32 *addr;
22:
23: switch (DebugCpu_GetRegisterAddress(regname, &addr)) {
24: case 32:
25: *addr = value;
26: break;
27: case 16:
28: *(Uint16*)addr = value;
29: break;
30: default:
31: fprintf(stderr, "SETUP ERROR: Register '%s' to set (to %x) is unrecognized!\n", regname, value);
32: return false;
33: }
34: return true;
35: }
36:
37: #if 0
38: static bool SetDspRegister(const char *regname, Uint32 value)
39: {
40: Uint32 *addr, mask;
41:
42: switch (DSP_GetRegisterAddress(regname, &addr, &mask)) {
43: case 32:
44: *addr = value & mask;
45: break;
46: case 16:
47: *(Uint16*)addr = value & mask;
48: break;
49: default:
50: return false;
51: }
52: return true;
53: }
54: #endif
55:
56: int main(int argc, const char *argv[])
57: {
58: const char *parser_fail[] = {
59: /* syntax & register name errors */
60: "",
61: " = ",
62: " a0 d0 ",
63: "gggg=a0",
64: "=a=b=",
65: "a0=d0=20",
66: "a0=d || 0=20",
67: "a0=d & 0=20",
68: ".w&3=2",
69: "d0 = %200",
70: "d0 = \"ICE!BAR",
71: "pc > $200 :foobar",
72: "foo().w=bar()",
73: "(a0.w=d0.l)",
74: "(a0&3)=20",
75: "20 = (a0.w)",
76: "()&=d0",
77: "d0=().w",
1.1.1.3 ! root 78: "&& pc = 2",
! 79: "pc = 2 &&",
1.1 root 80: "255 & 3 = (d0) & && 2 = 2",
81: /* missing options file */
82: "pc>pc :file no-such-file",
83: /* size and mask mismatches with numbers */
84: "d0.w = $ffff0",
85: "(a0).b & 3 < 100",
86: NULL
87: };
88: const char *parser_pass[] = {
89: /* comparisons with normal numbers + indrect addressing */
90: " ($200).w > 200 ",
91: " ($200).w < 200 ",
92: " (200).w = $200 ",
93: " (200).w ! $200 ",
94: /* indirect addressing with registers */
95: "(a0)=(d0)",
96: "(d0).w=(a0).b",
97: /* sizes + multiple conditions + spacing */
98: "(a0).w&3=(d0)&&d0=1",
99: " ( a 0 ) . w & 1 = ( d 0 ) & 1 && d 0 = 3 ",
100: "a0=1 && (d0)&2=(a0).w && ($00ff00).w&1=1",
101: " ($ff820a).b = 2",
102: /* variables */
103: "hbl > 0 && vbl < 2000 && linecycles = 508",
104: /* options */
105: "($200).w ! ($200).w :trace",
106: "($200).w > ($200).w :4 :lock",
107: "pc>pc :file data/test.ini :once",
108: NULL
109: };
110: /* address breakpoint + expression evalution with register */
111: char addr_pass[] = "pc + ($200*16/2 & 0xffff)";
112:
113: const char *match_tests[] = {
114: "a0 = d0",
115: "( $200 ) . b > 200", /* byte access to avoid endianess */
116: "pc < $50000 && pc > $60000",
117: "pc > $50000 && pc < $54000",
118: #define FAILING_BC_TEST_MATCHES 4
119: "pc > $50000 && pc < $60000",
120: "( $200 ) . b > ( 200 ) . b",
121: "d0 = d1",
122: "a0 = pc",
123: NULL
124: };
125: const char *test;
126: char testidx[2] = "1";
127: int i, j, tests = 0, errors = 0;
128: int remaining_matches;
129: bool use_dsp;
130:
131: /* first automated tests... */
132: use_dsp = false;
133: fprintf(stderr, "\nShould FAIL for CPU:\n");
134: for (i = 0; (test = parser_fail[i]); i++) {
135: fprintf(stderr, "-----------------\n- parsing '%s'\n", test);
136: if (BreakCond_Command(test, use_dsp)) {
137: fprintf(stderr, "***ERROR***: should have failed\n");
138: errors++;
139: }
140: }
141: tests += i;
142: fprintf(stderr, "-----------------\n\n");
143: BreakCond_Command(CMD_LIST, use_dsp);
144:
145: fprintf(stderr, "\nShould PASS for CPU:\n");
146: for (i = 0; (test = parser_pass[i]); i++) {
147: fprintf(stderr, "-----------------\n- parsing '%s'\n", test);
148: if (!BreakCond_Command(test, use_dsp)) {
149: fprintf(stderr, "***ERROR***: should have passed\n");
150: errors++;
151: }
152: }
153: tests += i;
154: fprintf(stderr, "\nAddress PASS test for CPU:\n");
155: if (!BreakAddr_Command(addr_pass, use_dsp)) {
156: fprintf(stderr, "***ERROR***: should have passed\n");
157: errors++;
158: }
159: tests += 1;
160:
161: fprintf(stderr, "-----------------\n\n");
162: BreakCond_Command(CMD_LIST, use_dsp);
163: fprintf(stderr, "\n");
164: BreakCond_Command(CMD_REMOVE_ALL, use_dsp);
165: BreakCond_Command(CMD_LIST, use_dsp);
166: fprintf(stderr, "-----------------\n");
167:
168: /* add conditions */
169: fprintf(stderr, "\nLast one(s) should match, first one(s) shouldn't:\n");
170: for (i = 0; (test = match_tests[i]); i++) {
171: fprintf(stderr, "-----------------\n- parsing '%s'\n", test);
172: if (!BreakCond_Command(test, use_dsp)) {
173: fprintf(stderr, "***ERROR***: should have passed\n");
174: errors++;
175: }
176: }
177: tests += i;
178: BreakCond_Command(CMD_LIST, use_dsp);
179: fprintf(stderr, "\n");
180:
181: /* set up registers etc */
182:
183: /* fail indirect equality checks with zerod regs */
184: memset(STRam, 0, sizeof(STRam));
185: STRam[0] = 1;
186: /* !match: "( $200 ) > 200"
187: * match: "( $200 ) . w > ( 200 ) . b"
188: */
189: STRam[0x200] = 100;
190: STRam[200] = 0x20;
191: /* match: "d0 = d1" */
192: SetCpuRegister("d0", 4);
193: SetCpuRegister("d1", 4);
194: /* !match: "pc < $50000 && pc > $60000"
195: * !match: "pc < $50000 && pc > $54000"
196: * match: "pc > $50000 && pc < $60000"
197: */
198: regs.pc = 0x58000;
199: /* !match: "d0 = a0"
200: * match: "pc = a0"
201: */
202: SetCpuRegister("a0", 0x58000);
203:
204: /* check matches */
205: while ((i = BreakCond_MatchCpu())) {
206: fprintf(stderr, "Removing matching CPU breakpoint %d...\n", i);
207: for (j = 0; (test = match_tests[j]); j++) {
208: if (BreakCond_MatchCpuExpression(i, test)) {
209: break;
210: }
211: }
212: if (test) {
213: if (j < FAILING_BC_TEST_MATCHES) {
214: fprintf(stderr, "ERROR: breakpoint should not have matched!\n");
215: errors++;
216: }
217: } else {
218: fprintf(stderr, "WARNING: canonized breakpoint form didn't match\n");
219: errors++;
220: }
221: testidx[0] = '0' + i;
222: BreakCond_Command(testidx, use_dsp); /* remove given */
223: }
224: remaining_matches = BreakCond_BreakPointCount(use_dsp);
225: if (remaining_matches != FAILING_BC_TEST_MATCHES) {
226: fprintf(stderr, "ERROR: wrong number of breakpoints left (%d instead of %d)!\n",
227: remaining_matches, FAILING_BC_TEST_MATCHES);
228: errors++;
229: }
230:
231: fprintf(stderr, "\nOther breakpoints didn't match, removing the rest...\n");
232: BreakCond_Command(CMD_REMOVE_ALL, use_dsp);
233: BreakCond_Command(CMD_LIST, use_dsp);
234: fprintf(stderr, "-----------------\n");
235:
236: /* ...last parse cmd line args as DSP breakpoints */
237: if (argc > 1) {
238: use_dsp = true;
239: fprintf(stderr, "\nCommand line DSP breakpoints:\n");
240: for (argv++; --argc > 0; argv++) {
241: fprintf(stderr, "-----------------\n- parsing '%s'\n", *argv);
242: BreakCond_Command(*argv, use_dsp);
243: }
244: fprintf(stderr, "-----------------\n\n");
245: BreakCond_Command("", use_dsp); /* list */
246:
247: while ((i = BreakCond_MatchDsp())) {
248: fprintf(stderr, "Removing matching DSP breakpoint.\n");
249: testidx[0] = '0' + i;
250: BreakCond_Command(testidx, use_dsp); /* remove given */
251: }
252:
253: BreakCond_Command(CMD_REMOVE_ALL, use_dsp);
254: BreakCond_Command(CMD_LIST, use_dsp);
255: fprintf(stderr, "-----------------\n");
256: }
257: if (errors) {
258: fprintf(stderr, "\n***Detected %d ERRORs in %d automated tests!***\n\n",
259: errors, tests);
260: } else {
261: fprintf(stderr, "\nFinished without any errors!\n\n");
262: }
263: return errors;
264: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.