diff --git a/src/emulate.c b/src/emulate.c index c1f42c41..e5e4cddf 100644 --- a/src/emulate.c +++ b/src/emulate.c @@ -61,6 +61,25 @@ static void rv_trap_default_handler(riscv_t *rv) static void __trap_handler(riscv_t *rv); #endif /* RV32_HAS(SYSTEM) */ +#if RV32_HAS(ARCH_TEST) +/* Check if the write is to tohost and halt emulation if so. + * Compliance tests write to tohost and then enter an infinite loop. + * The emulator should detect this and exit gracefully. + */ +static inline void check_tohost_write(riscv_t *rv, + uint32_t addr, + uint32_t value) +{ + if (rv->tohost_addr && addr == rv->tohost_addr && value != 0) { + /* Non-zero write to tohost means test wants to exit */ + rv->halt = true; + /* Extract exit code from tohost value (value >> 1) */ + vm_attr_t *attr = PRIV(rv); + attr->exit_code = (value >> 1); + } +} +#endif /* RV32_HAS(ARCH_TEST) */ + /* wrap load/store and insn misaligned handler * @mask_or_pc: mask for load/store and pc for insn misaligned handler. * @type: type of misaligned handler @@ -466,7 +485,11 @@ static bool do_fuse3(riscv_t *rv, for (int i = 0; i < ir->imm2; i++) { uint32_t addr = rv->X[fuse[i].rs1] + fuse[i].imm; RV_EXC_MISALIGN_HANDLER(3, STORE, false, 1); - rv->io.mem_write_w(rv, addr, rv->X[fuse[i].rs2]); + uint32_t value = rv->X[fuse[i].rs2]; + rv->io.mem_write_w(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif } PC += ir->imm2 * 4; if (unlikely(RVOP_NO_NEXT(ir))) { diff --git a/src/main.c b/src/main.c index 8e079a50..4c851edd 100644 --- a/src/main.c +++ b/src/main.c @@ -314,6 +314,25 @@ int main(int argc, char **args) } rv_log_info("RISC-V emulator is created and ready to run"); +#if RV32_HAS(ARCH_TEST) + /* Extract tohost/fromhost addresses for arch-test mode */ + if (opt_arch_test && opt_prog_name) { + elf_t *elf = elf_new(); + if (elf && elf_open(elf, opt_prog_name)) { + const struct Elf32_Sym *sym; + if ((sym = elf_get_symbol(elf, "tohost"))) { + rv_set_tohost_addr(rv, sym->st_value); + rv_log_info("Found tohost at 0x%08x", sym->st_value); + } + if ((sym = elf_get_symbol(elf, "fromhost"))) { + rv_set_fromhost_addr(rv, sym->st_value); + rv_log_info("Found fromhost at 0x%08x", sym->st_value); + } + } + elf_delete(elf); + } +#endif + #if defined(__EMSCRIPTEN__) disable_run_button(); #endif diff --git a/src/riscv.c b/src/riscv.c index 5ee8a955..b892cf27 100644 --- a/src/riscv.c +++ b/src/riscv.c @@ -886,6 +886,18 @@ bool rv_has_halted(riscv_t *rv) return rv->halt; } +#if RV32_HAS(ARCH_TEST) +void rv_set_tohost_addr(riscv_t *rv, uint32_t addr) +{ + rv->tohost_addr = addr; +} + +void rv_set_fromhost_addr(riscv_t *rv, uint32_t addr) +{ + rv->fromhost_addr = addr; +} +#endif + void rv_delete(riscv_t *rv) { assert(rv); diff --git a/src/riscv.h b/src/riscv.h index 8ff55f49..c8e6cb53 100644 --- a/src/riscv.h +++ b/src/riscv.h @@ -440,6 +440,12 @@ void rv_halt(riscv_t *rv); /* return the halt state */ bool rv_has_halted(riscv_t *rv); +#if RV32_HAS(ARCH_TEST) +/* Set tohost/fromhost addresses for architectural testing */ +void rv_set_tohost_addr(riscv_t *rv, uint32_t addr); +void rv_set_fromhost_addr(riscv_t *rv, uint32_t addr); +#endif + enum { /* run and trace instructions and print them out during emulation */ RV_RUN_TRACE = 1, diff --git a/src/riscv_private.h b/src/riscv_private.h index ace3ca90..12a3bfd0 100644 --- a/src/riscv_private.h +++ b/src/riscv_private.h @@ -229,6 +229,12 @@ struct riscv_internal { */ uint32_t last_csr_sepc; #endif + +#if RV32_HAS(ARCH_TEST) + /* RISC-V architectural test support: tohost/fromhost addresses */ + uint32_t tohost_addr; + uint32_t fromhost_addr; +#endif }; /* sign extend a 16 bit value */ diff --git a/src/rv32_template.c b/src/rv32_template.c index a2354daf..14ad8b7a 100644 --- a/src/rv32_template.c +++ b/src/rv32_template.c @@ -705,7 +705,11 @@ RVOP( sb, { const uint32_t addr = rv->X[ir->rs1] + ir->imm; - rv->io.mem_write_b(rv, addr, rv->X[ir->rs2]); + const uint32_t value = rv->X[ir->rs2]; + rv->io.mem_write_b(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ mem; @@ -722,7 +726,11 @@ RVOP( { const uint32_t addr = rv->X[ir->rs1] + ir->imm; RV_EXC_MISALIGN_HANDLER(1, STORE, false, 1); - rv->io.mem_write_s(rv, addr, rv->X[ir->rs2]); + const uint32_t value = rv->X[ir->rs2]; + rv->io.mem_write_s(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ mem; @@ -739,7 +747,11 @@ RVOP( { const uint32_t addr = rv->X[ir->rs1] + ir->imm; RV_EXC_MISALIGN_HANDLER(3, STORE, false, 1); - rv->io.mem_write_w(rv, addr, rv->X[ir->rs2]); + const uint32_t value = rv->X[ir->rs2]; + rv->io.mem_write_w(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ mem; @@ -1501,8 +1513,12 @@ RVOP( */ const uint32_t addr = rv->X[ir->rs1]; RV_EXC_MISALIGN_HANDLER(3, STORE, false, 1); - rv->io.mem_write_w(rv, addr, rv->X[ir->rs2]); + const uint32_t value = rv->X[ir->rs2]; + rv->io.mem_write_w(rv, addr, value); rv->X[ir->rd] = 0; +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1519,6 +1535,9 @@ RVOP( if (ir->rd) rv->X[ir->rd] = value1; rv->io.mem_write_w(rv, addr, value2); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value2); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1536,6 +1555,9 @@ RVOP( rv->X[ir->rd] = value1; const uint32_t res = value1 + value2; rv->io.mem_write_w(rv, addr, res); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, res); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1553,6 +1575,9 @@ RVOP( rv->X[ir->rd] = value1; const uint32_t res = value1 ^ value2; rv->io.mem_write_w(rv, addr, res); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, res); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1570,6 +1595,9 @@ RVOP( rv->X[ir->rd] = value1; const uint32_t res = value1 & value2; rv->io.mem_write_w(rv, addr, res); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, res); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1587,6 +1615,9 @@ RVOP( rv->X[ir->rd] = value1; const uint32_t res = value1 | value2; rv->io.mem_write_w(rv, addr, res); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, res); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1606,6 +1637,9 @@ RVOP( const int32_t b = value2; const uint32_t res = a < b ? value1 : value2; rv->io.mem_write_w(rv, addr, res); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, res); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1625,6 +1659,9 @@ RVOP( const int32_t b = value2; const uint32_t res = a > b ? value1 : value2; rv->io.mem_write_w(rv, addr, res); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, res); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1642,6 +1679,9 @@ RVOP( rv->X[ir->rd] = value1; const uint32_t ures = value1 < value2 ? value1 : value2; rv->io.mem_write_w(rv, addr, ures); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, ures); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1659,6 +1699,9 @@ RVOP( rv->X[ir->rd] = value1; const uint32_t ures = value1 > value2 ? value1 : value2; rv->io.mem_write_w(rv, addr, ures); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, ures); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -1688,7 +1731,11 @@ RVOP( /* copy from float registers */ const uint32_t addr = rv->X[ir->rs1] + ir->imm; RV_EXC_MISALIGN_HANDLER(3, STORE, false, 1); - rv->io.mem_write_w(rv, addr, rv->F[ir->rs2].v); + const uint32_t value = rv->F[ir->rs2].v; + rv->io.mem_write_w(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -2070,7 +2117,11 @@ RVOP( { const uint32_t addr = rv->X[ir->rs1] + (uint32_t) ir->imm; RV_EXC_MISALIGN_HANDLER(3, STORE, true, 1); - rv->io.mem_write_w(rv, addr, rv->X[ir->rs2]); + const uint32_t value = rv->X[ir->rs2]; + rv->io.mem_write_w(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ mem; @@ -2591,7 +2642,11 @@ RVOP( { const uint32_t addr = rv->X[rv_reg_sp] + ir->imm; RV_EXC_MISALIGN_HANDLER(3, STORE, true, 1); - rv->io.mem_write_w(rv, addr, rv->X[ir->rs2]); + const uint32_t value = rv->X[ir->rs2]; + rv->io.mem_write_w(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ mem; @@ -2622,7 +2677,11 @@ RVOP( { const uint32_t addr = rv->X[rv_reg_sp] + ir->imm; RV_EXC_MISALIGN_HANDLER(3, STORE, false, 1); - rv->io.mem_write_w(rv, addr, rv->F[ir->rs2].v); + const uint32_t value = rv->F[ir->rs2].v; + rv->io.mem_write_w(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ assert; /* FIXME: Implement */ @@ -2646,7 +2705,11 @@ RVOP( { const uint32_t addr = rv->X[ir->rs1] + (uint32_t) ir->imm; RV_EXC_MISALIGN_HANDLER(3, STORE, false, 1); - rv->io.mem_write_w(rv, addr, rv->F[ir->rs2].v); + const uint32_t value = rv->F[ir->rs2].v; + rv->io.mem_write_w(rv, addr, value); +#if RV32_HAS(ARCH_TEST) + check_tohost_write(rv, addr, value); +#endif }, GEN({ assert; /* FIXME: Implement */