riscv-compliance: incorporate review feedback

riscv-compliance
Megan Wachs 2018-08-30 11:26:05 -07:00
parent 34ee883aef
commit 934440b80e
1 changed files with 108 additions and 123 deletions

View File

@ -3058,6 +3058,21 @@ void riscv013_clear_abstract_error(struct target *target)
total_tests++; \ total_tests++; \
} }
#define COMPLIANCE_MUST_PASS(b) COMPLIANCE_TEST(ERROR_OK == (b), "Regular calls must return ERROR_OK")
#define COMPLIANCE_READ(target, addr, value) COMPLIANCE_MUST_PASS(dmi_read(target, addr, value))
#define COMPLIANCE_WRITE(target, addr, value) COMPLIANCE_MUST_PASS(dmi_write(target, addr, value))
#define COMPLIANCE_CHECK_RO(target, addr) \
{ \
uint32_t orig; \
uint32_t inverse; \
COMPLIANCE_READ(target, &orig, addr); \
COMPLIANCE_WRITE(target, addr, ~orig); \
COMPLIANCE_READ(target, &inverse, addr); \
COMPLIANCE_TEST(orig == inverse, "Register must be read-only"); \
}
int riscv013_test_compliance(struct target *target) int riscv013_test_compliance(struct target *target)
{ {
LOG_INFO("Testing Compliance against RISC-V Debug Spec v0.13"); LOG_INFO("Testing Compliance against RISC-V Debug Spec v0.13");
@ -3077,71 +3092,48 @@ int riscv013_test_compliance(struct target *target)
riscv_reg_t value; riscv_reg_t value;
RISCV013_INFO(info); RISCV013_INFO(info);
/* TODO: Support HARTSELLHI as well */ /* All the bits of HARTSEL is covered by the examine sequence. */
dmcontrol = dmcontrol_orig | DMI_DMCONTROL_HARTSELLO;
dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
COMPLIANCE_TEST(get_field(dmcontrol, DMI_DMCONTROL_HARTSELLO) == (uint32_t) ((1 << info->hartsellen) - 1),
"DMCONTROL.hartsello should hold all the harts allowed by its hartsellen.");
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTSELLO, 0);
dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
COMPLIANCE_TEST(get_field(dmcontrol, DMI_DMCONTROL_HARTSELLO) == 0,
"DMCONTROL.hartsello should hold Hart ID 0");
/* hartreset */ /* hartreset */
/* This field is optional. Either we can read and write it to 1/0, /* This field is optional. Either we can read and write it to 1/0,
or it is tied to 0. */ or it is tied to 0. This check doesn't really do anything, but
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1); it does attempt to set the bit to 1 and then back to 0, which needs to
dmi_write(target, DMI_DMCONTROL, dmcontrol); work if its implemented. */
dmi_read(target, &dmcontrol, DMI_DMCONTROL); COMPLIANCE_WRITE(target, DMI_DMCONTROL, set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1));
testvar = get_field(dmcontrol, DMI_DMCONTROL_HARTRESET); COMPLIANCE_WRITE(target, DMI_DMCONTROL, set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 0));
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 0); COMPLIANCE_READ(target, &dmcontrol, DMI_DMCONTROL);
dmi_write(target, DMI_DMCONTROL, dmcontrol); COMPLIANCE_TEST((get_field(dmcontrol, DMI_DMCONTROL_HARTRESET) == 0),
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
COMPLIANCE_TEST(((testvar == 0) || (get_field(dmcontrol, DMI_DMCONTROL_HARTRESET)) == 0),
"DMCONTROL.hartreset can be 0 or RW."); "DMCONTROL.hartreset can be 0 or RW.");
/* hasel */ /* hasel */
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1); COMPLIANCE_WRITE(target, DMI_DMCONTROL, set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1));
dmi_write(target, DMI_DMCONTROL, dmcontrol); COMPLIANCE_WRITE(target, DMI_DMCONTROL, set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 0));
dmi_read(target, &dmcontrol, DMI_DMCONTROL); COMPLIANCE_READ(target, &dmcontrol, DMI_DMCONTROL);
testvar = get_field(dmcontrol, DMI_DMCONTROL_HASEL); COMPLIANCE_TEST((get_field(dmcontrol, DMI_DMCONTROL_HASEL) == 0),
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 0);
dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
COMPLIANCE_TEST(((testvar == 0) || (get_field(dmcontrol, DMI_DMCONTROL_HASEL)) == 0),
"DMCONTROL.hasel can be 0 or RW."); "DMCONTROL.hasel can be 0 or RW.");
/* TODO: test that hamask registers exist if hasel does. */ /* TODO: test that hamask registers exist if hasel does. */
/* haltreq */ /* haltreq */
riscv_halt_all_harts(target); COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target));
/* This bit is not actually readable according to the spec, so nothing to check.*/ /* This bit is not actually readable according to the spec, so nothing to check.*/
/* DMSTATUS */ /* DMSTATUS */
uint32_t dmstatus, dmstatus_read; COMPLIANCE_CHECK_RO(target, DMI_DMSTATUS);
dmi_read(target, &dmstatus, DMI_DMSTATUS);
dmi_write(target, DMI_DMSTATUS, ~dmstatus);
dmi_read(target, &dmstatus_read, DMI_DMSTATUS);
COMPLIANCE_TEST(dmstatus_read == dmstatus, "DMSTATUS is R/O");
/* resumereq */ /* resumereq */
/* This bit is not actually readable according to the spec, so nothing to check.*/ /* This bit is not actually readable according to the spec, so nothing to check.*/
riscv_resume_all_harts(target); COMPLIANCE_MUST_PASS(riscv_resume_all_harts(target));
/* Halt all harts again so the test can continue.*/ /* Halt all harts again so the test can continue.*/
riscv_halt_all_harts(target); COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target));
/* HARTINFO: Read-Only. This is per-hart, so need to adjust hartsel. */ /* HARTINFO: Read-Only. This is per-hart, so need to adjust hartsel. */
uint32_t hartinfo;
COMPLIANCE_READ(target, &hartinfo, DMI_HARTINFO);
for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) { for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) {
riscv_set_current_hartid(target, hartsel); COMPLIANCE_MUST_PASS(riscv_set_current_hartid(target, hartsel));
uint32_t hartinfo, hartinfo_read; COMPLIANCE_CHECK_RO(target, DMI_HARTINFO);
dmi_read(target, &hartinfo, DMI_HARTINFO);
dmi_write(target, DMI_HARTINFO, ~hartinfo);
dmi_read(target, &hartinfo_read, DMI_HARTINFO);
COMPLIANCE_TEST((hartinfo_read == hartinfo), "DMHARTINFO should be Read-Only.");
/* $dscratch CSRs */ /* $dscratch CSRs */
uint32_t nscratch = get_field(hartinfo, DMI_HARTINFO_NSCRATCH); uint32_t nscratch = get_field(hartinfo, DMI_HARTINFO_NSCRATCH);
@ -3195,16 +3187,16 @@ int riscv013_test_compliance(struct target *target)
for (int i = 0; i < MIN(riscv_count_harts(target), 32); i++) for (int i = 0; i < MIN(riscv_count_harts(target), 32); i++)
expected_haltsum0 |= (1 << i); expected_haltsum0 |= (1 << i);
dmi_read(target, &testvar_read, DMI_HALTSUM0); COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM0);
COMPLIANCE_TEST(testvar_read == expected_haltsum0, COMPLIANCE_TEST(testvar_read == expected_haltsum0,
"HALTSUM0 should report summary of up to 32 halted harts"); "HALTSUM0 should report summary of up to 32 halted harts");
dmi_write(target, DMI_HALTSUM0, 0xffffffff); COMPLIANCE_WRITE(target, DMI_HALTSUM0, 0xffffffff);
dmi_read(target, &testvar_read, DMI_HALTSUM0); COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM0);
COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O"); COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O");
dmi_write(target, DMI_HALTSUM0, 0x0); COMPLIANCE_WRITE(target, DMI_HALTSUM0, 0x0);
dmi_read(target, &testvar_read, DMI_HALTSUM0); COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM0);
COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O"); COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O");
/* HALTSUM1 */ /* HALTSUM1 */
@ -3212,16 +3204,16 @@ int riscv013_test_compliance(struct target *target)
for (int i = 0; i < MIN(riscv_count_harts(target), 1024); i += 32) for (int i = 0; i < MIN(riscv_count_harts(target), 1024); i += 32)
expected_haltsum1 |= (1 << (i/32)); expected_haltsum1 |= (1 << (i/32));
dmi_read(target, &testvar_read, DMI_HALTSUM1); COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM1);
COMPLIANCE_TEST(testvar_read == expected_haltsum1, COMPLIANCE_TEST(testvar_read == expected_haltsum1,
"HALTSUM1 should report summary of up to 1024 halted harts"); "HALTSUM1 should report summary of up to 1024 halted harts");
dmi_write(target, DMI_HALTSUM1, 0xffffffff); COMPLIANCE_WRITE(target, DMI_HALTSUM1, 0xffffffff);
dmi_read(target, &testvar_read, DMI_HALTSUM1); COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM1);
COMPLIANCE_TEST(testvar_read == expected_haltsum1, "HALTSUM1 should be R/O"); COMPLIANCE_TEST(testvar_read == expected_haltsum1, "HALTSUM1 should be R/O");
dmi_write(target, DMI_HALTSUM1, 0x0); COMPLIANCE_WRITE(target, DMI_HALTSUM1, 0x0);
dmi_read(target, &testvar_read, DMI_HALTSUM1); COMPLIANCE_READ(target, &testvar_read, DMI_HALTSUM1);
COMPLIANCE_TEST(testvar_read == expected_haltsum1, "HALTSUM1 should be R/O"); COMPLIANCE_TEST(testvar_read == expected_haltsum1, "HALTSUM1 should be R/O");
/* TODO: HAWINDOWSEL */ /* TODO: HAWINDOWSEL */
@ -3231,7 +3223,7 @@ int riscv013_test_compliance(struct target *target)
/* ABSTRACTCS */ /* ABSTRACTCS */
uint32_t abstractcs; uint32_t abstractcs;
dmi_read(target, &abstractcs, DMI_ABSTRACTCS); COMPLIANCE_READ(target, &abstractcs, DMI_ABSTRACTCS);
/* Check that all reported Data Words are really R/W */ /* Check that all reported Data Words are really R/W */
for (int invert = 0; invert < 2; invert++) { for (int invert = 0; invert < 2; invert++) {
@ -3239,13 +3231,13 @@ int riscv013_test_compliance(struct target *target)
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
if (invert) if (invert)
testvar = ~testvar; testvar = ~testvar;
dmi_write(target, DMI_DATA0 + i, testvar); COMPLIANCE_WRITE(target, DMI_DATA0 + i, testvar);
} }
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) {
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
if (invert) if (invert)
testvar = ~testvar; testvar = ~testvar;
dmi_read(target, &testvar_read, DMI_DATA0 + i); COMPLIANCE_READ(target, &testvar_read, DMI_DATA0 + i);
COMPLIANCE_TEST(testvar_read == testvar, "All reported DATA words must be R/W"); COMPLIANCE_TEST(testvar_read == testvar, "All reported DATA words must be R/W");
} }
} }
@ -3256,13 +3248,13 @@ int riscv013_test_compliance(struct target *target)
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
if (invert) if (invert)
testvar = ~testvar; testvar = ~testvar;
dmi_write(target, DMI_PROGBUF0 + i, testvar); COMPLIANCE_WRITE(target, DMI_PROGBUF0 + i, testvar);
} }
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
if (invert) if (invert)
testvar = ~testvar; testvar = ~testvar;
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); COMPLIANCE_READ(target, &testvar_read, DMI_PROGBUF0 + i);
COMPLIANCE_TEST(testvar_read == testvar, "All reported PROGBUF words must be R/W"); COMPLIANCE_TEST(testvar_read == testvar, "All reported PROGBUF words must be R/W");
} }
} }
@ -3272,18 +3264,17 @@ int riscv013_test_compliance(struct target *target)
/* COMMAND /* COMMAND
According to the spec, this register is only W, so can't really check the read result. According to the spec, this register is only W, so can't really check the read result.
But at any rate, this is not legal and should cause an error. */ But at any rate, this is not legal and should cause an error. */
dmi_write(target, DMI_COMMAND, 0xAAAAAAAA); COMPLIANCE_WRITE(target, DMI_COMMAND, 0xAAAAAAAA);
dmi_read(target, &testvar_read, DMI_COMMAND); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS);
dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \
"Illegal COMMAND should result in UNSUPPORTED"); "Illegal COMMAND should result in UNSUPPORTED");
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
dmi_write(target, DMI_COMMAND, 0x55555555);
dmi_read(target, &testvar_read, DMI_COMMAND); COMPLIANCE_WRITE(target, DMI_COMMAND, 0x55555555);
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \
"Illegal COMMAND should result in UNSUPPORTED"); "Illegal COMMAND should result in UNSUPPORTED");
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
/* Basic Abstract Commands */ /* Basic Abstract Commands */
for (unsigned int i = 1; i < 32; i = i << 1) { for (unsigned int i = 1; i < 32; i = i << 1) {
@ -3291,7 +3282,7 @@ int riscv013_test_compliance(struct target *target)
riscv_reg_t testval_read; riscv_reg_t testval_read;
COMPLIANCE_TEST(ERROR_OK == register_write_direct(target, GDB_REGNO_ZERO + i, testval), COMPLIANCE_TEST(ERROR_OK == register_write_direct(target, GDB_REGNO_ZERO + i, testval),
"GPR Writes should be supported."); "GPR Writes should be supported.");
write_abstract_arg(target, 0, 0xDEADBEEFDEADBEEF, 64); COMPLIANCE_MUST_PASS(write_abstract_arg(target, 0, 0xDEADBEEFDEADBEEF, 64));
COMPLIANCE_TEST(ERROR_OK == register_read_direct(target, &testval_read, GDB_REGNO_ZERO + i), COMPLIANCE_TEST(ERROR_OK == register_read_direct(target, &testval_read, GDB_REGNO_ZERO + i),
"GPR Reads should be supported."); "GPR Reads should be supported.");
if (riscv_xlen(target) > 32) { if (riscv_xlen(target) > 32) {
@ -3305,11 +3296,11 @@ int riscv013_test_compliance(struct target *target)
/* ABSTRACTAUTO /* ABSTRACTAUTO
See which bits are actually writable */ See which bits are actually writable */
dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF);
uint32_t abstractauto; uint32_t abstractauto;
uint32_t busy; uint32_t busy;
dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); COMPLIANCE_READ(target, &abstractauto, DMI_ABSTRACTAUTO);
dmi_write(target, DMI_ABSTRACTAUTO, 0x0); COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0x0);
if (abstractauto > 0) { if (abstractauto > 0) {
/* This mechanism only works when you have a reasonable sized progbuf, which is not /* This mechanism only works when you have a reasonable sized progbuf, which is not
a true compliance requirement. */ a true compliance requirement. */
@ -3319,22 +3310,22 @@ int riscv013_test_compliance(struct target *target)
COMPLIANCE_TEST(ERROR_OK == register_write_direct(target, GDB_REGNO_S0, 0), COMPLIANCE_TEST(ERROR_OK == register_write_direct(target, GDB_REGNO_S0, 0),
"Need to be able to write S0 to test ABSTRACTAUTO"); "Need to be able to write S0 to test ABSTRACTAUTO");
struct riscv_program program; struct riscv_program program;
riscv_program_init(&program, target); COMPLIANCE_MUST_PASS(riscv_program_init(&program, target));
/* This is also testing that WFI() is a NOP during debug mode. */ /* This is also testing that WFI() is a NOP during debug mode. */
riscv_program_insert(&program, wfi()); COMPLIANCE_MUST_PASS(riscv_program_insert(&program, wfi()));
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, 1); COMPLIANCE_MUST_PASS(riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, 1));
riscv_program_ebreak(&program); COMPLIANCE_MUST_PASS(riscv_program_ebreak(&program));
dmi_write(target, DMI_ABSTRACTAUTO, 0x0); COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0x0);
riscv_program_exec(&program, target); COMPLIANCE_MUST_PASS(riscv_program_exec(&program, target));
testvar++; testvar++;
dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF);
dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); COMPLIANCE_READ(target, &abstractauto, DMI_ABSTRACTAUTO);
uint32_t autoexec_data = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECDATA); uint32_t autoexec_data = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECDATA);
uint32_t autoexec_progbuf = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); uint32_t autoexec_progbuf = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
for (unsigned int i = 0; i < 12; i++) { for (unsigned int i = 0; i < 12; i++) {
dmi_read(target, &testvar_read, DMI_DATA0 + i); COMPLIANCE_READ(target, &testvar_read, DMI_DATA0 + i);
do { do {
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS);
busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY);
} while (busy); } while (busy);
if (autoexec_data & (1 << i)) { if (autoexec_data & (1 << i)) {
@ -3344,9 +3335,9 @@ int riscv013_test_compliance(struct target *target)
} }
} }
for (unsigned int i = 0; i < 16; i++) { for (unsigned int i = 0; i < 16; i++) {
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); COMPLIANCE_READ(target, &testvar_read, DMI_PROGBUF0 + i);
do { do {
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS);
busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY);
} while (busy); } while (busy);
if (autoexec_progbuf & (1 << i)) { if (autoexec_progbuf & (1 << i)) {
@ -3356,7 +3347,7 @@ int riscv013_test_compliance(struct target *target)
} }
} }
dmi_write(target, DMI_ABSTRACTAUTO, 0); COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0);
COMPLIANCE_TEST(ERROR_OK == register_read_direct(target, &value, GDB_REGNO_S0), COMPLIANCE_TEST(ERROR_OK == register_read_direct(target, &value, GDB_REGNO_S0),
"Need to be able to read S0 to test ABSTRACTAUTO"); "Need to be able to read S0 to test ABSTRACTAUTO");
@ -3367,9 +3358,9 @@ int riscv013_test_compliance(struct target *target)
/* Single-Step each hart. */ /* Single-Step each hart. */
for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) { for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) {
riscv_set_current_hartid(target, hartsel); COMPLIANCE_MUST_PASS(riscv_set_current_hartid(target, hartsel));
riscv013_on_step(target); COMPLIANCE_MUST_PASS(riscv013_on_step(target));
riscv013_step_current_hart(target); COMPLIANCE_MUST_PASS(riscv013_step_current_hart(target));
COMPLIANCE_TEST(riscv_halt_reason(target, hartsel) == RISCV_HALT_SINGLESTEP, COMPLIANCE_TEST(riscv_halt_reason(target, hartsel) == RISCV_HALT_SINGLESTEP,
"Single Step should result in SINGLESTEP"); "Single Step should result in SINGLESTEP");
} }
@ -3377,14 +3368,14 @@ int riscv013_test_compliance(struct target *target)
/* Core Register Tests */ /* Core Register Tests */
uint64_t bogus_dpc = 0xdeadbeef; uint64_t bogus_dpc = 0xdeadbeef;
for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) { for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) {
riscv_set_current_hartid(target, hartsel); COMPLIANCE_MUST_PASS(riscv_set_current_hartid(target, hartsel));
/* DCSR Tests */ /* DCSR Tests */
register_write_direct(target, GDB_REGNO_DCSR, 0x0); COMPLIANCE_MUST_PASS(register_write_direct(target, GDB_REGNO_DCSR, 0x0));
register_read_direct(target, &value, GDB_REGNO_DCSR); COMPLIANCE_MUST_PASS(register_read_direct(target, &value, GDB_REGNO_DCSR));
COMPLIANCE_TEST(value != 0, "Not all bits in DCSR are writable by Debugger"); COMPLIANCE_TEST(value != 0, "Not all bits in DCSR are writable by Debugger");
register_write_direct(target, GDB_REGNO_DCSR, 0xFFFFFFFF); COMPLIANCE_MUST_PASS(register_write_direct(target, GDB_REGNO_DCSR, 0xFFFFFFFF));
register_read_direct(target, &value, GDB_REGNO_DCSR); COMPLIANCE_MUST_PASS(register_read_direct(target, &value, GDB_REGNO_DCSR));
COMPLIANCE_TEST(value != 0, "At least some bits in DCSR must be 1"); COMPLIANCE_TEST(value != 0, "At least some bits in DCSR must be 1");
/* DPC. Note that DPC is sign-extended. */ /* DPC. Note that DPC is sign-extended. */
@ -3397,12 +3388,12 @@ int riscv013_test_compliance(struct target *target)
if (riscv_supports_extension(target, riscv_current_hartid(target), 'C')) if (riscv_supports_extension(target, riscv_current_hartid(target), 'C'))
dpcmask |= 0x2; dpcmask |= 0x2;
register_write_direct(target, GDB_REGNO_DPC, dpcmask); COMPLIANCE_MUST_PASS(register_write_direct(target, GDB_REGNO_DPC, dpcmask));
register_read_direct(target, &dpc, GDB_REGNO_DPC); COMPLIANCE_MUST_PASS(register_read_direct(target, &dpc, GDB_REGNO_DPC));
COMPLIANCE_TEST(dpcmask == dpc, COMPLIANCE_TEST(dpcmask == dpc,
"DPC must be sign-extended to XLEN and writable to all-1s (except the least significant bits)"); "DPC must be sign-extended to XLEN and writable to all-1s (except the least significant bits)");
register_write_direct(target, GDB_REGNO_DPC, 0); COMPLIANCE_MUST_PASS(register_write_direct(target, GDB_REGNO_DPC, 0));
register_read_direct(target, &dpc, GDB_REGNO_DPC); COMPLIANCE_MUST_PASS(register_read_direct(target, &dpc, GDB_REGNO_DPC));
COMPLIANCE_TEST(dpc == 0, "DPC must be writable to 0."); COMPLIANCE_TEST(dpc == 0, "DPC must be writable to 0.");
if (hartsel == 0) if (hartsel == 0)
bogus_dpc = dpc; /* For a later test step */ bogus_dpc = dpc; /* For a later test step */
@ -3415,49 +3406,47 @@ int riscv013_test_compliance(struct target *target)
*/ */
/* Write some registers. They should not be impacted by ndmreset. */ /* Write some registers. They should not be impacted by ndmreset. */
dmi_write(target, DMI_COMMAND, 0xFFFFFFFF); COMPLIANCE_WRITE(target, DMI_COMMAND, 0xFFFFFFFF);
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
dmi_write(target, DMI_PROGBUF0 + i, testvar); COMPLIANCE_WRITE(target, DMI_PROGBUF0 + i, testvar);
} }
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) {
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
dmi_write(target, DMI_DATA0 + i, testvar); COMPLIANCE_WRITE(target, DMI_DATA0 + i, testvar);
} }
dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF);
dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); COMPLIANCE_READ(target, &abstractauto, DMI_ABSTRACTAUTO);
/* Pulse reset. */ /* Pulse reset. */
target->reset_halt = true; target->reset_halt = true;
riscv_set_current_hartid(target, 0); COMPLIANCE_MUST_PASS(riscv_set_current_hartid(target, 0));
COMPLIANCE_TEST(ERROR_OK == assert_reset(target), "Must be able to assert NDMRESET"); COMPLIANCE_TEST(ERROR_OK == assert_reset(target), "Must be able to assert NDMRESET");
COMPLIANCE_TEST(ERROR_OK == deassert_reset(target), "Must be able to deassert NDMRESET"); COMPLIANCE_TEST(ERROR_OK == deassert_reset(target), "Must be able to deassert NDMRESET");
/* Verify that most stuff is not affected by ndmreset. */ /* Verify that most stuff is not affected by ndmreset. */
dmi_read(target, &testvar_read, DMI_COMMAND); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS);
COMPLIANCE_TEST(testvar_read == 0xFFFFFFFF, "NDMRESET should not affect DMI_COMMAND");
dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED,
"NDMRESET should not affect DMI_ABSTRACTCS"); "NDMRESET should not affect DMI_ABSTRACTCS");
dmi_read(target, &testvar_read, DMI_ABSTRACTAUTO); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTAUTO);
COMPLIANCE_TEST(testvar_read == abstractauto, "NDMRESET should not affect DMI_ABSTRACTAUTO"); COMPLIANCE_TEST(testvar_read == abstractauto, "NDMRESET should not affect DMI_ABSTRACTAUTO");
/* Clean up to avoid future test failures */ /* Clean up to avoid future test failures */
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); COMPLIANCE_WRITE(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
dmi_write(target, DMI_ABSTRACTAUTO, 0); COMPLIANCE_WRITE(target, DMI_ABSTRACTAUTO, 0);
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); COMPLIANCE_READ(target, &testvar_read, DMI_PROGBUF0 + i);
COMPLIANCE_TEST(testvar_read == testvar, "PROGBUF words must not be affected by NDMRESET"); COMPLIANCE_TEST(testvar_read == testvar, "PROGBUF words must not be affected by NDMRESET");
} }
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) {
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_DATA0 + i); COMPLIANCE_READ(target, &testvar_read, DMI_DATA0 + i);
COMPLIANCE_TEST(testvar_read == testvar, "DATA words must not be affected by NDMRESET"); COMPLIANCE_TEST(testvar_read == testvar, "DATA words must not be affected by NDMRESET");
} }
@ -3465,7 +3454,7 @@ int riscv013_test_compliance(struct target *target)
just verify that at least it's not the bogus value anymore. */ just verify that at least it's not the bogus value anymore. */
COMPLIANCE_TEST(bogus_dpc != 0xdeadbeef, "BOGUS DPC should have been set somehow (bug in compliance test)"); COMPLIANCE_TEST(bogus_dpc != 0xdeadbeef, "BOGUS DPC should have been set somehow (bug in compliance test)");
register_read_direct(target, &value, GDB_REGNO_DPC); COMPLIANCE_MUST_PASS(register_read_direct(target, &value, GDB_REGNO_DPC));
COMPLIANCE_TEST(bogus_dpc != value, "NDMRESET should move DPC to reset value."); COMPLIANCE_TEST(bogus_dpc != value, "NDMRESET should move DPC to reset value.");
COMPLIANCE_TEST(riscv_halt_reason(target, 0) == RISCV_HALT_INTERRUPT, COMPLIANCE_TEST(riscv_halt_reason(target, 0) == RISCV_HALT_INTERRUPT,
@ -3474,24 +3463,20 @@ int riscv013_test_compliance(struct target *target)
/* DMACTIVE -- deasserting DMACTIVE should reset all the above values. */ /* DMACTIVE -- deasserting DMACTIVE should reset all the above values. */
/* Toggle dmactive */ /* Toggle dmactive */
dmi_write(target, DMI_DMCONTROL, 0); COMPLIANCE_WRITE(target, DMI_DMCONTROL, 0);
dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); COMPLIANCE_WRITE(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
dmi_read(target, &testvar_read, DMI_COMMAND); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTCS);
COMPLIANCE_TEST(testvar_read == 0, "DMI_COMMAND should reset to 0");
dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "ABSTRACTCS.cmderr should reset to 0"); COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "ABSTRACTCS.cmderr should reset to 0");
dmi_read(target, &testvar_read, DMI_ABSTRACTAUTO); COMPLIANCE_READ(target, &testvar_read, DMI_ABSTRACTAUTO);
COMPLIANCE_TEST(testvar_read == 0, "ABSTRACTAUTO should reset to 0"); COMPLIANCE_TEST(testvar_read == 0, "ABSTRACTAUTO should reset to 0");
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
testvar = (i + 1) * 0x11111111; COMPLIANCE_READ(target, &testvar_read, DMI_PROGBUF0 + i);
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i);
COMPLIANCE_TEST(testvar_read == 0, "PROGBUF words should reset to 0"); COMPLIANCE_TEST(testvar_read == 0, "PROGBUF words should reset to 0");
} }
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) { for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) {
testvar = (i + 1) * 0x11111111; COMPLIANCE_READ(target, &testvar_read, DMI_DATA0 + i);
dmi_read(target, &testvar_read, DMI_DATA0 + i);
COMPLIANCE_TEST(testvar_read == 0, "DATA words should reset to 0"); COMPLIANCE_TEST(testvar_read == 0, "DATA words should reset to 0");
} }
@ -3505,7 +3490,7 @@ int riscv013_test_compliance(struct target *target)
*/ */
/* Halt every hart for any follow-up tests*/ /* Halt every hart for any follow-up tests*/
riscv_halt_all_harts(target); COMPLIANCE_MUST_PASS(riscv_halt_all_harts(target));
LOG_INFO("PASSED %d of %d TESTS\n", passed_tests, total_tests); LOG_INFO("PASSED %d of %d TESTS\n", passed_tests, total_tests);