Initial commit of tests for SBA feature
parent
52eabbd2a5
commit
c5a8e1cf4c
|
@ -57,6 +57,9 @@ static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a,
|
|||
static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a);
|
||||
static int riscv013_dmi_write_u64_bits(struct target *target);
|
||||
static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf);
|
||||
static int riscv013_test_sba_config_reg(struct target *target, uint32_t address);
|
||||
uint32_t read_memory_sba_simple(struct target *target, uint32_t addr, uint32_t sbcs);
|
||||
void write_memory_sba_simple(struct target *target, uint32_t addr, uint32_t data, uint32_t sbcs);
|
||||
static int register_read_direct(struct target *target, uint64_t *value, uint32_t number);
|
||||
static int register_write_direct(struct target *target, unsigned number,
|
||||
uint64_t value);
|
||||
|
@ -1488,6 +1491,7 @@ static int init_target(struct command_context *cmd_ctx,
|
|||
generic_info->fill_dmi_read_u64 = &riscv013_fill_dmi_read_u64;
|
||||
generic_info->fill_dmi_nop_u64 = &riscv013_fill_dmi_nop_u64;
|
||||
generic_info->dmi_write_u64_bits = &riscv013_dmi_write_u64_bits;
|
||||
generic_info->test_sba_config_reg = &riscv013_test_sba_config_reg;
|
||||
generic_info->authdata_read = &riscv013_authdata_read;
|
||||
generic_info->authdata_write = &riscv013_authdata_write;
|
||||
generic_info->dmi_read = &dmi_read;
|
||||
|
@ -2811,6 +2815,162 @@ void riscv013_fill_dmi_nop_u64(struct target *target, char *buf)
|
|||
buf_set_u64((unsigned char *)buf, DTM_DMI_ADDRESS_OFFSET, info->abits, 0);
|
||||
}
|
||||
|
||||
static int riscv013_test_sba_config_reg(struct target *target, uint32_t address)
|
||||
{
|
||||
LOG_INFO("Testing System Bus Access as defined by RISC-V Debug Spec v0.13");
|
||||
|
||||
if(!riscv_rtos_enabled(target)) {
|
||||
LOG_ERROR("Please run with -rtos riscv to run SBA test.");
|
||||
}
|
||||
|
||||
uint32_t rd_val;
|
||||
uint32_t sbcs_orig;
|
||||
dmi_read(target, &sbcs_orig, DMI_SBCS);
|
||||
|
||||
uint32_t sbcs = sbcs_orig;
|
||||
|
||||
// Test 1: Simple write/read test, no address autoincrement
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBAUTOINCREMENT,0);
|
||||
dmi_write(target,DMI_SBCS,sbcs);
|
||||
|
||||
for(int sbaccess = 0; sbaccess < 0x5; sbaccess++) {
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBACCESS,sbaccess);
|
||||
dmi_write(target,DMI_SBCS,sbcs);
|
||||
|
||||
for(int i = 0; i < 100; i++){
|
||||
uint32_t addr = 0x80000000 + (i << sbaccess);
|
||||
write_memory_sba_simple(target,addr,i,sbcs_orig);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 100; i++){
|
||||
uint32_t addr = 0x80000000 + (i << sbaccess);
|
||||
uint32_t val = read_memory_sba_simple(target,addr,sbcs_orig);
|
||||
if(i != val) {
|
||||
LOG_ERROR("System Bus Access Test: Error reading non-autoincremented address %x, expected val = %d, read val = %d",addr,i,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_INFO("System Bus Access Test: Read/write test, no addr autoincrement PASSED");
|
||||
|
||||
// Test 2: Simple write/read test, with address autoincrement
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBAUTOINCREMENT,1);
|
||||
dmi_write(target,DMI_SBCS,sbcs);
|
||||
|
||||
for(int sbaccess = 0; sbaccess < 0x5; sbaccess++){
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBACCESS,sbaccess);
|
||||
dmi_write(target,DMI_SBCS,sbcs);
|
||||
|
||||
dmi_write(target,DMI_SBADDRESS0,0x80000000);
|
||||
for(int i = 0; i < 100; i++){
|
||||
read_sbcs_nonbusy(target,&sbcs);
|
||||
dmi_write(target,DMI_SBDATA0,i);
|
||||
}
|
||||
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBREADONDATA,1);
|
||||
|
||||
dmi_write(target,DMI_SBADDRESS0,0x80000000);
|
||||
for(uint32_t i = 0; i < 100; i++){
|
||||
read_sbcs_nonbusy(target,&sbcs);
|
||||
uint32_t val;
|
||||
dmi_read(target,&val,DMI_SBDATA0);
|
||||
if(i != val) {
|
||||
LOG_ERROR("System Bus Access Test: Error reading autoincremented address, expected val = %d, read val = %d",i,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_INFO("System Bus Access Test: Read/write test, with addr autoincrement PASSED");
|
||||
|
||||
// Test 3: Read from illegal address
|
||||
read_memory_sba_simple(target,address,sbcs_orig);
|
||||
|
||||
dmi_read(target,&rd_val,DMI_SBCS);
|
||||
if(get_field(rd_val,DMI_SBCS_SBERROR) == 0x2) {
|
||||
LOG_INFO("System Bus Access Test: Illegal address read test PASSED");
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBERROR,1);
|
||||
dmi_write(target,DMI_SBCS,sbcs);
|
||||
} else {
|
||||
LOG_ERROR("System Bus Access Test: Illegal address read test FAILED");
|
||||
}
|
||||
|
||||
// Test 4: Write to illegal address
|
||||
write_memory_sba_simple(target,address,0xdeadbeef,sbcs_orig);
|
||||
|
||||
dmi_read(target,&rd_val,DMI_SBCS);
|
||||
if(get_field(rd_val,DMI_SBCS_SBERROR) == 0x2) {
|
||||
LOG_INFO("System Bus Access Test: Illegal address write test PASSED");
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBERROR,1);
|
||||
dmi_write(target,DMI_SBCS,sbcs);
|
||||
} else {
|
||||
LOG_ERROR("System Bus Access Test: Illegal address write test FAILED");
|
||||
}
|
||||
|
||||
// Test 5: Write to unsupported sbaccess size
|
||||
uint32_t sbaccess128 = get_field(sbcs_orig,DMI_SBCS_SBACCESS128);
|
||||
|
||||
if(sbaccess128) {
|
||||
LOG_INFO("System Bus Access Test: SBCS Alignment error test PASSED, all alignments supported");
|
||||
} else {
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBACCESS,0x4);
|
||||
dmi_write(target, DMI_SBCS, sbcs);
|
||||
|
||||
write_memory_sba_simple(target, 0x80000000, 0xdeadbeef, sbcs_orig);
|
||||
|
||||
dmi_read(target,&rd_val,DMI_SBCS);
|
||||
|
||||
if(get_field(rd_val,DMI_SBCS_SBERROR) == 0x3) {
|
||||
LOG_INFO("System Bus Access Test: SBCS Alignment error test PASSED");
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBERROR,0x1);
|
||||
dmi_write(target,DMI_SBCS,sbcs);
|
||||
} else {
|
||||
LOG_ERROR("System Bus Access Test: SBCS Alignment error test FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
// Test 5: Set sbbusyerror
|
||||
dmi_write(target,DMI_SBADDRESS0,0x80000000);
|
||||
dmi_write(target,DMI_SBADDRESS0,0x80000000);
|
||||
|
||||
dmi_read(target,&rd_val,DMI_SBCS);
|
||||
if(get_field(rd_val,DMI_SBCS_SBBUSYERROR)) {
|
||||
LOG_INFO("System Bus Access Test: SBCS sbbusy test PASSED");
|
||||
sbcs = set_field(sbcs_orig,DMI_SBCS_SBBUSYERROR,0x1);
|
||||
dmi_write(target,DMI_SBCS,sbcs);
|
||||
} else {
|
||||
LOG_ERROR("System Bus Access Test: SBCS sbbusy test FAILED");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void write_memory_sba_simple(struct target *target, uint32_t addr, uint32_t data, uint32_t sbcs)
|
||||
{
|
||||
uint32_t rd_sbcs;
|
||||
read_sbcs_nonbusy(target,&rd_sbcs);
|
||||
|
||||
uint32_t sbcs_no_readonaddr = set_field(sbcs,DMI_SBCS_SBREADONADDR,0);
|
||||
dmi_write(target,DMI_SBCS,sbcs_no_readonaddr);
|
||||
dmi_write(target,DMI_SBADDRESS0,addr);
|
||||
dmi_write(target,DMI_SBDATA0,data);
|
||||
}
|
||||
|
||||
uint32_t read_memory_sba_simple(struct target *target, uint32_t addr, uint32_t sbcs)
|
||||
{
|
||||
uint32_t rd_val;
|
||||
uint32_t rd_sbcs;
|
||||
read_sbcs_nonbusy(target,&rd_sbcs);
|
||||
|
||||
uint32_t sbcs_readonaddr = set_field(sbcs,DMI_SBCS_SBREADONADDR,1);
|
||||
dmi_write(target,DMI_SBCS,sbcs_readonaddr);
|
||||
dmi_write(target,DMI_SBADDRESS0,addr);
|
||||
|
||||
read_sbcs_nonbusy(target,&rd_sbcs);
|
||||
|
||||
dmi_read(target,&rd_val,DMI_SBDATA0);
|
||||
|
||||
return rd_val;
|
||||
}
|
||||
|
||||
int riscv013_dmi_write_u64_bits(struct target *target)
|
||||
{
|
||||
RISCV013_INFO(info);
|
||||
|
|
|
@ -1428,6 +1428,27 @@ COMMAND_HANDLER(riscv_dmi_write)
|
|||
}
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(riscv_test_sba_config_reg)
|
||||
{
|
||||
if (CMD_ARGC != 1) {
|
||||
LOG_ERROR("Command takes exactly 1 argument");
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
RISCV_INFO(r);
|
||||
|
||||
uint32_t address;
|
||||
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address);
|
||||
|
||||
if (r->test_sba_config_reg) {
|
||||
return r->test_sba_config_reg(target,address);
|
||||
} else {
|
||||
LOG_ERROR("test_sba_config_reg is not implemented for this target.");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct command_registration riscv_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "set_command_timeout_sec",
|
||||
|
@ -1495,6 +1516,13 @@ static const struct command_registration riscv_exec_command_handlers[] = {
|
|||
.usage = "riscv dmi_write address value",
|
||||
.help = "Perform a 32-bit DMI write of value at address."
|
||||
},
|
||||
{
|
||||
.name = "test_sba_config_reg",
|
||||
.handler = riscv_test_sba_config_reg,
|
||||
.mode = COMMAND_ANY,
|
||||
.usage = "riscv test_sba_config_reg address",
|
||||
.help = "Perform a series of tests on the SBCS register. Pass in a non-readable/writable address"
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
|
|
|
@ -116,6 +116,9 @@ typedef struct {
|
|||
|
||||
int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address);
|
||||
int (*dmi_write)(struct target *target, uint32_t address, uint32_t value);
|
||||
|
||||
int (*test_sba_config_reg)(struct target *target, uint32_t address);
|
||||
|
||||
} riscv_info_t;
|
||||
|
||||
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
|
||||
|
|
Loading…
Reference in New Issue