adds initial semihosting host capabilities
This commit is contained in:
@ -55,6 +55,8 @@
|
||||
#include <util/ities.h>
|
||||
#include <util/sparse_array.h>
|
||||
|
||||
#include <iss/semihosting/semihosting.h>
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
@ -317,6 +319,8 @@ public:
|
||||
|
||||
void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); }
|
||||
|
||||
void set_semihosting_callback(std::function<void(arch_if*, reg_t, reg_t)>& cb) { semihosting_cb = cb; };
|
||||
|
||||
protected:
|
||||
struct riscv_instrumentation_if : public iss::instrumentation_if {
|
||||
|
||||
@ -371,9 +375,11 @@ protected:
|
||||
reg_t fault_data;
|
||||
uint64_t tohost = tohost_dflt;
|
||||
uint64_t fromhost = fromhost_dflt;
|
||||
unsigned to_host_wr_cnt = 0;
|
||||
bool tohost_lower_written = false;
|
||||
riscv_instrumentation_if instr_if;
|
||||
|
||||
std::function<void(arch_if*, reg_t, reg_t)> semihosting_cb;
|
||||
|
||||
using mem_type = util::sparse_array<uint8_t, 1ULL << 32>;
|
||||
using csr_type = util::sparse_array<typename traits<BASE>::reg_t, 1ULL << 12, 12>;
|
||||
using csr_page_type = typename csr_type::page_type;
|
||||
@ -1317,6 +1323,7 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned le
|
||||
template <typename BASE, features_e FEAT>
|
||||
iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) {
|
||||
switch(paddr.val) {
|
||||
// TODO remove UART, Peripherals should not be part of the ISS
|
||||
case 0xFFFF0000: // UART0 base, TXFIFO reg
|
||||
if(((char)data[0]) == '\n' || data[0] == 0) {
|
||||
LOG(INFO) << "UART" << ((paddr.val >> 12) & 0x3) << " send '" << uart_buf.str() << "'";
|
||||
@ -1334,7 +1341,8 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||
auto tohost_lower = (traits<BASE>::XLEN == 32 && paddr.val == tohost) || (traits<BASE>::XLEN == 64 && paddr.val == tohost);
|
||||
if(tohost_lower || tohost_upper) {
|
||||
uint64_t hostvar = *reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask));
|
||||
if(tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
|
||||
// in case of 32 bit system, two writes to tohost are needed, only evaluate on the second (high) write
|
||||
if(tohost_upper && (tohost_lower || tohost_lower_written)) {
|
||||
switch(hostvar >> 48) {
|
||||
case 0:
|
||||
if(hostvar != 0x1) {
|
||||
@ -1346,8 +1354,10 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||
}
|
||||
this->reg.trap_state = std::numeric_limits<uint32_t>::max();
|
||||
this->interrupt_sim = hostvar;
|
||||
#ifndef WITH_TCC
|
||||
throw(iss::simulation_stopped(hostvar));
|
||||
#endif
|
||||
break;
|
||||
// throw(iss::simulation_stopped(hostvar));
|
||||
case 0x0101: {
|
||||
char c = static_cast<char>(hostvar & 0xff);
|
||||
if(c == '\n' || c == 0) {
|
||||
@ -1355,13 +1365,13 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned l
|
||||
uart_buf.str("");
|
||||
} else
|
||||
uart_buf << c;
|
||||
to_host_wr_cnt = 0;
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tohost_lower_written = false;
|
||||
} else if(tohost_lower)
|
||||
to_host_wr_cnt++;
|
||||
tohost_lower_written = true;
|
||||
} else if((traits<BASE>::XLEN == 32 && paddr.val == fromhost + 4) || (traits<BASE>::XLEN == 64 && paddr.val == fromhost)) {
|
||||
uint64_t fhostvar = *reinterpret_cast<uint64_t*>(p.data() + (fromhost & mem.page_addr_mask));
|
||||
*reinterpret_cast<uint64_t*>(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
|
||||
@ -1474,6 +1484,31 @@ template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::
|
||||
} else {
|
||||
csr[utval | (new_priv << 8)] = addr;
|
||||
}
|
||||
if(semihosting_cb) {
|
||||
// Check for semihosting call
|
||||
phys_addr_t p_addr(access_type::DEBUG_READ, traits<BASE>::MEM, addr - 4);
|
||||
std::array<uint8_t, 8> data;
|
||||
// check for SLLI_X0_X0_0X1F and SRAI_X0_X0_0X07
|
||||
this->read_mem(p_addr, 4, data.data());
|
||||
p_addr.val += 8;
|
||||
this->read_mem(p_addr, 4, data.data() + 4);
|
||||
|
||||
const std::array<uint8_t, 8> ref_data = {0x13, 0x10, 0xf0, 0x01, 0x13, 0x50, 0x70, 0x40};
|
||||
if(data == ref_data) {
|
||||
this->reg.NEXT_PC = addr + 8;
|
||||
|
||||
std::array<char, 32> buffer;
|
||||
#if defined(_MSC_VER)
|
||||
sprintf(buffer.data(), "0x%016llx", addr);
|
||||
#else
|
||||
sprintf(buffer.data(), "0x%016lx", addr);
|
||||
#endif
|
||||
CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred ";
|
||||
|
||||
semihosting_callback(this, this->reg.X10 /*a0*/, this->reg.X11 /*a1*/);
|
||||
return this->reg.NEXT_PC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
|
Reference in New Issue
Block a user