Merge pull request #797 from riscv/Zve32
If XLEN=64 and vsew=64 fails, fall back to vsew=32.
This commit is contained in:
commit
2b4826cd32
|
@ -116,12 +116,6 @@ struct trigger {
|
||||||
int unique_id;
|
int unique_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
YNM_MAYBE,
|
|
||||||
YNM_YES,
|
|
||||||
YNM_NO
|
|
||||||
} yes_no_maybe_t;
|
|
||||||
|
|
||||||
#define HART_INDEX_MULTIPLE -1
|
#define HART_INDEX_MULTIPLE -1
|
||||||
#define HART_INDEX_UNKNOWN -2
|
#define HART_INDEX_UNKNOWN -2
|
||||||
|
|
||||||
|
@ -1738,8 +1732,8 @@ static int examine(struct target *target)
|
||||||
LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work.");
|
LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work.");
|
||||||
r->vlenb = 0;
|
r->vlenb = 0;
|
||||||
} else {
|
} else {
|
||||||
LOG_TARGET_INFO(target, "Vector support with vlenb=%d", r->vlenb);
|
|
||||||
r->vlenb = vlenb;
|
r->vlenb = vlenb;
|
||||||
|
LOG_TARGET_INFO(target, "Vector support with vlenb=%d", r->vlenb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now init registers based on what we discovered. */
|
/* Now init registers based on what we discovered. */
|
||||||
|
@ -1911,34 +1905,54 @@ COMMAND_HELPER(riscv013_print_info, struct target *target)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prep_for_vector_access(struct target *target, uint64_t *vtype,
|
static int prep_for_vector_access(struct target *target, uint64_t *saved_vtype,
|
||||||
uint64_t *vl, unsigned *debug_vl)
|
uint64_t *saved_vl, unsigned *debug_vl, unsigned *debug_vsew)
|
||||||
{
|
{
|
||||||
RISCV_INFO(r);
|
RISCV_INFO(r);
|
||||||
/* TODO: this continuous save/restore is terrible for performance. */
|
/* TODO: this continuous save/restore is terrible for performance. */
|
||||||
/* Write vtype and vl. */
|
/* Write vtype and vl. */
|
||||||
unsigned encoded_vsew;
|
|
||||||
switch (riscv_xlen(target)) {
|
|
||||||
case 32:
|
|
||||||
encoded_vsew = 2;
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
encoded_vsew = 3;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERROR("Unsupported xlen: %d", riscv_xlen(target));
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save vtype and vl. */
|
/* Save vtype and vl. */
|
||||||
if (register_read_direct(target, vtype, GDB_REGNO_VTYPE) != ERROR_OK)
|
if (register_read_direct(target, saved_vtype, GDB_REGNO_VTYPE) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
if (register_read_direct(target, vl, GDB_REGNO_VL) != ERROR_OK)
|
if (register_read_direct(target, saved_vl, GDB_REGNO_VL) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK)
|
while (true) {
|
||||||
return ERROR_FAIL;
|
unsigned int encoded_vsew;
|
||||||
*debug_vl = DIV_ROUND_UP(r->vlenb * 8, riscv_xlen(target));
|
if (riscv_xlen(target) == 64 && r->vsew64_supported != YNM_NO) {
|
||||||
|
encoded_vsew = 3;
|
||||||
|
*debug_vsew = 64;
|
||||||
|
} else {
|
||||||
|
encoded_vsew = 2;
|
||||||
|
*debug_vsew = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set standard element width to match XLEN, for vmv instruction to move
|
||||||
|
* the least significant bits into a GPR. */
|
||||||
|
if (register_write_direct(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
if (*debug_vsew == 64 && r->vsew64_supported == YNM_MAYBE) {
|
||||||
|
/* Check that it's supported. */
|
||||||
|
uint64_t vtype;
|
||||||
|
if (register_read_direct(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK)
|
||||||
|
return ERROR_FAIL;
|
||||||
|
if (vtype >> (riscv_xlen(target) - 1)) {
|
||||||
|
r->vsew64_supported = YNM_NO;
|
||||||
|
/* Try again. */
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
r->vsew64_supported = YNM_YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the number of elements to be updated with results from a vector
|
||||||
|
* instruction, for the vslide1down instruction.
|
||||||
|
* Set it so the entire V register is updated. */
|
||||||
|
*debug_vl = DIV_ROUND_UP(r->vlenb * 8, *debug_vsew);
|
||||||
if (register_write_direct(target, GDB_REGNO_VL, *debug_vl) != ERROR_OK)
|
if (register_write_direct(target, GDB_REGNO_VL, *debug_vl) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
|
@ -1972,20 +1986,21 @@ static int riscv013_get_register_buf(struct target *target,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
uint64_t vtype, vl;
|
uint64_t vtype, vl;
|
||||||
unsigned debug_vl;
|
unsigned int debug_vl, debug_vsew;
|
||||||
if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK)
|
if (prep_for_vector_access(target, &vtype, &vl, &debug_vl, &debug_vsew) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
unsigned vnum = regno - GDB_REGNO_V0;
|
unsigned vnum = regno - GDB_REGNO_V0;
|
||||||
unsigned xlen = riscv_xlen(target);
|
|
||||||
|
|
||||||
struct riscv_program program;
|
|
||||||
riscv_program_init(&program, target);
|
|
||||||
riscv_program_insert(&program, vmv_x_s(S0, vnum));
|
|
||||||
riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true));
|
|
||||||
|
|
||||||
int result = ERROR_OK;
|
int result = ERROR_OK;
|
||||||
for (unsigned i = 0; i < debug_vl; i++) {
|
for (unsigned i = 0; i < debug_vl; i++) {
|
||||||
|
/* Can't reuse the same program because riscv_program_exec() adds
|
||||||
|
* ebreak to the end every time. */
|
||||||
|
struct riscv_program program;
|
||||||
|
riscv_program_init(&program, target);
|
||||||
|
riscv_program_insert(&program, vmv_x_s(S0, vnum));
|
||||||
|
riscv_program_insert(&program, vslide1down_vx(vnum, vnum, S0, true));
|
||||||
|
|
||||||
/* Executing the program might result in an exception if there is some
|
/* Executing the program might result in an exception if there is some
|
||||||
* issue with the vector implementation/instructions we're using. If that
|
* issue with the vector implementation/instructions we're using. If that
|
||||||
* happens, attempt to restore as usual. We may have clobbered the
|
* happens, attempt to restore as usual. We may have clobbered the
|
||||||
|
@ -1997,8 +2012,10 @@ static int riscv013_get_register_buf(struct target *target,
|
||||||
uint64_t v;
|
uint64_t v;
|
||||||
if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK)
|
if (register_read_direct(target, &v, GDB_REGNO_S0) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
buf_set_u64(value, xlen * i, xlen, v);
|
buf_set_u64(value, debug_vsew * i, debug_vsew, v);
|
||||||
} else {
|
} else {
|
||||||
|
LOG_TARGET_ERROR(target, "Failed to execute vmv/vslide1down while reading %s",
|
||||||
|
gdb_regno_name(regno));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2028,12 +2045,11 @@ static int riscv013_set_register_buf(struct target *target,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
uint64_t vtype, vl;
|
uint64_t vtype, vl;
|
||||||
unsigned debug_vl;
|
unsigned int debug_vl, debug_vsew;
|
||||||
if (prep_for_vector_access(target, &vtype, &vl, &debug_vl) != ERROR_OK)
|
if (prep_for_vector_access(target, &vtype, &vl, &debug_vl, &debug_vsew) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
||||||
unsigned vnum = regno - GDB_REGNO_V0;
|
unsigned vnum = regno - GDB_REGNO_V0;
|
||||||
unsigned xlen = riscv_xlen(target);
|
|
||||||
|
|
||||||
struct riscv_program program;
|
struct riscv_program program;
|
||||||
riscv_program_init(&program, target);
|
riscv_program_init(&program, target);
|
||||||
|
@ -2041,7 +2057,7 @@ static int riscv013_set_register_buf(struct target *target,
|
||||||
int result = ERROR_OK;
|
int result = ERROR_OK;
|
||||||
for (unsigned i = 0; i < debug_vl; i++) {
|
for (unsigned i = 0; i < debug_vl; i++) {
|
||||||
if (register_write_direct(target, GDB_REGNO_S0,
|
if (register_write_direct(target, GDB_REGNO_S0,
|
||||||
buf_get_u64(value, xlen * i, xlen)) != ERROR_OK)
|
buf_get_u64(value, debug_vsew * i, debug_vsew)) != ERROR_OK)
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
result = riscv_program_exec(&program, target);
|
result = riscv_program_exec(&program, target);
|
||||||
if (result != ERROR_OK)
|
if (result != ERROR_OK)
|
||||||
|
|
|
@ -3926,6 +3926,8 @@ void riscv_info_init(struct target *target, riscv_info_t *r)
|
||||||
|
|
||||||
INIT_LIST_HEAD(&r->expose_csr);
|
INIT_LIST_HEAD(&r->expose_csr);
|
||||||
INIT_LIST_HEAD(&r->expose_custom);
|
INIT_LIST_HEAD(&r->expose_custom);
|
||||||
|
|
||||||
|
r->vsew64_supported = YNM_MAYBE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_resume_go_all_harts(struct target *target)
|
static int riscv_resume_go_all_harts(struct target *target)
|
||||||
|
|
|
@ -41,6 +41,12 @@ typedef uint64_t riscv_reg_t;
|
||||||
typedef uint32_t riscv_insn_t;
|
typedef uint32_t riscv_insn_t;
|
||||||
typedef uint64_t riscv_addr_t;
|
typedef uint64_t riscv_addr_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
YNM_MAYBE,
|
||||||
|
YNM_YES,
|
||||||
|
YNM_NO
|
||||||
|
} yes_no_maybe_t;
|
||||||
|
|
||||||
enum riscv_mem_access_method {
|
enum riscv_mem_access_method {
|
||||||
RISCV_MEM_ACCESS_UNSPECIFIED,
|
RISCV_MEM_ACCESS_UNSPECIFIED,
|
||||||
RISCV_MEM_ACCESS_PROGBUF,
|
RISCV_MEM_ACCESS_PROGBUF,
|
||||||
|
@ -253,6 +259,8 @@ typedef struct {
|
||||||
|
|
||||||
/* Track when we were last asked to do something substantial. */
|
/* Track when we were last asked to do something substantial. */
|
||||||
int64_t last_activity;
|
int64_t last_activity;
|
||||||
|
|
||||||
|
yes_no_maybe_t vsew64_supported;
|
||||||
} riscv_info_t;
|
} riscv_info_t;
|
||||||
|
|
||||||
COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key,
|
COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key,
|
||||||
|
|
Loading…
Reference in New Issue