src/target/riscv: R/W vector register workaround when vslide1down_vx not present

In Nuclei RISC-V Processor, Vector Module can be configured to lite version
which vslide1down_vx instruction maybe not present, so we need to find other
ways to read and write vector registers, this commit is a workaround to do this.

Change-Id: I6e01666ec49d2876942b09b7e5d14c3fcc76854f
Signed-off-by: wangyanwen <wangyanwen@nucleisys.com>
This commit is contained in:
wangyanwen 2024-05-15 09:43:58 +08:00 committed by Huaqi Fang
parent 3ac078f0f5
commit 4665a40ac9
2 changed files with 86 additions and 6 deletions

View File

@ -342,4 +342,28 @@ static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2,
return ((vm & 1) << 25) | inst_rs2(vs2) | inst_rs1(rs1) | inst_rd(vd) | MATCH_VSLIDE1DOWN_VX;
}
static uint32_t vle32_v(unsigned int rs1, unsigned int vd) __attribute__((unused));
static uint32_t vle32_v(unsigned int rs1, unsigned int vd)
{
return inst_rs1(rs1) | inst_rd(vd) | 0x02006007;
}
static uint32_t vse32_v(unsigned int rs1, unsigned int vd) __attribute__((unused));
static uint32_t vse32_v(unsigned int rs1, unsigned int vd)
{
return inst_rs1(rs1) | inst_rd(vd) | 0x02006027;
}
static uint32_t vle64_v(unsigned int rs1, unsigned int vs3) __attribute__((unused));
static uint32_t vle64_v(unsigned int rs1, unsigned int vs3)
{
return inst_rs1(rs1) | inst_rd(vs3) | 0x02007007;
}
static uint32_t vse64_v(unsigned int rs1, unsigned int vs3) __attribute__((unused));
static uint32_t vse64_v(unsigned int rs1, unsigned int vs3)
{
return inst_rs1(rs1) | inst_rd(vs3) | 0x02007027;
}
#endif /* OPENOCD_TARGET_RISCV_OPCODES_H */

View File

@ -2287,6 +2287,7 @@ int riscv013_get_register_buf(struct target *target, uint8_t *value,
unsigned int vnum = regno - GDB_REGNO_V0;
int result = ERROR_OK;
bool vslide1down_fail = false;
for (unsigned int i = 0; i < debug_vl; i++) {
/* Can't reuse the same program because riscv_program_exec() adds
* ebreak to the end every time. */
@ -2304,17 +2305,43 @@ int riscv013_get_register_buf(struct target *target, uint8_t *value,
result = riscv_program_exec(&program, target);
if (result == ERROR_OK) {
riscv_reg_t v;
if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK) {
vslide1down_fail = true;
break;
}
buf_set_u64(value, debug_vsew * i, debug_vsew, v);
} else {
LOG_TARGET_ERROR(target,
"Failed to execute vmv/vslide1down while reading %s",
riscv_reg_gdb_regno_name(target, regno));
vslide1down_fail = true;
break;
}
}
if (vslide1down_fail) {
LOG_TARGET_WARNING(target,
"Failed to execute vmv/vslide1down while reading %s",
riscv_reg_gdb_regno_name(target, regno));
struct working_area *algorithm_v = NULL;
result = target_alloc_working_area(target, riscv_vlenb(target), &algorithm_v);
if (result != ERROR_OK)
LOG_TARGET_ERROR(target, "Failed to alloc workarea while read");
register_write_direct(target, GDB_REGNO_S0, algorithm_v->address);
struct riscv_program program;
riscv_program_init(&program, target);
if (debug_vsew == 32)
riscv_program_insert(&program, vse32_v(S0, vnum));
else
riscv_program_insert(&program, vse64_v(S0, vnum));
result = riscv_program_exec(&program, target);
if (result != ERROR_OK)
LOG_TARGET_ERROR(target, "Failed to execute vse while read");
read_memory(target, algorithm_v->address, 1, riscv_vlenb(target), value, 1);
target_free_working_area(target, algorithm_v);
}
if (cleanup_after_vector_access(target, mstatus, vtype, vl) != ERROR_OK)
return ERROR_FAIL;
@ -2345,13 +2372,42 @@ int riscv013_set_register_buf(struct target *target, enum gdb_regno regno,
riscv_program_init(&program, target);
riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true));
int result = ERROR_OK;
bool vslide1down_fail = false;
for (unsigned int i = 0; i < debug_vl; i++) {
if (register_write_direct(target, GDB_REGNO_S0,
buf_get_u64(value, debug_vsew * i, debug_vsew)) != ERROR_OK)
return ERROR_FAIL;
result = riscv_program_exec(&program, target);
if (result != ERROR_OK)
if (result != ERROR_OK) {
vslide1down_fail = true;
break;
}
}
if (vslide1down_fail) {
LOG_TARGET_WARNING(target,
"Failed to execute vmv/vslide1down while reading %s",
riscv_reg_gdb_regno_name(target, regno));
struct working_area *algorithm_v = NULL;
result = target_alloc_working_area(target, riscv_vlenb(target), &algorithm_v);
if (result != ERROR_OK)
LOG_TARGET_ERROR(target, "Failed to alloc workarea while write");
register_write_direct(target, GDB_REGNO_S0, algorithm_v->address);
write_memory(target, algorithm_v->address, 1, riscv_vlenb(target), value);
struct riscv_program program;
riscv_program_init(&program, target);
if (debug_vsew == 32)
riscv_program_insert(&program, vle32_v(S0, vnum));
else
riscv_program_insert(&program, vle64_v(S0, vnum));
result = riscv_program_exec(&program, target);
if (result != ERROR_OK)
LOG_TARGET_ERROR(target, "Failed to execute vle while write");
target_free_working_area(target, algorithm_v);
}
if (cleanup_after_vector_access(target, mstatus, vtype, vl) != ERROR_OK)