mirror of
https://github.com/Wiimpathy/HatariWii.git
synced 2024-11-22 17:59:14 +01:00
265 lines
6.7 KiB
C
265 lines
6.7 KiB
C
/*
|
|
* Code to test Hatari conditional breakpoints in src/debug/breakcond.c
|
|
* (both matching and setting CPU and DSP breakpoints)
|
|
*/
|
|
#include "main.h"
|
|
#include "dsp.h"
|
|
#include "debugcpu.h"
|
|
#include "breakcond.h"
|
|
#include "stMemory.h"
|
|
#include "newcpu.h"
|
|
|
|
#define BITMASK(x) ((1<<(x))-1)
|
|
|
|
/* BreakCond_Command() command strings */
|
|
#define CMD_LIST NULL
|
|
#define CMD_REMOVE_ALL "all"
|
|
|
|
|
|
static bool SetCpuRegister(const char *regname, Uint32 value)
|
|
{
|
|
Uint32 *addr;
|
|
|
|
switch (DebugCpu_GetRegisterAddress(regname, &addr)) {
|
|
case 32:
|
|
*addr = value;
|
|
break;
|
|
case 16:
|
|
*(Uint16*)addr = value;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "SETUP ERROR: Register '%s' to set (to %x) is unrecognized!\n", regname, value);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#if 0
|
|
static bool SetDspRegister(const char *regname, Uint32 value)
|
|
{
|
|
Uint32 *addr, mask;
|
|
|
|
switch (DSP_GetRegisterAddress(regname, &addr, &mask)) {
|
|
case 32:
|
|
*addr = value & mask;
|
|
break;
|
|
case 16:
|
|
*(Uint16*)addr = value & mask;
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
int main(int argc, const char *argv[])
|
|
{
|
|
const char *parser_fail[] = {
|
|
/* syntax & register name errors */
|
|
"",
|
|
" = ",
|
|
" a0 d0 ",
|
|
"gggg=a0",
|
|
"=a=b=",
|
|
"a0=d0=20",
|
|
"a0=d || 0=20",
|
|
"a0=d & 0=20",
|
|
".w&3=2",
|
|
"d0 = %200",
|
|
"d0 = \"ICE!BAR",
|
|
"pc > $200 :foobar",
|
|
"foo().w=bar()",
|
|
"(a0.w=d0.l)",
|
|
"(a0&3)=20",
|
|
"20 = (a0.w)",
|
|
"()&=d0",
|
|
"d0=().w",
|
|
"&& pc = 2",
|
|
"pc = 2 &&",
|
|
"255 & 3 = (d0) & && 2 = 2",
|
|
/* missing options file */
|
|
"pc>pc :file no-such-file",
|
|
/* size and mask mismatches with numbers */
|
|
"d0.w = $ffff0",
|
|
"(a0).b & 3 < 100",
|
|
NULL
|
|
};
|
|
const char *parser_pass[] = {
|
|
/* comparisons with normal numbers + indrect addressing */
|
|
" ($200).w > 200 ",
|
|
" ($200).w < 200 ",
|
|
" (200).w = $200 ",
|
|
" (200).w ! $200 ",
|
|
/* indirect addressing with registers */
|
|
"(a0)=(d0)",
|
|
"(d0).w=(a0).b",
|
|
/* sizes + multiple conditions + spacing */
|
|
"(a0).w&3=(d0)&&d0=1",
|
|
" ( a 0 ) . w & 1 = ( d 0 ) & 1 && d 0 = 3 ",
|
|
"a0=1 && (d0)&2=(a0).w && ($00ff00).w&1=1",
|
|
" ($ff820a).b = 2",
|
|
/* variables */
|
|
"hbl > 0 && vbl < 2000 && linecycles = 508",
|
|
/* options */
|
|
"($200).w ! ($200).w :trace",
|
|
"($200).w > ($200).w :4 :lock",
|
|
"pc>pc :file data/test.ini :once",
|
|
NULL
|
|
};
|
|
/* address breakpoint + expression evalution with register */
|
|
char addr_pass[] = "pc + ($200*16/2 & 0xffff)";
|
|
|
|
const char *match_tests[] = {
|
|
"a0 = d0",
|
|
"( $200 ) . b > 200", /* byte access to avoid endianess */
|
|
"pc < $50000 && pc > $60000",
|
|
"pc > $50000 && pc < $54000",
|
|
#define FAILING_BC_TEST_MATCHES 4
|
|
"pc > $50000 && pc < $60000",
|
|
"( $200 ) . b > ( 200 ) . b",
|
|
"d0 = d1",
|
|
"a0 = pc",
|
|
NULL
|
|
};
|
|
const char *test;
|
|
char testidx[2] = "1";
|
|
int i, j, tests = 0, errors = 0;
|
|
int remaining_matches;
|
|
bool use_dsp;
|
|
|
|
/* first automated tests... */
|
|
use_dsp = false;
|
|
fprintf(stderr, "\nShould FAIL for CPU:\n");
|
|
for (i = 0; (test = parser_fail[i]); i++) {
|
|
fprintf(stderr, "-----------------\n- parsing '%s'\n", test);
|
|
if (BreakCond_Command(test, use_dsp)) {
|
|
fprintf(stderr, "***ERROR***: should have failed\n");
|
|
errors++;
|
|
}
|
|
}
|
|
tests += i;
|
|
fprintf(stderr, "-----------------\n\n");
|
|
BreakCond_Command(CMD_LIST, use_dsp);
|
|
|
|
fprintf(stderr, "\nShould PASS for CPU:\n");
|
|
for (i = 0; (test = parser_pass[i]); i++) {
|
|
fprintf(stderr, "-----------------\n- parsing '%s'\n", test);
|
|
if (!BreakCond_Command(test, use_dsp)) {
|
|
fprintf(stderr, "***ERROR***: should have passed\n");
|
|
errors++;
|
|
}
|
|
}
|
|
tests += i;
|
|
fprintf(stderr, "\nAddress PASS test for CPU:\n");
|
|
if (!BreakAddr_Command(addr_pass, use_dsp)) {
|
|
fprintf(stderr, "***ERROR***: should have passed\n");
|
|
errors++;
|
|
}
|
|
tests += 1;
|
|
|
|
fprintf(stderr, "-----------------\n\n");
|
|
BreakCond_Command(CMD_LIST, use_dsp);
|
|
fprintf(stderr, "\n");
|
|
BreakCond_Command(CMD_REMOVE_ALL, use_dsp);
|
|
BreakCond_Command(CMD_LIST, use_dsp);
|
|
fprintf(stderr, "-----------------\n");
|
|
|
|
/* add conditions */
|
|
fprintf(stderr, "\nLast one(s) should match, first one(s) shouldn't:\n");
|
|
for (i = 0; (test = match_tests[i]); i++) {
|
|
fprintf(stderr, "-----------------\n- parsing '%s'\n", test);
|
|
if (!BreakCond_Command(test, use_dsp)) {
|
|
fprintf(stderr, "***ERROR***: should have passed\n");
|
|
errors++;
|
|
}
|
|
}
|
|
tests += i;
|
|
BreakCond_Command(CMD_LIST, use_dsp);
|
|
fprintf(stderr, "\n");
|
|
|
|
/* set up registers etc */
|
|
|
|
/* fail indirect equality checks with zerod regs */
|
|
memset(STRam, 0, sizeof(STRam));
|
|
STMemory_WriteByte(0, 1);
|
|
/* !match: "( $200 ) > 200"
|
|
* match: "( $200 ) . w > ( 200 ) . b"
|
|
*/
|
|
STMemory_WriteByte(0x200, 100);
|
|
STMemory_WriteByte(200, 0x20);
|
|
/* match: "d0 = d1" */
|
|
SetCpuRegister("d0", 4);
|
|
SetCpuRegister("d1", 4);
|
|
/* !match: "pc < $50000 && pc > $60000"
|
|
* !match: "pc < $50000 && pc > $54000"
|
|
* match: "pc > $50000 && pc < $60000"
|
|
*/
|
|
regs.pc = 0x58000;
|
|
/* !match: "d0 = a0"
|
|
* match: "pc = a0"
|
|
*/
|
|
SetCpuRegister("a0", 0x58000);
|
|
|
|
/* check matches */
|
|
while ((i = BreakCond_MatchCpu())) {
|
|
fprintf(stderr, "Removing matching CPU breakpoint %d...\n", i);
|
|
for (j = 0; (test = match_tests[j]); j++) {
|
|
if (BreakCond_MatchCpuExpression(i, test)) {
|
|
break;
|
|
}
|
|
}
|
|
if (test) {
|
|
if (j < FAILING_BC_TEST_MATCHES) {
|
|
fprintf(stderr, "ERROR: breakpoint should not have matched!\n");
|
|
errors++;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "WARNING: canonized breakpoint form didn't match\n");
|
|
errors++;
|
|
}
|
|
testidx[0] = '0' + i;
|
|
BreakCond_Command(testidx, use_dsp); /* remove given */
|
|
}
|
|
remaining_matches = BreakCond_CpuBreakPointCount();
|
|
if (remaining_matches != FAILING_BC_TEST_MATCHES) {
|
|
fprintf(stderr, "ERROR: wrong number of breakpoints left (%d instead of %d)!\n",
|
|
remaining_matches, FAILING_BC_TEST_MATCHES);
|
|
errors++;
|
|
}
|
|
|
|
fprintf(stderr, "\nOther breakpoints didn't match, removing the rest...\n");
|
|
BreakCond_Command(CMD_REMOVE_ALL, use_dsp);
|
|
BreakCond_Command(CMD_LIST, use_dsp);
|
|
fprintf(stderr, "-----------------\n");
|
|
|
|
/* ...last parse cmd line args as DSP breakpoints */
|
|
if (argc > 1) {
|
|
use_dsp = true;
|
|
fprintf(stderr, "\nCommand line DSP breakpoints:\n");
|
|
for (argv++; --argc > 0; argv++) {
|
|
fprintf(stderr, "-----------------\n- parsing '%s'\n", *argv);
|
|
BreakCond_Command(*argv, use_dsp);
|
|
}
|
|
fprintf(stderr, "-----------------\n\n");
|
|
BreakCond_Command("", use_dsp); /* list */
|
|
|
|
while ((i = BreakCond_MatchDsp())) {
|
|
fprintf(stderr, "Removing matching DSP breakpoint.\n");
|
|
testidx[0] = '0' + i;
|
|
BreakCond_Command(testidx, use_dsp); /* remove given */
|
|
}
|
|
|
|
BreakCond_Command(CMD_REMOVE_ALL, use_dsp);
|
|
BreakCond_Command(CMD_LIST, use_dsp);
|
|
fprintf(stderr, "-----------------\n");
|
|
}
|
|
if (errors) {
|
|
fprintf(stderr, "\n***Detected %d ERRORs in %d automated tests!***\n\n",
|
|
errors, tests);
|
|
} else {
|
|
fprintf(stderr, "\nFinished without any errors!\n\n");
|
|
}
|
|
return errors;
|
|
}
|