1 /*
2 * Code to test Hatari conditional breakpoints in src/debug/breakcond.c
3 * (both matching and setting CPU and DSP breakpoints)
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
SetCpuRegister(const char * regname,Uint32 value)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
main(int argc,const char * argv[])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",
78 "&& pc = 2",
79 "pc = 2 &&",
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 }
265