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