bsvtgc
(Ben)
August 2, 2020, 11:46am
1
In the due process of choosing a board to try writing some firmware on RISC-V core, browsed the HiFIve1 Rev B board. But could n’t find MISA CSR in FE310 manual. I know its an optional register to implement. But on a starter board, it would have been easy to read the supported extensions etc. Am I the one expecting this register? or is it least important?
jimw
(Jim Wilson)
August 3, 2020, 4:41am
2
I don’t have a HiFive1 Rev B, but this
https://github.com/sifive/freedom-e-sdk/blob/master/bsp/sifive-hifive1-revb/design.reglist
suggests that misa is implemented. That list of registers comes from the core generator, so should be correct.
SiFive has invested in a doc group, and the new docs are much better than the old ones. The old FE310-G002 manual doesn’t have a section listing all implemented CSRs. But the new docs have a programmer’s model chapter that has a section that lists all defined CSRs. Unfortunately, I don’t know if there will be a new version of the FE310-G002 docs, and you can’t rely on the new E31 core docs because that will list new features not present in the older core used in the FE310-G002 ASIC.
1 Like
The HiFive1 Rev B does have the misa register. I read mine just yesterday with a program written in Rust.
rust forum post
tgm
(Tommy Murphy)
August 4, 2020, 11:35pm
4
How important is MISA register?
Well if you use the riscv-openocd (GitHub - riscv/riscv-openocd: Fork of OpenOCD that has RISC-V support ) probably very important as the current implementation seems to make extensive use of it as far as I can see:
list_for_each_entry_safe(entry, tmp, &info->expose_csr, list) {
free(entry->name);
free(entry);
}
list_for_each_entry_safe(entry, tmp, &info->expose_custom, list) {
free(entry->name);
free(entry);
}
free_reg_names(target);
free(target->arch_info);
target->arch_info = NULL;
}
static void trigger_from_breakpoint(struct trigger *trigger,
const struct breakpoint *breakpoint)
{
trigger->address = breakpoint->address;
for (unsigned int i = *idx; i < r->trigger_count; i++) {
if (r->trigger_unique_id[i] == -1) {
if (r->trigger_tinfo[i] & (1 << type)) {
num_found++;
if (num_required == num_found) {
/* Found num_required consecutive free triggers - success, done. */
*idx = i - (num_required - 1);
LOG_TARGET_DEBUG(target,
"%d trigger(s) of type %d found on index %u, "
"chained == %s",
num_required, type, *idx,
chained ? "true" : "false");
return ERROR_OK;
}
/* Found a trigger but need more consecutive ones */
continue;
}
}
/* Trigger already occupied or incompatible type.
* Reset the counter of found consecutive triggers */
case TARGET_UNAVAILABLE:
previous_riscv_state = RISCV_STATE_UNAVAILABLE;
break;
}
/* If OpenOCD thinks we're running but this hart is halted then it's time
* to raise an event. */
enum riscv_hart_state state;
if (riscv_get_hart_state(target, &state) != ERROR_OK)
return ERROR_FAIL;
if (state == RISCV_STATE_NON_EXISTENT) {
LOG_TARGET_ERROR(target, "Hart is non-existent!");
return ERROR_FAIL;
}
if (state == RISCV_STATE_HALTED && timeval_ms() - r->last_activity > 100) {
/* If we've been idle for a while, flush the register cache. Just in case
* OpenOCD is going to be disconnected without shutting down cleanly. */
if (riscv_flush_registers(target) != ERROR_OK)
return ERROR_FAIL;
{
LOG_TARGET_DEBUG(target, "Set dcsr.ebreak*");
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
RISCV_INFO(r);
RISCV013_INFO(info);
riscv_reg_t original_dcsr, dcsr;
/* We want to twiddle some bits in the debug CSR so debugging works. */
if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;
original_dcsr = dcsr;
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, r->riscv_ebreakm);
dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, r->riscv_ebreaks && riscv_supports_extension(target, 'S'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
if (dcsr != original_dcsr &&
riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
if (dcsr != original_dcsr &&
riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
return ERROR_FAIL;
info->dcsr_ebreak_is_set = true;
return ERROR_OK;
}
static int halt_set_dcsr_ebreak(struct target *target)
{
RISCV_INFO(r);
RISCV013_INFO(info);
LOG_TARGET_DEBUG(target, "Halt to set DCSR.ebreak*");
/* Remove this hart from the halt group. This won't work on all targets
* because the debug spec allows halt groups to be hard-coded, but I
* haven't actually encountered those in the wild yet.
*
* There is a possible race condition when another hart halts, and
*
* The perfect solution would be Quick Access, but I'm not aware of any
* hardware that implements it.
*
* We don't need a perfect solution, because we only get here when a
* hart spontaneously resets, or when it powers down and back up again.
* Those are both relatively rare. (At least I hope so. Maybe some
* design just powers each hart down for 90ms out of every 100ms)
*/
if (info->haltgroup_supported) {
bool supported;
if (set_group(target, &supported, 0, HALT_GROUP) != ERROR_OK)
return ERROR_FAIL;
if (!supported)
LOG_TARGET_ERROR(target, "Couldn't place hart in halt group 0. "
"Some harts may be unexpectedly halted.");
}
int result = ERROR_OK;
dump_debug_ram(target);
return ERROR_FAIL;
}
LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target));
if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) {
const unsigned old_csr_misa = 0xf10;
LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA,
old_csr_misa);
if (read_remote_csr(target, &r->misa, old_csr_misa) != ERROR_OK) {
/* Maybe this is an old core that still has $misa at the old
* address. */
LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa);
return ERROR_FAIL;
}
}
/* Update register list to match discovered XLEN/supported extensions. */
riscv_init_registers(target);
info->never_halted = true;
target_set_examined(target);
for (size_t i = 0; i < 32; ++i)
reg_cache_set(target, i, -1);
LOG_INFO("Examined RISCV core; XLEN=%d, misa=0x%" PRIx64,
riscv_xlen(target), r->misa);
return ERROR_OK;
}
static riscv_error_t handle_halt_routine(struct target *target)
{
riscv011_info_t *info = get_info(target);
scans_t *scans = scans_new(target, 256);
if (!scans)
return RE_FAIL;
/* Read all GPRs as fast as we can, because gdb is going to ask for them
* anyway. Reading them one at a time is much slower. */
1 Like