riscv-compliance: Fix OpenOCD lint checks

This commit is contained in:
Megan Wachs 2018-04-17 07:49:06 -07:00
parent bc32aaafa4
commit fa99b8e3b1
1 changed files with 507 additions and 479 deletions

View File

@ -1501,7 +1501,7 @@ static int init_target(struct command_context *cmd_ctx,
generic_info->dmi_read = &dmi_read; generic_info->dmi_read = &dmi_read;
generic_info->dmi_write = &dmi_write; generic_info->dmi_write = &dmi_write;
generic_info->test_compliance = &riscv013_test_compliance; generic_info->test_compliance = &riscv013_test_compliance;
generic_info->version_specific = calloc(1, sizeof(riscv013_info_t)); generic_info->version_specific = calloc(1, sizeof(riscv013_info_t));
if (!generic_info->version_specific) if (!generic_info->version_specific)
return ERROR_FAIL; return ERROR_FAIL;
riscv013_info_t *info = get_info(target); riscv013_info_t *info = get_info(target);
@ -2934,482 +2934,510 @@ void riscv013_clear_abstract_error(struct target *target)
dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR); dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR);
} }
#define COMPLIANCE_TEST(b, message) { \ #define COMPLIANCE_TEST(b, message) \
int pass = 0; \ { \
if (b) { \ int pass = 0; \
pass = 1; \ if (b) { \
passed_tests ++; \ pass = 1; \
} \ passed_tests++; \
LOG_INFO("%s test %d (%s)\n", (pass) ? "PASSED":"FAILED", total_tests, message); \ } \
assert(pass); \ LOG_INFO("%s test %d (%s)\n", (pass) ? "PASSED" : "FAILED", total_tests, message); \
total_tests ++; \ assert(pass); \
} total_tests++; \
}
int riscv013_test_compliance(struct target *target) {
LOG_INFO("Testing Compliance against RISC-V Debug Spec v0.13"); int riscv013_test_compliance(struct target *target)
{
if (!riscv_rtos_enabled(target)) { LOG_INFO("Testing Compliance against RISC-V Debug Spec v0.13");
LOG_ERROR("Please run with -rtos riscv to run compliance test.");
return ERROR_FAIL; if (!riscv_rtos_enabled(target)) {
} LOG_ERROR("Please run with -rtos riscv to run compliance test.");
return ERROR_FAIL;
int total_tests = 0; }
int passed_tests = 0;
int total_tests = 0;
uint32_t dmcontrol_orig; int passed_tests = 0;
dmi_read(target, &dmcontrol_orig, DMI_DMCONTROL);
uint32_t dmcontrol; uint32_t dmcontrol_orig;
uint32_t testvar; dmi_read(target, &dmcontrol_orig, DMI_DMCONTROL);
uint32_t testvar_read; uint32_t dmcontrol;
riscv_reg_t value; uint32_t testvar;
uint32_t testvar_read;
dmcontrol = set_field(dmcontrol_orig, hartsel_mask(target), RISCV_MAX_HARTS-1); riscv_reg_t value;
dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_read(target, &dmcontrol, DMI_DMCONTROL); dmcontrol = set_field(dmcontrol_orig, hartsel_mask(target), RISCV_MAX_HARTS-1);
COMPLIANCE_TEST(get_field(dmcontrol, hartsel_mask(target)) == (RISCV_MAX_HARTS-1), "DMCONTROL.hartsel should hold all the harts allowed by HARTSELLEN."); dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
dmcontrol = set_field(dmcontrol_orig, hartsel_mask(target), 0); COMPLIANCE_TEST(get_field(dmcontrol, hartsel_mask(target)) == (RISCV_MAX_HARTS-1),
dmi_write(target, DMI_DMCONTROL, dmcontrol); "DMCONTROL.hartsel should hold all the harts allowed by HARTSELLEN.");
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
COMPLIANCE_TEST(get_field(dmcontrol, hartsel_mask(target)) == 0, "DMCONTROL.hartsel should hold Hart ID 0"); dmcontrol = set_field(dmcontrol_orig, hartsel_mask(target), 0);
dmi_write(target, DMI_DMCONTROL, dmcontrol);
// hartreset dmi_read(target, &dmcontrol, DMI_DMCONTROL);
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1); COMPLIANCE_TEST(get_field(dmcontrol, hartsel_mask(target)) == 0, "DMCONTROL.hartsel should hold Hart ID 0");
dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_read(target, &dmcontrol, DMI_DMCONTROL); /* hartreset */
testvar = get_field(dmcontrol, DMI_DMCONTROL_HARTRESET); dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1);
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1); dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_write(target, DMI_DMCONTROL, dmcontrol); dmi_read(target, &dmcontrol, DMI_DMCONTROL);
dmi_read(target, &dmcontrol, DMI_DMCONTROL); testvar = get_field(dmcontrol, DMI_DMCONTROL_HARTRESET);
COMPLIANCE_TEST(((testvar == 0) || (get_field(dmcontrol, DMI_DMCONTROL_HARTRESET)) == 0), "DMCONTROL.hartreset can be 0 or RW."); dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HARTRESET, 1);
dmi_write(target, DMI_DMCONTROL, dmcontrol);
// hasel dmi_read(target, &dmcontrol, DMI_DMCONTROL);
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1); COMPLIANCE_TEST(((testvar == 0) || (get_field(dmcontrol, DMI_DMCONTROL_HARTRESET)) == 0),
dmi_write(target, DMI_DMCONTROL, dmcontrol); "DMCONTROL.hartreset can be 0 or RW.");
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
testvar = get_field(dmcontrol, DMI_DMCONTROL_HASEL); /* hasel */
dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1); dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1);
dmi_write(target, DMI_DMCONTROL, dmcontrol); dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_read(target, &dmcontrol, DMI_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."); testvar = get_field(dmcontrol, DMI_DMCONTROL_HASEL);
//TODO: test that hamask registers exist if hasel does. dmcontrol = set_field(dmcontrol_orig, DMI_DMCONTROL_HASEL, 1);
dmi_write(target, DMI_DMCONTROL, dmcontrol);
// haltreq dmi_read(target, &dmcontrol, DMI_DMCONTROL);
riscv_halt_all_harts(target); COMPLIANCE_TEST(((testvar == 0) || (get_field(dmcontrol, DMI_DMCONTROL_HASEL)) == 0),
// Writing haltreq should not cause any problems for a halted hart, but we "DMCONTROL.hasel can be 0 or RW.");
// should be able to read and write it. /* TODO: test that hamask registers exist if hasel does. */
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
dmcontrol |= DMI_DMCONTROL_HALTREQ; /* haltreq */
dmi_write(target, DMI_DMCONTROL, dmcontrol); riscv_halt_all_harts(target);
dmi_read(target, &dmcontrol, DMI_DMCONTROL); /* Writing haltreq should not cause any problems for a halted hart, but we
COMPLIANCE_TEST(dmcontrol & DMI_DMCONTROL_HALTREQ, "DMCONTROL.haltreq should be R/W"); should be able to read and write it. */
uint32_t dmstatus, dmstatus_read; dmi_read(target, &dmcontrol, DMI_DMCONTROL);
do { dmcontrol |= DMI_DMCONTROL_HALTREQ;
dmi_read(target, &dmstatus, DMI_DMSTATUS); dmi_write(target, DMI_DMCONTROL, dmcontrol);
} while ((dmstatus & DMI_DMSTATUS_ALLHALTED) == 0); dmi_read(target, &dmcontrol, DMI_DMCONTROL);
COMPLIANCE_TEST(dmcontrol & DMI_DMCONTROL_HALTREQ, "DMCONTROL.haltreq should be R/W");
dmi_write(target, DMI_DMSTATUS, 0xffffffff); uint32_t dmstatus, dmstatus_read;
dmi_read(target, &dmstatus_read, DMI_DMSTATUS); do {
COMPLIANCE_TEST(dmstatus_read == dmstatus, "DMSTATUS is R/O"); dmi_read(target, &dmstatus, DMI_DMSTATUS);
} while ((dmstatus & DMI_DMSTATUS_ALLHALTED) == 0);
// resumereq. This will resume the hart but this test is destructive anyway.
dmcontrol &= ~DMI_DMCONTROL_HALTREQ; dmi_write(target, DMI_DMSTATUS, 0xffffffff);
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 1); dmi_read(target, &dmstatus_read, DMI_DMSTATUS);
dmi_write(target, DMI_DMCONTROL, dmcontrol); COMPLIANCE_TEST(dmstatus_read == dmstatus, "DMSTATUS is R/O");
dmi_read(target, &dmcontrol, DMI_DMCONTROL);
COMPLIANCE_TEST(get_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ) == 1, "DMCONTROL.resumereq should be R/W"); /* resumereq. This will resume the hart but this test is destructive anyway. */
dmcontrol &= ~DMI_DMCONTROL_HALTREQ;
do { dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 1);
dmi_read(target, &dmstatus, DMI_DMSTATUS); dmi_write(target, DMI_DMCONTROL, dmcontrol);
} while (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0); dmi_read(target, &dmcontrol, DMI_DMCONTROL);
COMPLIANCE_TEST(get_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ) == 1,
// Halt the hart again because the target isn't aware that we resumed it. "DMCONTROL.resumereq should be R/W");
dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 0);
dmcontrol |= DMI_DMCONTROL_HALTREQ; do {
dmi_write(target, DMI_DMCONTROL, dmcontrol); dmi_read(target, &dmstatus, DMI_DMSTATUS);
do { } while (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0);
dmi_read(target, &dmstatus, DMI_DMSTATUS);
} while ((dmstatus & DMI_DMSTATUS_ALLHALTED) == 0); /* Halt the hart again because the target isn't aware that we resumed it. */
dmcontrol &= ~DMI_DMCONTROL_HALTREQ; dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 0);
dmi_write(target, DMI_DMCONTROL, dmcontrol); dmcontrol |= DMI_DMCONTROL_HALTREQ;
// Not clear that this read is required according to the spec. dmi_write(target, DMI_DMCONTROL, dmcontrol);
dmi_read(target, &dmstatus, DMI_DMSTATUS); do {
dmi_read(target, &dmstatus, DMI_DMSTATUS);
// HARTINFO: Read-Only. This is per-hart, so need to adjust hartsel. } while ((dmstatus & DMI_DMSTATUS_ALLHALTED) == 0);
for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++){ dmcontrol &= ~DMI_DMCONTROL_HALTREQ;
riscv_set_current_hartid(target, hartsel); dmi_write(target, DMI_DMCONTROL, dmcontrol);
/* Not clear that this read is required according to the spec. */
uint32_t hartinfo, hartinfo_read; dmi_read(target, &dmstatus, DMI_DMSTATUS);
dmi_read(target, &hartinfo, DMI_HARTINFO);
dmi_write(target, DMI_HARTINFO, ~hartinfo); /* HARTINFO: Read-Only. This is per-hart, so need to adjust hartsel. */
dmi_read(target, &hartinfo_read, DMI_HARTINFO); for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) {
COMPLIANCE_TEST((hartinfo_read == hartinfo), "DMHARTINFO should be Read-Only."); riscv_set_current_hartid(target, hartsel);
uint32_t nscratch = get_field(hartinfo, DMI_HARTINFO_NSCRATCH); uint32_t hartinfo, hartinfo_read;
for (unsigned int d = 0; d < nscratch; d++) { dmi_read(target, &hartinfo, DMI_HARTINFO);
dmi_write(target, DMI_HARTINFO, ~hartinfo);
//TODO: DSCRATCH CSRs should be 64-bit on 64-bit systems. dmi_read(target, &hartinfo_read, DMI_HARTINFO);
riscv_reg_t testval; COMPLIANCE_TEST((hartinfo_read == hartinfo), "DMHARTINFO should be Read-Only.");
for (testval = 0x0011223300112233; testval != 0xDEAD ; testval = testval == 0x0011223300112233 ? ~testval : 0xDEAD ) {
COMPLIANCE_TEST(register_write_direct(target, GDB_REGNO_S0, testval) == ERROR_OK, "Need to be able to write S0 in order to test DSCRATCH."); uint32_t nscratch = get_field(hartinfo, DMI_HARTINFO_NSCRATCH);
struct riscv_program program32; for (unsigned int d = 0; d < nscratch; d++) {
riscv_program_init(&program32, target); /* TODO: DSCRATCH CSRs should be 64-bit on 64-bit systems. */
riscv_program_csrw(&program32, GDB_REGNO_S0, GDB_REGNO_DSCRATCH + d); riscv_reg_t testval;
riscv_program_csrr(&program32, GDB_REGNO_S1, GDB_REGNO_DSCRATCH + d); for (testval = 0x0011223300112233;
riscv_program_fence(&program32); testval != 0xDEAD;
riscv_program_ebreak(&program32); testval = testval == 0x0011223300112233 ? ~testval : 0xDEAD) {
COMPLIANCE_TEST(riscv_program_exec(&program32, target) == ERROR_OK, "Accessing DSCRATCH with program buffer should succeed."); COMPLIANCE_TEST(register_write_direct(target, GDB_REGNO_S0, testval) == ERROR_OK,
COMPLIANCE_TEST(register_read_direct(target, &value, GDB_REGNO_S1) == ERROR_OK, "Need to be able to read S1 in order to test DSCRATCH."); "Need to be able to write S0 in order to test DSCRATCH.");
if (riscv_xlen(target) > 32) { struct riscv_program program32;
COMPLIANCE_TEST(value == testval, "All DSCRATCH registers in HARTINFO must be R/W."); riscv_program_init(&program32, target);
} else { riscv_program_csrw(&program32, GDB_REGNO_S0, GDB_REGNO_DSCRATCH + d);
COMPLIANCE_TEST(value == (testval & 0xFFFFFFFF), "All DSCRATCH registers in HARTINFO must be R/W."); riscv_program_csrr(&program32, GDB_REGNO_S1, GDB_REGNO_DSCRATCH + d);
} riscv_program_fence(&program32);
} riscv_program_ebreak(&program32);
} COMPLIANCE_TEST(riscv_program_exec(&program32, target) == ERROR_OK,
// TODO: dataaccess "Accessing DSCRATCH with program buffer should succeed.");
if (get_field(hartinfo, DMI_HARTINFO_DATAACCESS)) { COMPLIANCE_TEST(register_read_direct(target, &value, GDB_REGNO_S1) == ERROR_OK,
// TODO: Shadowed in memory map. "Need to be able to read S1 in order to test DSCRATCH.");
// TODO: datasize if (riscv_xlen(target) > 32)
// TODO: dataaddr COMPLIANCE_TEST(value == testval,
} else { "All DSCRATCH registers in HARTINFO must be R/W.");
// TODO: Shadowed in CSRs. else
// TODO: datasize COMPLIANCE_TEST(value == (testval & 0xFFFFFFFF),
// TODO: dataaddr "All DSCRATCH registers in HARTINFO must be R/W.");
} }
}
} /* TODO: dataaccess */
if (get_field(hartinfo, DMI_HARTINFO_DATAACCESS)) {
// HALTSUM -- TODO: More than 32 harts /* TODO: Shadowed in memory map. */
// TODO: HALTSUM2, HALTSUM3 /* TODO: datasize */
uint32_t expected_haltsum0 = 0; /* TODO: dataaddr */
for (int i = 0; i < riscv_count_harts(target); i +=32){ } else {
expected_haltsum0 |= (1 << (i / 32)); /* TODO: Shadowed in CSRs. */
} /* TODO: datasize */
dmi_read(target, &testvar_read, DMI_HALTSUM0); /* TODO: dataaddr */
COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should report summary of 32 halted harts"); }
dmi_write(target, DMI_HALTSUM0, 0xffffffff); }
dmi_read(target, &testvar_read, DMI_HALTSUM0);
COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O"); /* HALTSUM -- TODO: More than 32 harts */
/* TODO: HALTSUM2, HALTSUM3 */
dmi_write(target, DMI_HALTSUM0, 0x0); uint32_t expected_haltsum0 = 0;
dmi_read(target, &testvar_read, DMI_HALTSUM0); for (int i = 0; i < riscv_count_harts(target); i += 32)
COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O"); expected_haltsum0 |= (1 << (i / 32));
for (int i = 0; i < 32/*TODO: riscv_count_harts(target)*/; i +=32){ dmi_read(target, &testvar_read, DMI_HALTSUM0);
//TODO: Set hartsel for i > 32 harts. COMPLIANCE_TEST(testvar_read == expected_haltsum0,
dmi_read(target, &testvar_read, DMI_HALTSUM1); "HALTSUM0 should report summary of 32 halted harts");
uint32_t haltsum1_expected = (((i + 1) * 32) <= riscv_count_harts(target)) ? 0xFFFFFFFFU : ((1U << (riscv_count_harts(target) % 32)) - 1);
COMPLIANCE_TEST(testvar_read == haltsum1_expected, "HALTSUM1 should report summary of 1024 halted harts"); dmi_write(target, DMI_HALTSUM0, 0xffffffff);
dmi_read(target, &testvar_read, DMI_HALTSUM0);
// Just have to check this once COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O");
if (i == 0) {
dmi_write(target, DMI_HALTSUM1, 0xffffffff); dmi_write(target, DMI_HALTSUM0, 0x0);
dmi_read(target, &testvar_read, DMI_HALTSUM1); dmi_read(target, &testvar_read, DMI_HALTSUM0);
COMPLIANCE_TEST(testvar_read == haltsum1_expected, "HALTSUM1 should be R/O"); COMPLIANCE_TEST(testvar_read == expected_haltsum0, "HALTSUM0 should be R/O");
dmi_write(target, DMI_HALTSUM1, 0x0); for (int i = 0; i < 32/*TODO: riscv_count_harts(target)*/; i += 32) {
dmi_read(target, &testvar_read, DMI_HALTSUM1); /* TODO: Set hartsel for i > 32 harts. */
COMPLIANCE_TEST(testvar_read == haltsum1_expected, "HALTSUM1 should be R/O"); dmi_read(target, &testvar_read, DMI_HALTSUM1);
} uint32_t haltsum1_expected = (((i + 1) * 32) <= riscv_count_harts(target)) ?
} 0xFFFFFFFFU :
((1U << (riscv_count_harts(target) % 32)) - 1);
// TODO: HAWINDOWSEL COMPLIANCE_TEST(testvar_read == haltsum1_expected,
"HALTSUM1 should report summary of 1024 halted harts");
// TODO: HAWINDOW
/* Just have to check this once */
// ABSTRACTCS if (i == 0) {
dmi_write(target, DMI_HALTSUM1, 0xffffffff);
uint32_t abstractcs; dmi_read(target, &testvar_read, DMI_HALTSUM1);
dmi_read(target, &abstractcs, DMI_ABSTRACTCS); COMPLIANCE_TEST(testvar_read == haltsum1_expected, "HALTSUM1 should be R/O");
// Check that all reported Data Words are really R/W dmi_write(target, DMI_HALTSUM1, 0x0);
for (int invert = 0; invert < 2; invert++) { dmi_read(target, &testvar_read, DMI_HALTSUM1);
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i ++){ COMPLIANCE_TEST(testvar_read == haltsum1_expected, "HALTSUM1 should be R/O");
testvar = (i + 1) * 0x11111111; }
if (invert) {testvar = ~testvar;} }
dmi_write(target, DMI_DATA0 + i, testvar);
} /* TODO: HAWINDOWSEL */
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i ++){
testvar = (i + 1) * 0x11111111; /* TODO: HAWINDOW */
if (invert) {testvar = ~testvar;}
dmi_read(target, &testvar_read, DMI_DATA0 + i); /* ABSTRACTCS */
COMPLIANCE_TEST(testvar_read == testvar, "All reported DATA words must be R/W");
} uint32_t abstractcs;
} dmi_read(target, &abstractcs, DMI_ABSTRACTCS);
// Check that all reported ProgBuf 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++) {
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i ++){ for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) {
testvar = (i + 1) * 0x11111111; testvar = (i + 1) * 0x11111111;
if (invert) {testvar = ~testvar;} if (invert)
dmi_write(target, DMI_PROGBUF0 + i, testvar); testvar = ~testvar;
} dmi_write(target, DMI_DATA0 + i, testvar);
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i ++){ }
testvar = (i + 1) * 0x11111111; for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) {
if (invert) {testvar = ~testvar;} testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); if (invert)
COMPLIANCE_TEST(testvar_read == testvar, "All reported PROGBUF words must be R/W"); testvar = ~testvar;
} dmi_read(target, &testvar_read, DMI_DATA0 + i);
} COMPLIANCE_TEST(testvar_read == testvar, "All reported DATA words must be R/W");
}
// TODO: Cause and clear all error types }
// COMMAND /*Check that all reported ProgBuf words are really R/W */
// TODO: Unclear from the spec whether all these bits need to truly be R/W. for (int invert = 0; invert < 2; invert++) {
// But at any rate, this is not legal and should cause an error. for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
dmi_write(target, DMI_COMMAND, 0xAAAAAAAA); testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_COMMAND); if (invert)
COMPLIANCE_TEST(testvar_read == 0xAAAAAAAA, "COMMAND register should be R/W"); testvar = ~testvar;
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); dmi_write(target, DMI_PROGBUF0 + i, testvar);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ }
"Illegal COMMAND should result in UNSUPPORTED"); for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); testvar = (i + 1) * 0x11111111;
dmi_write(target, DMI_COMMAND, 0x55555555); if (invert)
dmi_read(target, &testvar_read, DMI_COMMAND); testvar = ~testvar;
COMPLIANCE_TEST(testvar_read == 0x55555555, "COMMAND register should be R/W"); dmi_read(target, &testvar_read, DMI_PROGBUF0 + i);
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); COMPLIANCE_TEST(testvar_read == testvar, "All reported PROGBUF words must be R/W");
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \ }
"Illegal COMMAND should result in UNSUPPORTED"); }
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
/* TODO: Cause and clear all error types */
// Basic Abstract Commands
uint32_t command = 0; /* COMMAND
uint32_t busy; TODO: Unclear from the spec whether all these bits need to truly be R/W.
command = set_field(command, AC_ACCESS_REGISTER_SIZE, riscv_xlen(target) > 32 ? 3:2); But at any rate, this is not legal and should cause an error. */
command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); dmi_write(target, DMI_COMMAND, 0xAAAAAAAA);
for (unsigned int i = 1 ; i < 32 ; i = i << 1) { dmi_read(target, &testvar_read, DMI_COMMAND);
command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1000 + GDB_REGNO_ZERO + i); COMPLIANCE_TEST(testvar_read == 0xAAAAAAAA, "COMMAND register should be R/W");
command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
dmi_write(target, DMI_DATA0, i); COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \
if (riscv_xlen(target) > 32) { "Illegal COMMAND should result in UNSUPPORTED");
dmi_write(target, DMI_DATA0 + 1, i + 1); dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
} dmi_write(target, DMI_COMMAND, 0x55555555);
dmi_write(target, DMI_COMMAND, command); dmi_read(target, &testvar_read, DMI_COMMAND);
do { COMPLIANCE_TEST(testvar_read == 0x55555555, "COMMAND register should be R/W");
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, \
} while (busy); "Illegal COMMAND should result in UNSUPPORTED");
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "GPR Writes should be supported.");
dmi_write(target, DMI_DATA0, 0xDEADBEEF); /* Basic Abstract Commands */
if (riscv_xlen(target) > 32) { uint32_t command = 0;
dmi_write(target, DMI_DATA0 + 1, 0xDEADBEEF); uint32_t busy;
} command = set_field(command, AC_ACCESS_REGISTER_SIZE, riscv_xlen(target) > 32 ? 3 : 2);
command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0); command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1);
dmi_write(target, DMI_COMMAND, command); for (unsigned int i = 1; i < 32; i = i << 1) {
do { command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1000 + GDB_REGNO_ZERO + i);
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1);
busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); dmi_write(target, DMI_DATA0, i);
} while (busy); if (riscv_xlen(target) > 32)
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); dmi_write(target, DMI_DATA0 + 1, i + 1);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "GPR Reads should be supported."); dmi_write(target, DMI_COMMAND, command);
dmi_read(target, &testvar_read, DMI_DATA0); do {
COMPLIANCE_TEST(testvar_read == i, "GPR Reads and writes should be supported."); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
if (riscv_xlen(target) > 32) { busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY);
dmi_read(target, &testvar_read, DMI_DATA0 + 1); } while (busy);
COMPLIANCE_TEST(testvar_read == (i + 1), "GPR Reads and writes should be supported."); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
} COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0,
} "GPR Writes should be supported.");
dmi_write(target, DMI_DATA0, 0xDEADBEEF);
// ABSTRACTAUTO if (riscv_xlen(target) > 32)
// See which bits are actually writable dmi_write(target, DMI_DATA0 + 1, 0xDEADBEEF);
dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0);
uint32_t abstractauto; dmi_write(target, DMI_COMMAND, command);
dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); do {
dmi_write(target, DMI_ABSTRACTAUTO, 0x0); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
if (abstractauto > 0) { busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY);
testvar = 0; } while (busy);
// TODO: This mechanism only works when you have a reasonable sized progbuf, which is not dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
// a true compliance requirement. COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0,
uint32_t result = riscv_set_register(target, GDB_REGNO_S0, 0); "GPR Reads should be supported.");
COMPLIANCE_TEST(result == ERROR_OK, "Need to be able to write S0 to test ABSTRACTAUTO"); dmi_read(target, &testvar_read, DMI_DATA0);
struct riscv_program program; COMPLIANCE_TEST(testvar_read == i, "GPR Reads and writes should be supported.");
riscv_program_init(&program, target); if (riscv_xlen(target) > 32) {
// Also testing that WFI() is a NOP during debug mode. dmi_read(target, &testvar_read, DMI_DATA0 + 1);
riscv_program_insert(&program, wfi()); COMPLIANCE_TEST(testvar_read == (i + 1),
riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, 1); "GPR Reads and writes should be supported.");
riscv_program_ebreak(&program); }
dmi_write(target, DMI_ABSTRACTAUTO, 0x0); }
riscv_program_exec(&program, target);
testvar ++; /* ABSTRACTAUTO
dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); See which bits are actually writable */
dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF);
uint32_t autoexec_data = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECDATA); uint32_t abstractauto;
uint32_t autoexec_progbuf = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO);
for (unsigned int i = 0; i < 12; i ++){ dmi_write(target, DMI_ABSTRACTAUTO, 0x0);
dmi_read(target, &testvar_read, DMI_DATA0 + i); if (abstractauto > 0) {
do { testvar = 0;
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); /* TODO: This mechanism only works when you have a reasonable sized progbuf, which is not
busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); a true compliance requirement. */
} while (busy); uint32_t result = riscv_set_register(target, GDB_REGNO_S0, 0);
if (autoexec_data & (1 << i)) { COMPLIANCE_TEST(result == ERROR_OK, "Need to be able to write S0 to test ABSTRACTAUTO");
COMPLIANCE_TEST(i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT), "AUTOEXEC may be writable up to DATACOUNT bits."); struct riscv_program program;
testvar ++; riscv_program_init(&program, target);
} /* Also testing that WFI() is a NOP during debug mode. */
} riscv_program_insert(&program, wfi());
for (unsigned int i = 0; i < 16; i ++){ riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, 1);
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); riscv_program_ebreak(&program);
do { dmi_write(target, DMI_ABSTRACTAUTO, 0x0);
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); riscv_program_exec(&program, target);
busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY); testvar++;
} while (busy); dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF);
if (autoexec_progbuf & (1 << i)) { dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO);
COMPLIANCE_TEST(i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE), "AUTOEXEC may be writable up to PROGBUFSIZE bits."); uint32_t autoexec_data = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECDATA);
testvar ++; uint32_t autoexec_progbuf = get_field(abstractauto, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF);
} for (unsigned int i = 0; i < 12; i++) {
} dmi_read(target, &testvar_read, DMI_DATA0 + i);
do {
dmi_write(target, DMI_ABSTRACTAUTO, 0); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
riscv_get_register(target, &value, GDB_REGNO_S0); busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY);
} while (busy);
COMPLIANCE_TEST(testvar == value, \ if (autoexec_data & (1 << i)) {
"ABSTRACTAUTO should cause COMMAND to run the expected number of times."); COMPLIANCE_TEST(i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT),
} "AUTOEXEC may be writable up to DATACOUNT bits.");
testvar++;
// Single-Step each hart. }
for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel ++){ }
riscv_set_current_hartid(target, hartsel); for (unsigned int i = 0; i < 16; i++) {
riscv013_on_step(target); dmi_read(target, &testvar_read, DMI_PROGBUF0 + i);
riscv013_step_current_hart(target); do {
COMPLIANCE_TEST(riscv_halt_reason(target, hartsel) == RISCV_HALT_SINGLESTEP, "Single Step should result in SINGLESTEP"); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
} busy = get_field(testvar_read, DMI_ABSTRACTCS_BUSY);
} while (busy);
// Core Register Tests if (autoexec_progbuf & (1 << i)) {
uint64_t bogus_dpc = 0xdeadbeef; COMPLIANCE_TEST(i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE),
for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel ++){ "AUTOEXEC may be writable up to PROGBUFSIZE bits.");
riscv_set_current_hartid(target, hartsel); testvar++;
}
// DCSR Tests }
riscv_set_register(target, GDB_REGNO_DCSR, 0x0);
riscv_get_register(target, &value, GDB_REGNO_DCSR); dmi_write(target, DMI_ABSTRACTAUTO, 0);
COMPLIANCE_TEST(value != 0, "Not all bits in DCSR are writable by Debugger"); riscv_get_register(target, &value, GDB_REGNO_S0);
riscv_set_register(target, GDB_REGNO_DCSR, 0xFFFFFFFF);
riscv_get_register(target, &value, GDB_REGNO_DCSR); COMPLIANCE_TEST(testvar == value, \
COMPLIANCE_TEST(value != 0, "At least some bits in DCSR must be 1"); "ABSTRACTAUTO should cause COMMAND to run the expected number of times.");
}
// DPC. Note that DPC is sign-extended.
riscv_reg_t dpcmask = 0xFFFFFFFCUL; /* Single-Step each hart. */
riscv_reg_t dpc; for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) {
riscv_set_current_hartid(target, hartsel);
if (riscv_xlen(target) > 32) { riscv013_on_step(target);
dpcmask |= (0xFFFFFFFFULL << 32); riscv013_step_current_hart(target);
} COMPLIANCE_TEST(riscv_halt_reason(target, hartsel) == RISCV_HALT_SINGLESTEP,
if (riscv_supports_extension(target, riscv_current_hartid(target), 'C')){ "Single Step should result in SINGLESTEP");
dpcmask |= 0x2; }
}
/* Core Register Tests */
riscv_set_register(target, GDB_REGNO_DPC, dpcmask); uint64_t bogus_dpc = 0xdeadbeef;
riscv_get_register(target, &dpc, GDB_REGNO_DPC); for (int hartsel = 0; hartsel < riscv_count_harts(target); hartsel++) {
COMPLIANCE_TEST(dpcmask == dpc, "DPC must be sign-extended to XLEN and writable to all-1s (except the least significant bits)"); riscv_set_current_hartid(target, hartsel);
riscv_set_register(target, GDB_REGNO_DPC, 0);
riscv_get_register(target, &dpc, GDB_REGNO_DPC); /* DCSR Tests */
COMPLIANCE_TEST(dpc == 0, "DPC must be writable to 0."); riscv_set_register(target, GDB_REGNO_DCSR, 0x0);
if (hartsel == 0) {bogus_dpc = dpc;} // For a later test step riscv_get_register(target, &value, GDB_REGNO_DCSR);
} COMPLIANCE_TEST(value != 0, "Not all bits in DCSR are writable by Debugger");
riscv_set_register(target, GDB_REGNO_DCSR, 0xFFFFFFFF);
//NDMRESET riscv_get_register(target, &value, GDB_REGNO_DCSR);
// NDMRESET COMPLIANCE_TEST(value != 0, "At least some bits in DCSR must be 1");
// Asserting non-debug module reset should not reset Debug Module state.
// But it should reset Hart State, e.g. DPC should get a different value. /* DPC. Note that DPC is sign-extended. */
// Also make sure that DCSR reports cause of 'HALT' even though previously we single-stepped. riscv_reg_t dpcmask = 0xFFFFFFFCUL;
riscv_reg_t dpc;
// Write some registers. They should not be impacted by ndmreset.
dmi_write(target, DMI_COMMAND, 0xFFFFFFFF); if (riscv_xlen(target) > 32)
dpcmask |= (0xFFFFFFFFULL << 32);
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i ++){
testvar = (i + 1) * 0x11111111; if (riscv_supports_extension(target, riscv_current_hartid(target), 'C'))
dmi_write(target, DMI_PROGBUF0 + i, testvar); dpcmask |= 0x2;
}
riscv_set_register(target, GDB_REGNO_DPC, dpcmask);
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i ++){ riscv_get_register(target, &dpc, GDB_REGNO_DPC);
testvar = (i + 1) * 0x11111111; COMPLIANCE_TEST(dpcmask == dpc,
dmi_write(target, DMI_DATA0 + i, testvar); "DPC must be sign-extended to XLEN and writable to all-1s (except the least significant bits)");
} riscv_set_register(target, GDB_REGNO_DPC, 0);
riscv_get_register(target, &dpc, GDB_REGNO_DPC);
dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF); COMPLIANCE_TEST(dpc == 0, "DPC must be writable to 0.");
dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO); if (hartsel == 0)
bogus_dpc = dpc; /* For a later test step */
// Pulse reset. }
target->reset_halt = true; /* NDMRESET
dmi_read(target, &dmcontrol, DMI_DMCONTROL); Asserting non-debug module reset should not reset Debug Module state.
riscv_set_current_hartid(target, 0); But it should reset Hart State, e.g. DPC should get a different value.
assert_reset(target); Also make sure that DCSR reports cause of 'HALT' even though previously we single-stepped.
deassert_reset(target); */
// Verify that most stuff is not affected by ndmreset. /* Write some registers. They should not be impacted by ndmreset. */
dmi_read(target, &testvar_read, DMI_COMMAND); dmi_write(target, DMI_COMMAND, 0xFFFFFFFF);
COMPLIANCE_TEST(testvar_read == 0xFFFFFFFF, "NDMRESET should not affect DMI_COMMAND");
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED, "NDMRESET should not affect DMI_ABSTRACTCS"); testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_ABSTRACTAUTO); dmi_write(target, DMI_PROGBUF0 + i, testvar);
COMPLIANCE_TEST(testvar_read == abstractauto, "NDMRESET should not affect DMI_ABSTRACTAUTO"); }
// Clean up to avoid future test failures for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) {
dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR); testvar = (i + 1) * 0x11111111;
dmi_write(target, DMI_ABSTRACTAUTO, 0); dmi_write(target, DMI_DATA0 + i, testvar);
}
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i ++){
testvar = (i + 1) * 0x11111111; dmi_write(target, DMI_ABSTRACTAUTO, 0xFFFFFFFF);
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); dmi_read(target, &abstractauto, DMI_ABSTRACTAUTO);
COMPLIANCE_TEST(testvar_read == testvar, "PROGBUF words must not be affected by NDMRESET");
} /* Pulse reset. */
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i ++){ target->reset_halt = true;
testvar = (i + 1) * 0x11111111; dmi_read(target, &dmcontrol, DMI_DMCONTROL);
dmi_read(target, &testvar_read, DMI_DATA0 + i); riscv_set_current_hartid(target, 0);
COMPLIANCE_TEST(testvar_read == testvar, "DATA words must not be affected by NDMRESET"); assert_reset(target);
} deassert_reset(target);
// verify that DPC *is* affected by ndmreset. Since we don't know what it *should* be, /* Verify that most stuff is not affected by ndmreset. */
// just verify that at least it's not the bogus value anymore. dmi_read(target, &testvar_read, DMI_COMMAND);
COMPLIANCE_TEST(bogus_dpc != 0xdeadbeef, "BOGUS DPC should have been set somehow (bug in compliance test)"); COMPLIANCE_TEST(testvar_read == 0xFFFFFFFF, "NDMRESET should not affect DMI_COMMAND");
riscv_get_register(target, &value, GDB_REGNO_DPC); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
COMPLIANCE_TEST(bogus_dpc != value, "NDMRESET should move DPC to reset value."); COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == CMDERR_NOT_SUPPORTED,
"NDMRESET should not affect DMI_ABSTRACTCS");
COMPLIANCE_TEST(riscv_halt_reason(target, 0) == RISCV_HALT_INTERRUPT, "After NDMRESET halt, DCSR should report cause of halt"); dmi_read(target, &testvar_read, DMI_ABSTRACTAUTO);
COMPLIANCE_TEST(testvar_read == abstractauto, "NDMRESET should not affect DMI_ABSTRACTAUTO");
// DMACTIVE -- deasserting DMACTIVE should reset all the above values.
/* Clean up to avoid future test failures */
// Toggle dmactive dmi_write(target, DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
dmi_write(target, DMI_DMCONTROL, 0); dmi_write(target, DMI_ABSTRACTAUTO, 0);
dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
dmi_read(target, &testvar_read, DMI_COMMAND); for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
COMPLIANCE_TEST(testvar_read == 0, "DMI_COMMAND should reset to 0"); testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_ABSTRACTCS); dmi_read(target, &testvar_read, DMI_PROGBUF0 + i);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "ABSTRACTCS.cmderr should reset to 0"); COMPLIANCE_TEST(testvar_read == testvar, "PROGBUF words must not be affected by NDMRESET");
dmi_read(target, &testvar_read, DMI_ABSTRACTAUTO); }
COMPLIANCE_TEST(testvar_read == 0, "ABSTRACTAUTO 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_PROGBUFSIZE); i ++){ testvar = (i + 1) * 0x11111111;
testvar = (i + 1) * 0x11111111; dmi_read(target, &testvar_read, DMI_DATA0 + i);
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i); COMPLIANCE_TEST(testvar_read == testvar, "DATA words must not be affected by NDMRESET");
COMPLIANCE_TEST(testvar_read == 0, "PROGBUF words should reset to 0"); }
}
/* Verify that DPC *is* affected by ndmreset. Since we don't know what it *should* be,
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i ++){ just verify that at least it's not the bogus value anymore. */
testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_DATA0 + i); COMPLIANCE_TEST(bogus_dpc != 0xdeadbeef, "BOGUS DPC should have been set somehow (bug in compliance test)");
COMPLIANCE_TEST(testvar_read == 0, "DATA words should reset to 0"); riscv_get_register(target, &value, GDB_REGNO_DPC);
} COMPLIANCE_TEST(bogus_dpc != value, "NDMRESET should move DPC to reset value.");
//TODO: COMPLIANCE_TEST(riscv_halt_reason(target, 0) == RISCV_HALT_INTERRUPT,
// DCSR.cause priorities "After NDMRESET halt, DCSR should report cause of halt");
// DCSR.stoptime/stopcycle
// DCSR.stepie /* DMACTIVE -- deasserting DMACTIVE should reset all the above values. */
// DCSR.ebreak
// DCSR.prv /* Toggle dmactive */
dmi_write(target, DMI_DMCONTROL, 0);
/* Halt every hart for any follow-up tests*/ dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
riscv_halt_all_harts(target); dmi_read(target, &testvar_read, DMI_COMMAND);
COMPLIANCE_TEST(testvar_read == 0, "DMI_COMMAND should reset to 0");
LOG_INFO("PASSED %d of %d TESTS\n", passed_tests, total_tests); dmi_read(target, &testvar_read, DMI_ABSTRACTCS);
COMPLIANCE_TEST(get_field(testvar_read, DMI_ABSTRACTCS_CMDERR) == 0, "ABSTRACTCS.cmderr should reset to 0");
if (total_tests == passed_tests) { dmi_read(target, &testvar_read, DMI_ABSTRACTAUTO);
return ERROR_OK; COMPLIANCE_TEST(testvar_read == 0, "ABSTRACTAUTO should reset to 0");
} else {
return ERROR_FAIL; for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); i++) {
} testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_PROGBUF0 + i);
COMPLIANCE_TEST(testvar_read == 0, "PROGBUF words should reset to 0");
}
for (unsigned int i = 0; i < get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); i++) {
testvar = (i + 1) * 0x11111111;
dmi_read(target, &testvar_read, DMI_DATA0 + i);
COMPLIANCE_TEST(testvar_read == 0, "DATA words should reset to 0");
}
/*
* TODO:
* DCSR.cause priorities
* DCSR.stoptime/stopcycle
* DCSR.stepie
* DCSR.ebreak
* DCSR.prv
*/
/* Halt every hart for any follow-up tests*/
riscv_halt_all_harts(target);
LOG_INFO("PASSED %d of %d TESTS\n", passed_tests, total_tests);
if (total_tests == passed_tests)
return ERROR_OK;
else
return ERROR_FAIL;
} }