diff --git a/src/iss/arch/riscv_hart_common.h b/src/iss/arch/riscv_hart_common.h index 95933c1..ef325bc 100644 --- a/src/iss/arch/riscv_hart_common.h +++ b/src/iss/arch/riscv_hart_common.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (C) 2017, 2018, 2021 MINRES Technologies GmbH + * Copyright (C) 2017 - 2025 MINRES Technologies GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -35,6 +35,8 @@ #ifndef _RISCV_HART_COMMON #define _RISCV_HART_COMMON +#include "iss/arch/traits.h" +#include "iss/log_categories.h" #include "iss/vm_types.h" #include #include @@ -42,11 +44,14 @@ #include #include #include +#include #include #include #include #include +#include #include +#include #if defined(__GNUC__) #define likely(x) ::__builtin_expect(!!(x), 1) @@ -312,16 +317,120 @@ inline void write_reg_uint32(uint64_t offs, uint32_t& reg, const uint8_t* const break; } } -struct riscv_hart_common { - riscv_hart_common(){}; - ~riscv_hart_common(){}; +template struct riscv_hart_common : public BASE { + const std::array lvl = {{'U', 'S', 'H', 'M'}}; + const std::array trap_str = {{"" + "Instruction address misaligned", // 0 + "Instruction access fault", // 1 + "Illegal instruction", // 2 + "Breakpoint", // 3 + "Load address misaligned", // 4 + "Load access fault", // 5 + "Store/AMO address misaligned", // 6 + "Store/AMO access fault", // 7 + "Environment call from U-mode", // 8 + "Environment call from S-mode", // 9 + "Reserved", // a + "Environment call from M-mode", // b + "Instruction page fault", // c + "Load page fault", // d + "Reserved", // e + "Store/AMO page fault"}}; + const std::array irq_str = {{"User software interrupt", "Supervisor software interrupt", "Reserved", + "Machine software interrupt", "User timer interrupt", "Supervisor timer interrupt", + "Reserved", "Machine timer interrupt", "User external interrupt", + "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; + constexpr static unsigned MEM = traits::MEM; + + using core = BASE; + using this_class = riscv_hart_common; + using phys_addr_t = typename core::phys_addr_t; + using reg_t = typename core::reg_t; + using addr_t = typename core::addr_t; + +#define MK_CSR_RD_CB(FCT) [this](unsigned a, reg_t& r) -> iss::status { return this->FCT(a, r); }; +#define MK_CSR_WR_CB(FCT) [this](unsigned a, reg_t r) -> iss::status { return this->FCT(a, r); }; + + riscv_hart_common() + : instr_if(*this) { + // reset values + csr[misa] = traits::MISA_VAL; + csr[mvendorid] = 0x669; + csr[marchid] = traits::MARCHID_VAL; + csr[mimpid] = 1; + + if(traits::FLEN > 0) { + csr_rd_cb[fcsr] = MK_CSR_RD_CB(read_fcsr); + csr_wr_cb[fcsr] = MK_CSR_WR_CB(write_fcsr); + csr_rd_cb[fflags] = MK_CSR_RD_CB(read_fcsr); + csr_wr_cb[fflags] = MK_CSR_WR_CB(write_fcsr); + csr_rd_cb[frm] = MK_CSR_RD_CB(read_fcsr); + csr_wr_cb[frm] = MK_CSR_WR_CB(write_fcsr); + } + for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) { + csr_rd_cb[addr] = MK_CSR_RD_CB(read_null); + csr_wr_cb[addr] = MK_CSR_WR_CB(write_plain); + } + if(traits::XLEN == 32) + for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) { + csr_rd_cb[addr] = MK_CSR_RD_CB(read_null); + csr_wr_cb[addr] = MK_CSR_WR_CB(write_plain); + } + for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) { + csr_rd_cb[addr] = MK_CSR_RD_CB(read_null); + csr_wr_cb[addr] = MK_CSR_WR_CB(write_plain); + } + for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) { + csr_rd_cb[addr] = MK_CSR_RD_CB(read_null); + } + if(traits::XLEN == 32) + for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) { + csr_rd_cb[addr] = MK_CSR_RD_CB(read_null); + } + // common regs + const std::array roaddrs{{misa, mvendorid, marchid, mimpid}}; + for(auto addr : roaddrs) { + csr_rd_cb[addr] = MK_CSR_RD_CB(read_plain); + csr_wr_cb[addr] = MK_CSR_WR_CB(write_null); + } + // special handling & overrides + csr_rd_cb[time] = MK_CSR_RD_CB(read_time); + if(traits::XLEN == 32) + csr_rd_cb[timeh] = MK_CSR_RD_CB(read_time); + csr_rd_cb[cycle] = MK_CSR_RD_CB(read_cycle); + if(traits::XLEN == 32) + csr_rd_cb[cycleh] = MK_CSR_RD_CB(read_cycle); + csr_rd_cb[instret] = MK_CSR_RD_CB(read_instret); + if(traits::XLEN == 32) + csr_rd_cb[instreth] = MK_CSR_RD_CB(read_instret); + + csr_rd_cb[mcycle] = MK_CSR_RD_CB(read_cycle); + csr_wr_cb[mcycle] = MK_CSR_WR_CB(write_cycle); + if(traits::XLEN == 32) + csr_rd_cb[mcycleh] = MK_CSR_RD_CB(read_cycle); + if(traits::XLEN == 32) + csr_wr_cb[mcycleh] = MK_CSR_WR_CB(write_cycle); + csr_rd_cb[minstret] = MK_CSR_RD_CB(read_instret); + csr_wr_cb[minstret] = MK_CSR_WR_CB(write_instret); + if(traits::XLEN == 32) + csr_rd_cb[minstreth] = MK_CSR_RD_CB(read_instret); + if(traits::XLEN == 32) + csr_wr_cb[minstreth] = MK_CSR_WR_CB(write_instret); + csr_rd_cb[mhartid] = MK_CSR_RD_CB(read_hartid); + }; + ~riscv_hart_common() {}; std::unordered_map symbol_table; uint64_t entry_address{0}; uint64_t tohost = std::numeric_limits::max(); uint64_t fromhost = std::numeric_limits::max(); - bool read_elf_file(std::string name, uint8_t expected_elf_class, - std::function cb) { + void set_semihosting_callback(semihosting_cb_t cb) { semihosting_cb = cb; }; + + std::pair load_file(std::string name, int type) { + return std::make_pair(entry_address, read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64)); + } + + bool read_elf_file(std::string name, uint8_t expected_elf_class) { // Create elfio reader ELFIO::elfio reader; // Load ELF data @@ -339,7 +448,8 @@ struct riscv_hart_common { const auto seg_data = pseg->get_data(); const auto type = pseg->get_type(); if(type == ELFIO::PT_LOAD && fsize > 0) { - auto res = cb(pseg->get_physical_address(), fsize, reinterpret_cast(seg_data)); + auto res = this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits::MEM, + pseg->get_physical_address(), fsize, reinterpret_cast(seg_data)); if(res != iss::Ok) CPPLOG(ERR) << "problem writing " << fsize << "bytes to 0x" << std::hex << pseg->get_physical_address(); } @@ -407,6 +517,280 @@ struct riscv_hart_common { } return iss::Ok; } + + constexpr bool has_compressed() { return traits::MISA_VAL & 0b0100; } + + constexpr reg_t get_pc_mask() { return has_compressed() ? (reg_t)~1 : (reg_t)~3; } + + void disass_output(uint64_t pc, const std::string instr) override { + // NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], + // (reg_t)state.mstatus, + // this->reg.cycle + cycle_offset); + NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [p:{};c:{}]", pc, instr, lvl[this->reg.PRIV], + this->reg.cycle + cycle_offset); + }; + + void register_custom_csr_rd(unsigned addr) { csr_rd_cb[addr] = &this_class::read_custom_csr; } + void register_custom_csr_wr(unsigned addr) { csr_wr_cb[addr] = &this_class::write_custom_csr; } + + bool debug_mode_active() { return this->reg.PRIV & 0x4; } + + const reg_t& get_mhartid() const { return mhartid_reg; } + void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; + + iss::status read_csr(unsigned addr, reg_t& val) { + if(addr >= csr.size()) + return iss::Err; + auto req_priv_lvl = (addr >> 8) & 0x3; + if(this->reg.PRIV < req_priv_lvl) // not having required privileges + throw illegal_instruction_fault(this->fault_data); + auto it = csr_rd_cb.find(addr); + if(it == csr_rd_cb.end() || !it->second) // non existent register + throw illegal_instruction_fault(this->fault_data); + return it->second(addr, val); + } + + iss::status write_csr(unsigned addr, reg_t val) { + if(addr >= csr.size()) + return iss::Err; + auto req_priv_lvl = (addr >> 8) & 0x3; + if(this->reg.PRIV < req_priv_lvl) // not having required privileges + throw illegal_instruction_fault(this->fault_data); + if((addr & 0xc00) == 0xc00) // writing to read-only region + throw illegal_instruction_fault(this->fault_data); + auto it = csr_wr_cb.find(addr); + if(it == csr_wr_cb.end() || !it->second) // non existent register + throw illegal_instruction_fault(this->fault_data); + return it->second(addr, val); + } + + iss::status read_null(unsigned addr, reg_t& val) { + val = 0; + return iss::Ok; + } + + iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; } + + iss::status read_plain(unsigned addr, reg_t& val) { + val = csr[addr]; + return iss::Ok; + } + + iss::status write_plain(unsigned addr, reg_t val) { + csr[addr] = val; + return iss::Ok; + } + + iss::status read_cycle(unsigned addr, reg_t& val) { + auto cycle_val = this->reg.cycle + cycle_offset; + if(addr == mcycle) { + val = static_cast(cycle_val); + } else if(addr == mcycleh) { + val = static_cast(cycle_val >> 32); + } + return iss::Ok; + } + + iss::status write_cycle(unsigned addr, reg_t val) { + if(sizeof(typename traits::reg_t) != 4) { + mcycle_csr = static_cast(val); + } else { + if(addr == mcycle) { + mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val; + } else { + mcycle_csr = (static_cast(val) << 32) + (mcycle_csr & 0xffffffff); + } + } + cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around + return iss::Ok; + } + + iss::status read_instret(unsigned addr, reg_t& val) { + if((addr & 0xff) == (minstret & 0xff)) { + val = static_cast(this->reg.instret); + } else if((addr & 0xff) == (minstreth & 0xff)) { + val = static_cast(this->reg.instret >> 32); + } + return iss::Ok; + } + + iss::status write_instret(unsigned addr, reg_t val) { + if(sizeof(typename traits::reg_t) != 4) { + this->reg.instret = static_cast(val); + } else { + if((addr & 0xff) == (minstret & 0xff)) { + this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val; + } else { + this->reg.instret = (static_cast(val) << 32) + (this->reg.instret & 0xffffffff); + } + } + this->reg.instret--; + return iss::Ok; + } + + iss::status read_time(unsigned addr, reg_t& val) { + uint64_t time_val = this->reg.cycle / (100000000 / 32768 - 1); //-> ~3052; + if(addr == time) { + val = static_cast(time_val); + } else if(addr == timeh) { + if(sizeof(typename traits::reg_t) != 4) + return iss::Err; + val = static_cast(time_val >> 32); + } + return iss::Ok; + } + + iss::status read_tvec(unsigned addr, reg_t& val) { + val = csr[addr] & ~2; + return iss::Ok; + } + + iss::status read_hartid(unsigned addr, reg_t& val) { + val = mhartid_reg; + return iss::Ok; + } + + iss::status write_epc(unsigned addr, reg_t val) { + csr[addr] = val & get_pc_mask(); + return iss::Ok; + } + + iss::status write_dcsr(unsigned addr, reg_t val) { + if(!debug_mode_active()) + throw illegal_instruction_fault(this->fault_data); + // +-------------- ebreakm + // | +---------- stepi + // | | +++----- cause + // | | ||| +- step + csr[addr] = val & 0b1000100111000100U; + return iss::Ok; + } + + iss::status read_debug(unsigned addr, reg_t& val) { + if(!debug_mode_active()) + throw illegal_instruction_fault(this->fault_data); + val = csr[addr]; + return iss::Ok; + } + + iss::status write_dscratch(unsigned addr, reg_t val) { + if(!debug_mode_active()) + throw illegal_instruction_fault(this->fault_data); + csr[addr] = val; + return iss::Ok; + } + + iss::status read_dpc(unsigned addr, reg_t& val) { + if(!debug_mode_active()) + throw illegal_instruction_fault(this->fault_data); + val = this->reg.DPC; + return iss::Ok; + } + + iss::status write_dpc(unsigned addr, reg_t val) { + if(!debug_mode_active()) + throw illegal_instruction_fault(this->fault_data); + this->reg.DPC = val; + return iss::Ok; + } + + iss::status read_fcsr(unsigned addr, reg_t& val) { + switch(addr) { + case 1: // fflags, 4:0 + val = bit_sub<0, 5>(this->get_fcsr()); + break; + case 2: // frm, 7:5 + val = bit_sub<5, 3>(this->get_fcsr()); + break; + case 3: // fcsr + val = this->get_fcsr(); + break; + default: + return iss::Err; + } + return iss::Ok; + } + + iss::status write_fcsr(unsigned addr, reg_t val) { + switch(addr) { + case 1: // fflags, 4:0 + this->set_fcsr((this->get_fcsr() & 0xffffffe0) | (val & 0x1f)); + break; + case 2: // frm, 7:5 + this->set_fcsr((this->get_fcsr() & 0xffffff1f) | ((val & 0x7) << 5)); + break; + case 3: // fcsr + this->set_fcsr(val & 0xff); + break; + default: + return iss::Err; + } + return iss::Ok; + } + + iss::status write_xtvt(unsigned addr, reg_t val) { + csr[addr] = val & ~0x3fULL; + return iss::Ok; + } + +protected: + struct riscv_instrumentation_if : public iss::instrumentation_if { + + riscv_instrumentation_if(riscv_hart_common& arch) + : arch(arch) {} + /** + * get the name of this architecture + * + * @return the name of this architecture + */ + const std::string core_type_name() const override { return traits::core_type; } + + uint64_t get_pc() override { return arch.reg.PC; } + + uint64_t get_next_pc() override { return arch.reg.NEXT_PC; } + + uint64_t get_instr_word() override { return arch.reg.instruction; } + + uint64_t get_instr_count() override { return arch.reg.icount; } + + uint64_t get_pendig_traps() override { return arch.reg.trap_state; } + + uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; } + + void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; } + + bool is_branch_taken() override { return arch.reg.last_branch; } + + unsigned get_reg_num() override { return traits::NUM_REGS; } + + unsigned get_reg_size(unsigned num) override { return traits::reg_bit_widths[num]; } + + std::unordered_map const& get_symbol_table(std::string name) override { return arch.symbol_table; } + + riscv_hart_common& arch; + }; + + friend struct riscv_instrumentation_if; + riscv_instrumentation_if instr_if; + + using csr_type = util::sparse_array::reg_t, 1ULL << 12, 12>; + using csr_page_type = typename csr_type::page_type; + csr_type csr; + + using rd_csr_f = std::function; + using wr_csr_f = std::function; + std::unordered_map csr_rd_cb; + std::unordered_map csr_wr_cb; + + reg_t mhartid_reg{0x0}; + uint64_t mcycle_csr{0}; + uint64_t minstret_csr{0}; + reg_t fault_data; + + int64_t cycle_offset{0}; + int64_t instret_offset{0}; + semihosting_cb_t semihosting_cb; + std::array vm; }; } // namespace arch diff --git a/src/iss/arch/riscv_hart_m_p.h b/src/iss/arch/riscv_hart_m_p.h index 3fe71b7..1a985b1 100644 --- a/src/iss/arch/riscv_hart_m_p.h +++ b/src/iss/arch/riscv_hart_m_p.h @@ -35,9 +35,7 @@ #ifndef _RISCV_HART_M_P_H #define _RISCV_HART_M_P_H -#include "iss/arch/traits.h" #include "iss/instrumentation_if.h" -#include "iss/log_categories.h" #include "iss/vm_if.h" #include "iss/vm_types.h" #include "riscv_hart_common.h" @@ -59,54 +57,20 @@ #include #include #include -#include -#include - -#include namespace iss { namespace arch { template -class riscv_hart_m_p : public BASE, public riscv_hart_common { -protected: - const std::array lvl = {{'U', 'S', 'H', 'M'}}; - const std::array trap_str = {{"" - "Instruction address misaligned", // 0 - "Instruction access fault", // 1 - "Illegal instruction", // 2 - "Breakpoint", // 3 - "Load address misaligned", // 4 - "Load access fault", // 5 - "Store/AMO address misaligned", // 6 - "Store/AMO access fault", // 7 - "Environment call from U-mode", // 8 - "Environment call from S-mode", // 9 - "Reserved", // a - "Environment call from M-mode", // b - "Instruction page fault", // c - "Load page fault", // d - "Reserved", // e - "Store/AMO page fault"}}; - const std::array irq_str = {{"User software interrupt", "Supervisor software interrupt", "Reserved", - "Machine software interrupt", "User timer interrupt", "Supervisor timer interrupt", - "Reserved", "Machine timer interrupt", "User external interrupt", - "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; - +class riscv_hart_m_p : public riscv_hart_common { public: using core = BASE; + using base = riscv_hart_common; using this_class = riscv_hart_m_p; using phys_addr_t = typename core::phys_addr_t; using reg_t = typename core::reg_t; using addr_t = typename core::addr_t; - using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t&); - using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t); - using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t* const); - using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const* const); - - constexpr static unsigned MEM = traits::MEM; - // primary template template struct hart_state {}; // specialization 32bit @@ -261,108 +225,41 @@ public: return 0b100010001000; // only machine mode is supported } - constexpr bool has_compressed() { return traits::MISA_VAL & 0b0100; } - constexpr reg_t get_pc_mask() { return has_compressed() ? (reg_t)~1 : (reg_t)~3; } - riscv_hart_m_p(feature_config cfg = feature_config{}); + virtual ~riscv_hart_m_p() = default; void reset(uint64_t address) override; - std::pair load_file(std::string name, int type = -1) override; - iss::status read(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, uint8_t* const data) override; iss::status write(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, const uint8_t* const data) override; - uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, fault_data, fault_data); } + uint64_t enter_trap(uint64_t flags) override { return riscv_hart_m_p::enter_trap(flags, this->fault_data, this->fault_data); } uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override; uint64_t leave_trap(uint64_t flags) override; - const reg_t& get_mhartid() const { return mhartid_reg; } - void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; - - void disass_output(uint64_t pc, const std::string instr) override { - NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [s:0x{:x};c:{}]", pc, instr, (reg_t)state.mstatus, - this->reg.cycle + cycle_offset); - }; - - iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; } - - void set_csr(unsigned addr, reg_t val) { csr[addr & csr.page_addr_mask] = val; } + void set_csr(unsigned addr, reg_t val) { this->csr[addr & this->csr.page_addr_mask] = val; } void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } - void set_semihosting_callback(semihosting_cb_t cb) { semihosting_cb = cb; }; - protected: - struct riscv_instrumentation_if : public iss::instrumentation_if { - - riscv_instrumentation_if(riscv_hart_m_p& arch) - : arch(arch) {} - /** - * get the name of this architecture - * - * @return the name of this architecture - */ - const std::string core_type_name() const override { return traits::core_type; } - - uint64_t get_pc() override { return arch.reg.PC; } - - uint64_t get_next_pc() override { return arch.reg.NEXT_PC; } - - uint64_t get_instr_word() override { return arch.reg.instruction; } - - uint64_t get_instr_count() override { return arch.reg.icount; } - - uint64_t get_pendig_traps() override { return arch.reg.trap_state; } - - uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; } - - void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; } - - bool is_branch_taken() override { return arch.reg.last_branch; } - - unsigned get_reg_num() override { return traits::NUM_REGS; } - - unsigned get_reg_size(unsigned num) override { return traits::reg_bit_widths[num]; } - - std::unordered_map const& get_symbol_table(std::string name) override { return arch.symbol_table; } - - riscv_hart_m_p& arch; - }; - - friend struct riscv_instrumentation_if; - virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t* const data); virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t* const data); iss::status read_clic(uint64_t addr, unsigned length, uint8_t* const data); iss::status write_clic(uint64_t addr, unsigned length, const uint8_t* const data); - virtual iss::status read_csr(unsigned addr, reg_t& val); - virtual iss::status write_csr(unsigned addr, reg_t val); + using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t* const); + using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const* const); hart_state_type state; - int64_t cycle_offset{0}; - uint64_t mcycle_csr{0}; - int64_t instret_offset{0}; - uint64_t minstret_csr{0}; - reg_t fault_data; - riscv_instrumentation_if instr_if; - - semihosting_cb_t semihosting_cb; using mem_type = util::sparse_array; - using csr_type = util::sparse_array::reg_t, 1ULL << 12, 12>; - using csr_page_type = typename csr_type::page_type; mem_type mem; - csr_type csr; std::unordered_map ptw; std::unordered_map atomic_reservation; - std::unordered_map csr_rd_cb; - std::unordered_map csr_wr_cb; uint8_t clic_cfg_reg{0}; std::array clic_inttrig_reg; union clic_int_reg_t { @@ -380,16 +277,6 @@ protected: std::vector tcm; - iss::status read_plain(unsigned addr, reg_t& val); - iss::status write_plain(unsigned addr, reg_t val); - iss::status read_null(unsigned addr, reg_t& val); - iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; } - iss::status read_cycle(unsigned addr, reg_t& val); - iss::status write_cycle(unsigned addr, reg_t val); - iss::status read_instret(unsigned addr, reg_t& val); - iss::status write_instret(unsigned addr, reg_t val); - iss::status read_tvec(unsigned addr, reg_t& val); - iss::status read_time(unsigned addr, reg_t& val); iss::status read_status(unsigned addr, reg_t& val); iss::status write_status(unsigned addr, reg_t val); iss::status read_cause(unsigned addr, reg_t& val); @@ -397,8 +284,6 @@ protected: iss::status read_ie(unsigned addr, reg_t& val); iss::status write_ie(unsigned addr, reg_t val); iss::status read_ip(unsigned addr, reg_t& val); - iss::status read_hartid(unsigned addr, reg_t& val); - iss::status write_epc(unsigned addr, reg_t val); iss::status read_intstatus(unsigned addr, reg_t& val); iss::status write_intthresh(unsigned addr, reg_t val); iss::status write_xtvt(unsigned addr, reg_t val); @@ -407,26 +292,14 @@ protected: iss::status write_dscratch(unsigned addr, reg_t val); iss::status read_dpc(unsigned addr, reg_t& val); iss::status write_dpc(unsigned addr, reg_t val); - iss::status read_fcsr(unsigned addr, reg_t& val); - iss::status write_fcsr(unsigned addr, reg_t val); - - virtual iss::status read_custom_csr(unsigned addr, reg_t& val) { return iss::status::Err; }; - virtual iss::status write_custom_csr(unsigned addr, reg_t val) { return iss::status::Err; }; - - void register_custom_csr_rd(unsigned addr) { csr_rd_cb[addr] = &this_class::read_custom_csr; } - void register_custom_csr_wr(unsigned addr) { csr_wr_cb[addr] = &this_class::write_custom_csr; } - - reg_t mhartid_reg{0x0}; void check_interrupt(); - bool pmp_check(const access_type type, const uint64_t addr, const unsigned len); std::vector> memfn_range; std::vector> memfn_read; std::vector> memfn_write; void insert_mem_range(uint64_t, uint64_t, std::function, std::function); feature_config cfg; unsigned mcause_max_irq{(FEAT & features_e::FEAT_CLIC) ? std::max(16U, static_cast(traits::CLIC_NUM_IRQ)) : 16U}; - inline bool debug_mode_active() { return this->reg.PRIV & 0x4; } std::pair, std::function> replace_mem_access(std::function rd, std::function wr) { @@ -442,104 +315,45 @@ protected: template riscv_hart_m_p::riscv_hart_m_p(feature_config cfg) : state() -, instr_if(*this) , cfg(cfg) { - // reset values - csr[misa] = traits::MISA_VAL; - csr[mvendorid] = 0x669; - csr[marchid] = traits::MARCHID_VAL; - csr[mimpid] = 1; - - if(traits::FLEN > 0) { - csr_rd_cb[fcsr] = &this_class::read_fcsr; - csr_wr_cb[fcsr] = &this_class::write_fcsr; - } - for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_plain; - } - if(traits::XLEN == 32) - for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_plain; - } - for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_plain; - } - for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - } - if(traits::XLEN == 32) - for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - } - // common regs - const std::array roaddrs{{misa, mvendorid, marchid, mimpid}}; - for(auto addr : roaddrs) { - csr_rd_cb[addr] = &this_class::read_plain; - csr_wr_cb[addr] = &this_class::write_null; - } const std::array rwaddrs{{mepc, mtvec, mscratch, mtval}}; for(auto addr : rwaddrs) { - csr_rd_cb[addr] = &this_class::read_plain; - csr_wr_cb[addr] = &this_class::write_plain; + this->csr_rd_cb[addr] = MK_CSR_RD_CB(read_plain); + // MK_CSR_RD_CB(read_plain(a,r);}; + this->csr_wr_cb[addr] = MK_CSR_WR_CB(write_plain); } - // special handling & overrides - csr_rd_cb[time] = &this_class::read_time; - if(traits::XLEN == 32) - csr_rd_cb[timeh] = &this_class::read_time; - csr_rd_cb[cycle] = &this_class::read_cycle; - if(traits::XLEN == 32) - csr_rd_cb[cycleh] = &this_class::read_cycle; - csr_rd_cb[instret] = &this_class::read_instret; - if(traits::XLEN == 32) - csr_rd_cb[instreth] = &this_class::read_instret; + this->csr_rd_cb[mstatus] = MK_CSR_RD_CB(read_status); + this->csr_wr_cb[mstatus] = MK_CSR_WR_CB(write_status); + this->csr_rd_cb[mcause] = MK_CSR_RD_CB(read_cause); + this->csr_wr_cb[mcause] = MK_CSR_WR_CB(write_cause); + this->csr_rd_cb[mtvec] = MK_CSR_RD_CB(read_tvec); + this->csr_wr_cb[mepc] = MK_CSR_WR_CB(write_epc); + this->csr_rd_cb[mip] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_null); + this->csr_rd_cb[mie] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[mie] = MK_CSR_WR_CB(write_ie); + this->csr_wr_cb[misa] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[mvendorid] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[marchid] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[mimpid] = MK_CSR_WR_CB(write_null); - csr_rd_cb[mcycle] = &this_class::read_cycle; - csr_wr_cb[mcycle] = &this_class::write_cycle; - if(traits::XLEN == 32) - csr_rd_cb[mcycleh] = &this_class::read_cycle; - if(traits::XLEN == 32) - csr_wr_cb[mcycleh] = &this_class::write_cycle; - csr_rd_cb[minstret] = &this_class::read_instret; - csr_wr_cb[minstret] = &this_class::write_instret; - if(traits::XLEN == 32) - csr_rd_cb[minstreth] = &this_class::read_instret; - if(traits::XLEN == 32) - csr_wr_cb[minstreth] = &this_class::write_instret; - csr_rd_cb[mstatus] = &this_class::read_status; - csr_wr_cb[mstatus] = &this_class::write_status; - csr_rd_cb[mcause] = &this_class::read_cause; - csr_wr_cb[mcause] = &this_class::write_cause; - csr_rd_cb[mtvec] = &this_class::read_tvec; - csr_wr_cb[mepc] = &this_class::write_epc; - csr_rd_cb[mip] = &this_class::read_ip; - csr_wr_cb[mip] = &this_class::write_null; - csr_rd_cb[mie] = &this_class::read_ie; - csr_wr_cb[mie] = &this_class::write_ie; - csr_rd_cb[mhartid] = &this_class::read_hartid; - csr_wr_cb[misa] = &this_class::write_null; - csr_wr_cb[mvendorid] = &this_class::write_null; - csr_wr_cb[marchid] = &this_class::write_null; - csr_wr_cb[mimpid] = &this_class::write_null; if(FEAT & FEAT_CLIC) { - csr_rd_cb[mtvt] = &this_class::read_plain; - csr_wr_cb[mtvt] = &this_class::write_xtvt; - // csr_rd_cb[mxnti] = &this_class::read_csr_reg; - // csr_wr_cb[mxnti] = &this_class::write_csr_reg; - csr_rd_cb[mintstatus] = &this_class::read_intstatus; - csr_wr_cb[mintstatus] = &this_class::write_null; - // csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg; - // csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg; - // csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg; - // csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg; - csr_rd_cb[mintthresh] = &this_class::read_plain; - csr_wr_cb[mintthresh] = &this_class::write_intthresh; + this->csr_rd_cb[mtvt] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[mtvt] = MK_CSR_WR_CB(write_xtvt); + // this->csr_rd_cb[mxnti] = MK_CSR_RD_CB(read_plain(a,r);}; + // this->csr_wr_cb[mxnti] = MK_CSR_WR_CB(write_plain(a,r);}; + this->csr_rd_cb[mintstatus] = MK_CSR_RD_CB(read_intstatus); + this->csr_wr_cb[mintstatus] = MK_CSR_WR_CB(write_null); + // this->csr_rd_cb[mscratchcsw] = MK_CSR_RD_CB(read_plain(a,r);}; + // this->csr_wr_cb[mscratchcsw] = MK_CSR_WR_CB(write_plain(a,r);}; + // this->csr_rd_cb[mscratchcswl] = MK_CSR_RD_CB(read_plain(a,r);}; + // this->csr_wr_cb[mscratchcswl] = MK_CSR_WR_CB(write_plain(a,r);}; + this->csr_rd_cb[mintthresh] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[mintthresh] = MK_CSR_WR_CB(write_intthresh); clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw = 0}); clic_cfg_reg = 0x20; clic_mact_lvl = clic_mprev_lvl = (1 << (cfg.clic_int_ctl_bits)) - 1; - csr[mintthresh] = (1 << (cfg.clic_int_ctl_bits)) - 1; + this->csr[mintthresh] = (1 << (cfg.clic_int_ctl_bits)) - 1; insert_mem_range( cfg.clic_base, 0x5000UL, [this](phys_addr_t addr, unsigned length, uint8_t* const data) { return read_clic(addr.val, length, data); }, @@ -560,31 +374,19 @@ riscv_hart_m_p::riscv_hart_m_p(feature_config cfg) insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb); } if(FEAT & FEAT_DEBUG) { - csr_wr_cb[dscratch0] = &this_class::write_dscratch; - csr_rd_cb[dscratch0] = &this_class::read_debug; - csr_wr_cb[dscratch1] = &this_class::write_dscratch; - csr_rd_cb[dscratch1] = &this_class::read_debug; - csr_wr_cb[dpc] = &this_class::write_dpc; - csr_rd_cb[dpc] = &this_class::read_dpc; - csr_wr_cb[dcsr] = &this_class::write_dcsr; - csr_rd_cb[dcsr] = &this_class::read_debug; + this->csr_wr_cb[dscratch0] = MK_CSR_WR_CB(write_dscratch); + this->csr_rd_cb[dscratch0] = MK_CSR_RD_CB(read_debug); + this->csr_wr_cb[dscratch1] = MK_CSR_WR_CB(write_dscratch); + this->csr_rd_cb[dscratch1] = MK_CSR_RD_CB(read_debug); + this->csr_wr_cb[dpc] = MK_CSR_WR_CB(write_dpc); + this->csr_rd_cb[dpc] = MK_CSR_RD_CB(read_dpc); + this->csr_wr_cb[dcsr] = MK_CSR_WR_CB(write_dcsr); + this->csr_rd_cb[dcsr] = MK_CSR_RD_CB(read_debug); } hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return this->read_mem(a, l, d); }; hart_mem_wr_delegate = [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { return this->write_mem(a, l, d); }; } -template -std::pair riscv_hart_m_p::load_file(std::string name, int type) { - if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64, - [this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status { - return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits::MEM, addr, size, - data); - })) { - return std::make_pair(entry_address, true); - } - return std::make_pair(entry_address, false); -} - template inline void riscv_hart_m_p::insert_mem_range(uint64_t base, uint64_t size, std::function rd_f, std::function wr_fn) { @@ -613,9 +415,9 @@ iss::status riscv_hart_m_p::read(const address_type type, co try { switch(space) { case traits::MEM: { - auto alignment = is_fetch(access) ? (has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); + auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { - fault_data = addr; + this->fault_data = addr; if(is_debug(access)) throw trap_access(0, addr); this->reg.trap_state = (1UL << 31); // issue trap 0 @@ -624,7 +426,7 @@ iss::status riscv_hart_m_p::read(const address_type type, co try { if(!is_debug(access) && (addr & (alignment - 1))) { this->reg.trap_state = (1UL << 31) | 4 << 16; - fault_data = addr; + this->fault_data = addr; return iss::Err; } phys_addr_t phys_addr{access, space, addr}; @@ -644,13 +446,13 @@ iss::status riscv_hart_m_p::read(const address_type type, co } if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { this->reg.trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault - fault_data = addr; + this->fault_data = addr; } return res; } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } @@ -658,7 +460,7 @@ iss::status riscv_hart_m_p::read(const address_type type, co case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; - return read_csr(addr, *reinterpret_cast(data)); + return this->read_csr(addr, *reinterpret_cast(data)); } break; case traits::FENCE: { if((addr + length) > mem.size()) @@ -680,7 +482,7 @@ iss::status riscv_hart_m_p::read(const address_type type, co } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } @@ -716,7 +518,7 @@ iss::status riscv_hart_m_p::write(const address_type type, c switch(space) { case traits::MEM: { if(unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) { - fault_data = addr; + this->fault_data = addr; if(access && iss::access_type::DEBUG) throw trap_access(0, addr); this->reg.trap_state = (1UL << 31); // issue trap 0 @@ -726,7 +528,7 @@ iss::status riscv_hart_m_p::write(const address_type type, c auto alignment = std::min(length, sizeof(reg_t)); if(length > 1 && (addr & (alignment - 1)) && !is_debug(access)) { this->reg.trap_state = (1UL << 31) | 6 << 16; - fault_data = addr; + this->fault_data = addr; return iss::Err; } phys_addr_t phys_addr{access, space, addr}; @@ -746,19 +548,19 @@ iss::status riscv_hart_m_p::write(const address_type type, c } if(unlikely(res != iss::Ok && !is_debug(access))) { this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault) - fault_data = addr; + this->fault_data = addr; } return res; } catch(trap_access& ta) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; return iss::Err; } } break; case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; - return write_csr(addr, *reinterpret_cast(data)); + return this->write_csr(addr, *reinterpret_cast(data)); } break; case traits::FENCE: { if((addr + length) > mem.size()) @@ -782,128 +584,12 @@ iss::status riscv_hart_m_p::write(const address_type type, c } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } } -template -iss::status riscv_hart_m_p::read_csr(unsigned addr, reg_t& val) { - if(addr >= csr.size()) - return iss::Err; - auto req_priv_lvl = (addr >> 8) & 0x3; - if(this->reg.PRIV < req_priv_lvl) // not having required privileges - throw illegal_instruction_fault(this->fault_data); - auto it = csr_rd_cb.find(addr); - if(it == csr_rd_cb.end() || !it->second) // non existent register - throw illegal_instruction_fault(this->fault_data); - return (this->*(it->second))(addr, val); -} - -template -iss::status riscv_hart_m_p::write_csr(unsigned addr, reg_t val) { - if(addr >= csr.size()) - return iss::Err; - auto req_priv_lvl = (addr >> 8) & 0x3; - if(this->reg.PRIV < req_priv_lvl) // not having required privileges - throw illegal_instruction_fault(this->fault_data); - if((addr & 0xc00) == 0xc00) // writing to read-only region - throw illegal_instruction_fault(this->fault_data); - auto it = csr_wr_cb.find(addr); - if(it == csr_wr_cb.end() || !it->second) // non existent register - throw illegal_instruction_fault(this->fault_data); - return (this->*(it->second))(addr, val); -} - -template -iss::status riscv_hart_m_p::read_null(unsigned addr, reg_t& val) { - val = 0; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::read_plain(unsigned addr, reg_t& val) { - val = csr[addr]; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_plain(unsigned addr, reg_t val) { - csr[addr] = val; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::read_cycle(unsigned addr, reg_t& val) { - auto cycle_val = this->reg.cycle + cycle_offset; - if(addr == mcycle) { - val = static_cast(cycle_val); - } else if(addr == mcycleh) { - val = static_cast(cycle_val >> 32); - } - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_cycle(unsigned addr, reg_t val) { - if(sizeof(typename traits::reg_t) != 4) { - mcycle_csr = static_cast(val); - } else { - if(addr == mcycle) { - mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val; - } else { - mcycle_csr = (static_cast(val) << 32) + (mcycle_csr & 0xffffffff); - } - } - cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::read_instret(unsigned addr, reg_t& val) { - if((addr & 0xff) == (minstret & 0xff)) { - val = static_cast(this->reg.instret); - } else if((addr & 0xff) == (minstreth & 0xff)) { - val = static_cast(this->reg.instret >> 32); - } - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_instret(unsigned addr, reg_t val) { - if(sizeof(typename traits::reg_t) != 4) { - this->reg.instret = static_cast(val); - } else { - if((addr & 0xff) == (minstret & 0xff)) { - this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val; - } else { - this->reg.instret = (static_cast(val) << 32) + (this->reg.instret & 0xffffffff); - } - } - this->reg.instret--; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::read_time(unsigned addr, reg_t& val) { - uint64_t time_val = this->reg.cycle / (100000000 / 32768 - 1); //-> ~3052; - if(addr == time) { - val = static_cast(time_val); - } else if(addr == timeh) { - if(sizeof(typename traits::reg_t) != 4) - return iss::Err; - val = static_cast(time_val >> 32); - } - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::read_tvec(unsigned addr, reg_t& val) { - val = FEAT & features_e::FEAT_CLIC ? csr[addr] : csr[addr] & ~2; - return iss::Ok; -} - template iss::status riscv_hart_m_p::read_status(unsigned addr, reg_t& val) { val = state.mstatus & hart_state_type::get_mask(); @@ -919,48 +605,42 @@ iss::status riscv_hart_m_p::write_status(unsigned addr, reg_ template iss::status riscv_hart_m_p::read_cause(unsigned addr, reg_t& val) { - if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec] & 0x3) == 3) { - val = csr[addr] & ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16)); + if((FEAT & features_e::FEAT_CLIC) && (this->csr[mtvec] & 0x3) == 3) { + val = this->csr[addr] & ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16)); val |= clic_mprev_lvl << 16; val |= state.mstatus.MPIE << 27; val |= state.mstatus.MPP << 28; } else - val = csr[addr] & ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1)); + val = this->csr[addr] & ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1)); return iss::Ok; } template iss::status riscv_hart_m_p::write_cause(unsigned addr, reg_t val) { - if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec] & 0x3) == 3) { + if((FEAT & features_e::FEAT_CLIC) && (this->csr[mtvec] & 0x3) == 3) { auto mask = ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16)); - csr[addr] = (val & mask) | (csr[addr] & ~mask); + this->csr[addr] = (val & mask) | (this->csr[addr] & ~mask); clic_mprev_lvl = ((val >> 16) & 0xff) | (1 << (8 - cfg.clic_int_ctl_bits)) - 1; state.mstatus.MPIE = (val >> 27) & 0x1; state.mstatus.MPP = (val >> 28) & 0x3; } else { auto mask = ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1)); - csr[addr] = (val & mask) | (csr[addr] & ~mask); + this->csr[addr] = (val & mask) | (this->csr[addr] & ~mask); } return iss::Ok; } -template -iss::status riscv_hart_m_p::read_hartid(unsigned addr, reg_t& val) { - val = mhartid_reg; - return iss::Ok; -} - template iss::status riscv_hart_m_p::read_ie(unsigned addr, reg_t& val) { auto mask = get_irq_mask(); - val = csr[mie] & mask; + val = this->csr[mie] & mask; return iss::Ok; } template iss::status riscv_hart_m_p::write_ie(unsigned addr, reg_t val) { auto mask = get_irq_mask(); - csr[mie] = (csr[mie] & ~mask) | (val & mask); + this->csr[mie] = (this->csr[mie] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } @@ -968,57 +648,7 @@ iss::status riscv_hart_m_p::write_ie(unsigned addr, reg_t va template iss::status riscv_hart_m_p::read_ip(unsigned addr, reg_t& val) { auto mask = get_irq_mask(); - val = csr[mip] & mask; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_epc(unsigned addr, reg_t val) { - csr[addr] = val & get_pc_mask(); - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_dcsr(unsigned addr, reg_t val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - // +-------------- ebreakm - // | +---------- stepi - // | | +++----- cause - // | | ||| +- step - csr[addr] = val & 0b1000100111000100U; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::read_debug(unsigned addr, reg_t& val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - val = csr[addr]; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_dscratch(unsigned addr, reg_t val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - csr[addr] = val; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::read_dpc(unsigned addr, reg_t& val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - val = this->reg.DPC; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_dpc(unsigned addr, reg_t val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - this->reg.DPC = val; + val = this->csr[mip] & mask; return iss::Ok; } @@ -1028,27 +658,9 @@ iss::status riscv_hart_m_p::read_intstatus(unsigned addr, re return iss::Ok; } -template -iss::status riscv_hart_m_p::read_fcsr(unsigned addr, reg_t& val) { - val = this->get_fcsr(); - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_fcsr(unsigned addr, reg_t val) { - this->set_fcsr(val); - return iss::Ok; -} - template iss::status riscv_hart_m_p::write_intthresh(unsigned addr, reg_t val) { - csr[addr] = (val & 0xff) | (1 << (cfg.clic_int_ctl_bits)) - 1; - return iss::Ok; -} - -template -iss::status riscv_hart_m_p::write_xtvt(unsigned addr, reg_t val) { - csr[addr] = val & ~0x3fULL; + this->csr[addr] = (val & 0xff) | (1 << (cfg.clic_int_ctl_bits)) - 1; return iss::Ok; } @@ -1068,21 +680,23 @@ template iss::status riscv_hart_m_p::write_mem(phys_addr_t paddr, unsigned length, const uint8_t* const data) { mem_type::page_type& p = mem(paddr.val / mem.page_size); std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask)); - // tohost handling in case of riscv-test + // this->tohost handling in case of riscv-test // according to https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754: if(paddr.access && iss::access_type::FUNC) { - if(paddr.val == tohost) { + if(paddr.val == this->tohost) { reg_t cur_data = *reinterpret_cast(data); // Extract Device (bits 63:56) - uint8_t device = traits::XLEN == 32 ? *reinterpret_cast(p.data() + ((tohost + 4) & mem.page_addr_mask)) >> 24 - : (cur_data >> 56) & 0xFF; + uint8_t device = traits::XLEN == 32 + ? *reinterpret_cast(p.data() + ((this->tohost + 4) & mem.page_addr_mask)) >> 24 + : (cur_data >> 56) & 0xFF; // Extract Command (bits 55:48) - uint8_t command = traits::XLEN == 32 ? *reinterpret_cast(p.data() + ((tohost + 4) & mem.page_addr_mask)) >> 16 - : (cur_data >> 48) & 0xFF; + uint8_t command = traits::XLEN == 32 + ? *reinterpret_cast(p.data() + ((this->tohost + 4) & mem.page_addr_mask)) >> 16 + : (cur_data >> 48) & 0xFF; // Extract payload (bits 47:0) uint64_t payload_addr = cur_data & 0xFFFFFFFFFFFFULL; if(payload_addr & 1) { - CPPLOG(FATAL) << "tohost value is 0x" << std::hex << payload_addr << std::dec << " (" << payload_addr + CPPLOG(FATAL) << "this->tohost value is 0x" << std::hex << payload_addr << std::dec << " (" << payload_addr << "), stopping simulation"; this->reg.trap_state = std::numeric_limits::max(); this->interrupt_sim = payload_addr; @@ -1094,24 +708,24 @@ iss::status riscv_hart_m_p::write_mem(phys_addr_t paddr, uns CPPLOG(ERR) << "Syscall read went wrong"; uint64_t syscall_num = loaded_payload.at(0); if(syscall_num == 64) { // SYS_WRITE - return execute_sys_write(this, loaded_payload, traits::MEM); + return this->execute_sys_write(this, loaded_payload, traits::MEM); } else { - CPPLOG(ERR) << "tohost syscall with number 0x" << std::hex << syscall_num << std::dec << " (" << syscall_num + CPPLOG(ERR) << "this->tohost syscall with number 0x" << std::hex << syscall_num << std::dec << " (" << syscall_num << ") not implemented"; this->reg.trap_state = std::numeric_limits::max(); this->interrupt_sim = payload_addr; return iss::Ok; } } else { - CPPLOG(ERR) << "tohost functionality not implemented for device " << device << " and command " << command; + CPPLOG(ERR) << "this->tohost functionality not implemented for device " << device << " and command " << command; this->reg.trap_state = std::numeric_limits::max(); this->interrupt_sim = payload_addr; return iss::Ok; } } - if((traits::XLEN == 32 && paddr.val == fromhost + 4) || (traits::XLEN == 64 && paddr.val == fromhost)) { - uint64_t fhostvar = *reinterpret_cast(p.data() + (fromhost & mem.page_addr_mask)); - *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; + if((traits::XLEN == 32 && paddr.val == this->fromhost + 4) || (traits::XLEN == 64 && paddr.val == this->fromhost)) { + uint64_t fhostvar = *reinterpret_cast(p.data() + (this->fromhost & mem.page_addr_mask)); + *reinterpret_cast(p.data() + (this->tohost & mem.page_addr_mask)) = fhostvar; } } return iss::Ok; @@ -1165,7 +779,7 @@ template void riscv_hart_m_pcsr[mip] & this->csr[mie]; bool mstatus_mie = state.mstatus.MIE; auto m_enabled = this->reg.PRIV < PRIV_M || mstatus_mie; @@ -1193,7 +807,7 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t if(cause == 11) cause = 0x8 + PRIV_M; // adjust environment call cause // store ret addr in xepc register - csr[mepc] = static_cast(addr) & get_pc_mask(); // store actual address instruction of exception + this->csr[mepc] = static_cast(addr) & this->get_pc_mask(); // store actual address instruction of exception /* * write mtval if new_priv=M_MODE, spec says: * When a hardware breakpoint is triggered, or an instruction-fetch, load, @@ -1203,20 +817,20 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t */ switch(cause) { case 0: - csr[mtval] = static_cast(tval); + this->csr[mtval] = static_cast(tval); break; case 2: - csr[mtval] = (!has_compressed() || (tval & 0x3) == 3) ? tval : tval & 0xffff; + this->csr[mtval] = (!this->has_compressed() || (tval & 0x3) == 3) ? tval : tval & 0xffff; break; case 3: - if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) { + if((FEAT & FEAT_DEBUG) && (this->csr[dcsr] & 0x8000)) { this->reg.DPC = addr; - csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1 << 6) | PRIV_M; // FIXME: cause should not be 4 (stepi) + this->csr[dcsr] = (this->csr[dcsr] & ~0x1c3) | (1 << 6) | PRIV_M; // FIXME: cause should not be 4 (stepi) new_priv = this->reg.PRIV | PRIV_D; } else { - csr[mtval] = addr; + this->csr[mtval] = addr; } - if(semihosting_cb) { + if(this->semihosting_cb) { // Check for semihosting call phys_addr_t p_addr(access_type::DEBUG_READ, traits::MEM, addr - 4); std::array data; @@ -1237,24 +851,24 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t #endif NSCLOG(INFO, LOGCAT) << "Semihosting call at address " << buffer.data() << " occurred "; - semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); + this->semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); return this->reg.NEXT_PC; } } break; case 4: case 6: - csr[mtval] = fault_data; + this->csr[mtval] = this->fault_data; break; default: - csr[mtval] = 0; + this->csr[mtval] = 0; } - fault_data = 0; + this->fault_data = 0; } else { - csr[mepc] = this->reg.NEXT_PC & get_pc_mask(); // store next address if interrupt + this->csr[mepc] = this->reg.NEXT_PC & this->get_pc_mask(); // store next address if interrupt this->reg.pending_trap = 0; } - csr[mcause] = (trap_id << (traits::XLEN - 1)) + cause; + this->csr[mcause] = (trap_id << (traits::XLEN - 1)) + cause; // update mstatus // xPP field of mstatus is written with the active privilege mode at the time // of the trap; the x PIE field of mstatus @@ -1267,11 +881,11 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t state.mstatus.MIE = false; // get trap vector - auto xtvec = csr[mtvec]; + auto xtvec = this->csr[mtvec]; // calculate adds// set NEXT_PC to trap addressess to jump to based on MODE if((FEAT & features_e::FEAT_CLIC) && trap_id != 0 && (xtvec & 0x3UL) == 3UL) { reg_t data; - auto ret = read(address_type::LOGICAL, access_type::READ, 0, csr[mtvt], sizeof(reg_t), reinterpret_cast(&data)); + auto ret = read(address_type::LOGICAL, access_type::READ, 0, this->csr[mtvt], sizeof(reg_t), reinterpret_cast(&data)); if(ret == iss::Err) return this->reg.PC; this->reg.NEXT_PC = data; @@ -1291,8 +905,8 @@ uint64_t riscv_hart_m_p::enter_trap(uint64_t flags, uint64_t sprintf(buffer.data(), "0x%016lx", addr); #endif if((flags & 0xffffffff) != 0xffffffff) - NSCLOG(INFO, LOGCAT) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" - << cause << ")" + NSCLOG(INFO, LOGCAT) << (trap_id ? "Interrupt" : "Trap") << " with cause '" + << (trap_id ? this->irq_str[cause] : this->trap_str[cause]) << "' (" << cause << ")" << " at address " << buffer.data() << " occurred"; return this->reg.NEXT_PC; } @@ -1301,7 +915,7 @@ template uint64_t riscv_hart_m state.mstatus.MIE = state.mstatus.MPIE; state.mstatus.MPIE = 1; // sets the pc to the value stored in the x epc register. - this->reg.NEXT_PC = csr[mepc] & get_pc_mask(); + this->reg.NEXT_PC = this->csr[mepc] & this->get_pc_mask(); NSCLOG(INFO, LOGCAT) << "Executing xRET"; check_interrupt(); this->reg.trap_state = this->reg.pending_trap; diff --git a/src/iss/arch/riscv_hart_msu_vp.h b/src/iss/arch/riscv_hart_msu_vp.h index ca621c2..1ffeafd 100644 --- a/src/iss/arch/riscv_hart_msu_vp.h +++ b/src/iss/arch/riscv_hart_msu_vp.h @@ -35,9 +35,7 @@ #ifndef _RISCV_HART_MSU_VP_H #define _RISCV_HART_MSU_VP_H -#include "iss/arch/traits.h" #include "iss/instrumentation_if.h" -#include "iss/log_categories.h" #include "iss/vm_if.h" #include "iss/vm_types.h" #include "riscv_hart_common.h" @@ -59,52 +57,19 @@ #include #include #include -#include -#include - -#include namespace iss { namespace arch { -template class riscv_hart_msu_vp : public BASE, public riscv_hart_common { -protected: - const std::array lvl = {{'U', 'S', 'H', 'M'}}; - const std::array trap_str = {{"" - "Instruction address misaligned", // 0 - "Instruction access fault", // 1 - "Illegal instruction", // 2 - "Breakpoint", // 3 - "Load address misaligned", // 4 - "Load access fault", // 5 - "Store/AMO address misaligned", // 6 - "Store/AMO access fault", // 7 - "Environment call from U-mode", // 8 - "Environment call from S-mode", // 9 - "Reserved", // a - "Environment call from M-mode", // b - "Instruction page fault", // c - "Load page fault", // d - "Reserved", // e - "Store/AMO page fault"}}; - const std::array irq_str = {{"User software interrupt", "Supervisor software interrupt", "Reserved", - "Machine software interrupt", "User timer interrupt", "Supervisor timer interrupt", - "Reserved", "Machine timer interrupt", "User external interrupt", - "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; - +template class riscv_hart_msu_vp : public riscv_hart_common { public: using core = BASE; + using base = riscv_hart_common; using this_class = riscv_hart_msu_vp; - using virt_addr_t = typename core::virt_addr_t; using phys_addr_t = typename core::phys_addr_t; using reg_t = typename core::reg_t; using addr_t = typename core::addr_t; - using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t&); - using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t); - - constexpr static unsigned MEM = traits::MEM; - // primary template template struct hart_state {}; // specialization 32bit @@ -155,7 +120,7 @@ public: void write_mstatus(T val, unsigned priv_lvl) { auto mask = get_mask(priv_lvl); - auto new_val = (mstatus.st.value & ~mask) | (val & mask); + auto new_val = (static_cast(mstatus) & ~mask) | (val & mask); mstatus = new_val; } @@ -314,13 +279,12 @@ public: return m[mode]; } - riscv_hart_msu_vp(feature_config cfg = feature_config{}); + riscv_hart_msu_vp(); + virtual ~riscv_hart_msu_vp() = default; void reset(uint64_t address) override; - std::pair load_file(std::string name, int type = -1) override; - phys_addr_t virt2phys(const iss::addr_t& addr) override; iss::status read(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, @@ -328,105 +292,29 @@ public: iss::status write(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, const uint8_t* const data) override; - uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, fault_data, fault_data); } + uint64_t enter_trap(uint64_t flags) override { return riscv_hart_msu_vp::enter_trap(flags, this->fault_data, this->fault_data); } uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override; uint64_t leave_trap(uint64_t flags) override; void wait_until(uint64_t flags) override; - void disass_output(uint64_t pc, const std::string instr) override { - CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, - this->reg.cycle + cycle_offset); - }; + void set_csr(unsigned addr, reg_t val) { this->csr[addr & this->csr.page_addr_mask] = val; } - iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; } - - void set_csr(unsigned addr, reg_t val) { csr[addr & csr.page_addr_mask] = val; } - - void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } - - void set_semihosting_callback(std::function& cb) { semihosting_cb = cb; }; + void set_irq_num(unsigned i) { this->mcause_max_irq = 1 << util::ilog2(i); } protected: - struct riscv_instrumentation_if : public iss::instrumentation_if { - - riscv_instrumentation_if(riscv_hart_msu_vp& arch) - : arch(arch) {} - /** - * get the name of this architecture - * - * @return the name of this architecture - */ - const std::string core_type_name() const override { return traits::core_type; } - - uint64_t get_pc() override { return arch.reg.PC; } - - uint64_t get_next_pc() override { return arch.reg.NEXT_PC; } - - uint64_t get_instr_word() override { return arch.reg.instruction; } - - uint64_t get_instr_count() override { return arch.reg.icount; } - - uint64_t get_pendig_traps() override { return arch.reg.trap_state; } - - uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; } - - void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; } - - bool is_branch_taken() override { return arch.reg.last_branch; } - - unsigned get_reg_num() override { return traits::NUM_REGS; } - - unsigned get_reg_size(unsigned num) override { return traits::reg_bit_widths[num]; } - - std::unordered_map const& get_symbol_table(std::string name) override { return arch.symbol_table; } - - riscv_hart_msu_vp& arch; - }; - - friend struct riscv_instrumentation_if; - addr_t get_pc() { return this->reg.PC; } - addr_t get_next_pc() { return this->reg.NEXT_PC; } - virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t* const data); virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t* const data); - virtual iss::status read_csr(unsigned addr, reg_t& val); - virtual iss::status write_csr(unsigned addr, reg_t val); - hart_state_type state; - int64_t cycle_offset{0}; - uint64_t mcycle_csr{0}; - int64_t instret_offset{0}; - uint64_t minstret_csr{0}; - reg_t fault_data; - std::array vm; - riscv_instrumentation_if instr_if; - - std::function semihosting_cb; using mem_type = util::sparse_array; - using csr_type = util::sparse_array::reg_t, 1ULL << 12, 12>; - using csr_page_type = typename csr_type::page_type; mem_type mem; - csr_type csr; void update_vm_info(); std::unordered_map ptw; std::unordered_map atomic_reservation; - std::unordered_map csr_rd_cb; - std::unordered_map csr_wr_cb; std::vector tcm; - iss::status read_csr_reg(unsigned addr, reg_t& val); - iss::status write_csr_reg(unsigned addr, reg_t val); - iss::status read_null(unsigned addr, reg_t& val); - iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; } - iss::status read_cycle(unsigned addr, reg_t& val); - iss::status write_cycle(unsigned addr, reg_t val); - iss::status read_instret(unsigned addr, reg_t& val); - iss::status write_instret(unsigned addr, reg_t val); - iss::status read_tvec(unsigned addr, reg_t& val); - iss::status read_time(unsigned addr, reg_t& val); iss::status read_status(unsigned addr, reg_t& val); iss::status write_status(unsigned addr, reg_t val); iss::status write_cause(unsigned addr, reg_t val); @@ -435,18 +323,14 @@ protected: iss::status read_ip(unsigned addr, reg_t& val); iss::status write_ideleg(unsigned addr, reg_t val); iss::status write_edeleg(unsigned addr, reg_t val); - iss::status read_hartid(unsigned addr, reg_t& val); - iss::status write_epc(unsigned addr, reg_t val); iss::status read_satp(unsigned addr, reg_t& val); iss::status write_satp(unsigned addr, reg_t val); - iss::status read_fcsr(unsigned addr, reg_t& val); - iss::status write_fcsr(unsigned addr, reg_t val); virtual iss::status read_custom_csr_reg(unsigned addr, reg_t& val) { return iss::status::Err; }; virtual iss::status write_custom_csr_reg(unsigned addr, reg_t val) { return iss::status::Err; }; - void register_custom_csr_rd(unsigned addr) { csr_rd_cb[addr] = &this_class::read_custom_csr_reg; } - void register_custom_csr_wr(unsigned addr) { csr_wr_cb[addr] = &this_class::write_custom_csr_reg; } + void register_custom_csr_rd(unsigned addr) { this->csr_rd_cb[addr] = MK_CSR_RD_CB(read_custom_csr_reg); } + void register_custom_csr_wr(unsigned addr) { this->csr_wr_cb[addr] = MK_CSR_WR_CB(write_custom_csr_reg); } reg_t mhartid_reg{0x0}; @@ -455,118 +339,48 @@ protected: template riscv_hart_msu_vp::riscv_hart_msu_vp() -: state() -, instr_if(*this) { - this->_has_mmu = true; - // reset values - csr[misa] = traits::MISA_VAL; - csr[mvendorid] = 0x669; - csr[marchid] = traits::MARCHID_VAL; - csr[mimpid] = 1; - - for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_csr_reg; - } - for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_csr_reg; - } - for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_csr_reg; - } - for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - } - for(unsigned addr = cycleh; addr <= hpmcounter31h; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - // csr_wr_cb[addr] = &this_class::write_csr_reg; - } +: state() { + this->mmu = true; // common regs - const std::array addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, - mtval, mscratch, sepc, stvec, sscratch, scause, stval, sscratch, - uepc, utvec, uscratch, ucause, utval, uscratch}}; - for(auto addr : addrs) { - csr_rd_cb[addr] = &this_class::read_csr_reg; - csr_wr_cb[addr] = &this_class::write_csr_reg; + const std::array rwaddrs{{mepc, mtvec, mscratch, mtval, mscratch, sepc, stvec, sscratch, scause, stval, sscratch, uepc, + utvec, uscratch, ucause, utval, uscratch}}; + for(auto addr : rwaddrs) { + this->csr_rd_cb[addr] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[addr] = MK_CSR_WR_CB(write_plain); } // special handling & overrides - csr_rd_cb[time] = &this_class::read_time; - if(traits::XLEN == 32) - csr_rd_cb[timeh] = &this_class::read_time; - csr_rd_cb[cycle] = &this_class::read_cycle; - if(traits::XLEN == 32) - csr_rd_cb[cycleh] = &this_class::read_cycle; - csr_rd_cb[instret] = &this_class::read_instret; - if(traits::XLEN == 32) - csr_rd_cb[instreth] = &this_class::read_instret; - - csr_rd_cb[mcycle] = &this_class::read_cycle; - csr_wr_cb[mcycle] = &this_class::write_cycle; - if(traits::XLEN == 32) - csr_rd_cb[mcycleh] = &this_class::read_cycle; - if(traits::XLEN == 32) - csr_wr_cb[mcycleh] = &this_class::write_cycle; - csr_rd_cb[minstret] = &this_class::read_instret; - csr_wr_cb[minstret] = &this_class::write_instret; - if(traits::XLEN == 32) - csr_rd_cb[minstreth] = &this_class::read_instret; - if(traits::XLEN == 32) - csr_wr_cb[minstreth] = &this_class::write_instret; - csr_rd_cb[mstatus] = &this_class::read_status; - csr_wr_cb[mstatus] = &this_class::write_status; - csr_wr_cb[mcause] = &this_class::write_cause; - csr_rd_cb[sstatus] = &this_class::read_status; - csr_wr_cb[sstatus] = &this_class::write_status; - csr_wr_cb[scause] = &this_class::write_cause; - csr_rd_cb[ustatus] = &this_class::read_status; - csr_wr_cb[ustatus] = &this_class::write_status; - csr_wr_cb[ucause] = &this_class::write_cause; - csr_rd_cb[mtvec] = &this_class::read_tvec; - csr_rd_cb[stvec] = &this_class::read_tvec; - csr_rd_cb[utvec] = &this_class::read_tvec; - csr_wr_cb[mepc] = &this_class::write_epc; - csr_wr_cb[sepc] = &this_class::write_epc; - csr_wr_cb[uepc] = &this_class::write_epc; - csr_rd_cb[mip] = &this_class::read_ip; - csr_wr_cb[mip] = &this_class::write_null; - csr_rd_cb[sip] = &this_class::read_ip; - csr_wr_cb[sip] = &this_class::write_null; - csr_rd_cb[uip] = &this_class::read_ip; - csr_wr_cb[uip] = &this_class::write_null; - csr_rd_cb[mie] = &this_class::read_ie; - csr_wr_cb[mie] = &this_class::write_ie; - csr_rd_cb[sie] = &this_class::read_ie; - csr_wr_cb[sie] = &this_class::write_ie; - csr_rd_cb[uie] = &this_class::read_ie; - csr_wr_cb[uie] = &this_class::write_ie; - csr_rd_cb[mhartid] = &this_class::read_hartid; - csr_rd_cb[mcounteren] = &this_class::read_null; - csr_wr_cb[mcounteren] = &this_class::write_null; - csr_wr_cb[misa] = &this_class::write_null; - csr_wr_cb[mvendorid] = &this_class::write_null; - csr_wr_cb[marchid] = &this_class::write_null; - csr_wr_cb[mimpid] = &this_class::write_null; - csr_rd_cb[satp] = &this_class::read_satp; - csr_wr_cb[satp] = &this_class::write_satp; - csr_rd_cb[fcsr] = &this_class::read_fcsr; - csr_wr_cb[fcsr] = &this_class::write_fcsr; - csr_rd_cb[fflags] = &this_class::read_fcsr; - csr_wr_cb[fflags] = &this_class::write_fcsr; - csr_rd_cb[frm] = &this_class::read_fcsr; - csr_wr_cb[frm] = &this_class::write_fcsr; -} - -template std::pair riscv_hart_msu_vp::load_file(std::string name, int type) { - if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64, - [this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status { - return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits::MEM, addr, size, - data); - })) { - return std::make_pair(entry_address, true); - } - return std::make_pair(entry_address, false); + this->csr_rd_cb[mstatus] = MK_CSR_RD_CB(read_status); + this->csr_wr_cb[mstatus] = MK_CSR_WR_CB(write_status); + this->csr_wr_cb[mcause] = MK_CSR_WR_CB(write_cause); + this->csr_rd_cb[sstatus] = MK_CSR_RD_CB(read_status); + this->csr_wr_cb[sstatus] = MK_CSR_WR_CB(write_status); + this->csr_wr_cb[scause] = MK_CSR_WR_CB(write_cause); + this->csr_rd_cb[ustatus] = MK_CSR_RD_CB(read_status); + this->csr_wr_cb[ustatus] = MK_CSR_WR_CB(write_status); + this->csr_wr_cb[ucause] = MK_CSR_WR_CB(write_cause); + this->csr_rd_cb[mtvec] = MK_CSR_RD_CB(read_tvec); + this->csr_rd_cb[stvec] = MK_CSR_RD_CB(read_tvec); + this->csr_rd_cb[utvec] = MK_CSR_RD_CB(read_tvec); + this->csr_rd_cb[mip] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_null); + this->csr_rd_cb[sip] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[sip] = MK_CSR_WR_CB(write_null); + this->csr_rd_cb[uip] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[uip] = MK_CSR_WR_CB(write_null); + this->csr_rd_cb[mie] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[mie] = MK_CSR_WR_CB(write_ie); + this->csr_rd_cb[sie] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[sie] = MK_CSR_WR_CB(write_ie); + this->csr_rd_cb[uie] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[uie] = MK_CSR_WR_CB(write_ie); + this->csr_rd_cb[mcounteren] = MK_CSR_RD_CB(read_null); + this->csr_wr_cb[mcounteren] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[misa] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[mvendorid] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[marchid] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[mimpid] = MK_CSR_WR_CB(write_null); + this->csr_rd_cb[satp] = MK_CSR_RD_CB(read_satp); + this->csr_wr_cb[satp] = MK_CSR_WR_CB(write_satp); } template @@ -584,9 +398,9 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ try { switch(space) { case traits::MEM: { - auto alignment = is_fetch(access) ? (has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); + auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { - fault_data = addr; + this->fault_data = addr; if(access && iss::access_type::DEBUG) throw trap_access(0, addr); this->reg.trap_state = (1 << 31); // issue trap 0 @@ -595,7 +409,7 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ try { if(!is_debug(access) && (addr & (alignment - 1))) { this->reg.trap_state = 1 << 31 | 4 << 16; - fault_data = addr; + this->fault_data = addr; return iss::Err; } if(unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary @@ -609,16 +423,16 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ return res; } } - auto res = read_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data); + auto res = read_mem(virt2phys(iss::addr_t{access, type, space, addr}), length, data); if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault - fault_data = addr; + this->fault_data = addr; } return res; } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } @@ -626,7 +440,7 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; - return read_csr(addr, *reinterpret_cast(data)); + return this->read_csr(addr, *reinterpret_cast(data)); } break; case traits::FENCE: { if((addr + length) > mem.size()) @@ -659,7 +473,7 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_ } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } @@ -695,13 +509,13 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access switch(space) { case traits::MEM: { if(unlikely((access && iss::access_type::FETCH) && (addr & 0x1) == 1)) { - fault_data = addr; + this->fault_data = addr; if(access && iss::access_type::DEBUG) throw trap_access(0, addr); this->reg.trap_state = (1 << 31); // issue trap 0 return iss::Err; } - phys_addr_t paddr = BASE::v2p(iss::addr_t{access, type, space, addr}); + phys_addr_t paddr = virt2phys(iss::addr_t{access, type, space, addr}); try { // TODO: There is no check for alignment if(unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary @@ -718,19 +532,19 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access auto res = write_mem(paddr, length, data); if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault) - fault_data = addr; + this->fault_data = addr; } return res; } catch(trap_access& ta) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; return iss::Err; } } break; case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; - return write_csr(addr, *reinterpret_cast(data)); + return this->write_csr(addr, *reinterpret_cast(data)); } break; case traits::FENCE: { if((addr + length) > mem.size()) @@ -759,119 +573,12 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } } -template iss::status riscv_hart_msu_vp::read_csr(unsigned addr, reg_t& val) { - if(addr >= csr.size()) - return iss::Err; - auto req_priv_lvl = (addr >> 8) & 0x3; - if(this->reg.PRIV < req_priv_lvl) // not having required privileges - throw illegal_instruction_fault(this->fault_data); - auto it = csr_rd_cb.find(addr); - if(it == csr_rd_cb.end() || !it->second) // non existent register - throw illegal_instruction_fault(this->fault_data); - return (this->*(it->second))(addr, val); -} - -template iss::status riscv_hart_msu_vp::write_csr(unsigned addr, reg_t val) { - if(addr >= csr.size()) - return iss::Err; - auto req_priv_lvl = (addr >> 8) & 0x3; - if(this->reg.PRIV < req_priv_lvl) // not having required privileges - throw illegal_instruction_fault(this->fault_data); - if((addr & 0xc00) == 0xc00) // writing to read-only region - throw illegal_instruction_fault(this->fault_data); - auto it = csr_wr_cb.find(addr); - if(it == csr_wr_cb.end() || !it->second) // non existent register - throw illegal_instruction_fault(this->fault_data); - return (this->*(it->second))(addr, val); -} - -template iss::status riscv_hart_msu_vp::read_reg(unsigned addr, reg_t& val) { - val = csr[addr]; - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::read_null(unsigned addr, reg_t& val) { - val = 0; - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::write_reg(unsigned addr, reg_t val) { - csr[addr] = val; - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::read_cycle(unsigned addr, reg_t& val) { - auto cycle_val = this->reg.cycle + cycle_offset; - if(addr == mcycle) { - val = static_cast(cycle_val); - } else if(addr == mcycleh) { - if(sizeof(typename traits::reg_t) != 4) - return iss::Err; - val = static_cast(cycle_val >> 32); - } - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::write_cycle(unsigned addr, reg_t val) { - if(sizeof(typename traits::reg_t) != 4) { - mcycle_csr = static_cast(val); - } else { - if(addr == mcycle) { - mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val; - } else { - mcycle_csr = (static_cast(val) << 32) + (mcycle_csr & 0xffffffff); - } - } - cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::read_instret(unsigned addr, reg_t& val) { - if((addr & 0xff) == (minstret & 0xff)) { - val = static_cast(this->reg.instret); - } else if((addr & 0xff) == (minstreth & 0xff)) { - val = static_cast(this->reg.instret >> 32); - } - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::write_instret(unsigned addr, reg_t val) { - if(sizeof(typename traits::reg_t) != 4) { - this->reg.instret = static_cast(val); - } else { - if((addr & 0xff) == (minstret & 0xff)) { - this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val; - } else { - this->reg.instret = (static_cast(val) << 32) + (this->reg.instret & 0xffffffff); - } - } - this->reg.instret--; - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::read_time(unsigned addr, reg_t& val) { - uint64_t time_val = this->reg.cycle / (100000000 / 32768 - 1); //-> ~3052; - if(addr == time) { - val = static_cast(time_val); - } else if(addr == timeh) { - if(sizeof(typename traits::reg_t) != 4) - return iss::Err; - val = static_cast(time_val >> 32); - } - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::read_tvec(unsigned addr, reg_t& val) { - val = csr[addr] & ~2; - return iss::Ok; -} - template iss::status riscv_hart_msu_vp::read_status(unsigned addr, reg_t& val) { auto req_priv_lvl = (addr >> 8) & 0x3; val = state.mstatus & hart_state_type::get_mask(req_priv_lvl); @@ -887,43 +594,33 @@ template iss::status riscv_hart_msu_vp::write_status(unsig } template iss::status riscv_hart_msu_vp::write_cause(unsigned addr, reg_t val) { - csr[addr] = val & ((1UL << (traits::XLEN - 1)) | 0xf); // TODO: make exception code size configurable + this->csr[addr] = val & ((1UL << (traits::XLEN - 1)) | 0xf); // TODO: make exception code size configurable return iss::Ok; } template iss::status riscv_hart_msu_vp::read_ie(unsigned addr, reg_t& val) { - val = csr[mie]; + val = this->csr[mie]; if(addr < mie) - val &= csr[mideleg]; + val &= this->csr[mideleg]; if(addr < sie) - val &= csr[sideleg]; - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::read_hartid(unsigned addr, reg_t& val) { - val = mhartid_reg; + val &= this->csr[sideleg]; return iss::Ok; } template iss::status riscv_hart_msu_vp::write_ie(unsigned addr, reg_t val) { auto req_priv_lvl = (addr >> 8) & 0x3; auto mask = get_irq_mask(req_priv_lvl); - csr[mie] = (csr[mie] & ~mask) | (val & mask); + this->csr[mie] = (this->csr[mie] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } template iss::status riscv_hart_msu_vp::read_ip(unsigned addr, reg_t& val) { - val = csr[mip]; + val = this->csr[mip]; if(addr < mip) - val &= csr[mideleg]; + val &= this->csr[mideleg]; if(addr < sip) - val &= csr[sideleg]; - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::write_epc(unsigned addr, reg_t val) { - csr[addr] = val & get_pc_mask(); + val &= this->csr[sideleg]; return iss::Ok; } @@ -949,40 +646,6 @@ template iss::status riscv_hart_msu_vp::write_satp(unsigne update_vm_info(); return iss::Ok; } -template iss::status riscv_hart_msu_vp::read_fcsr(unsigned addr, reg_t& val) { - switch(addr) { - case 1: // fflags, 4:0 - val = bit_sub<0, 5>(this->get_fcsr()); - break; - case 2: // frm, 7:5 - val = bit_sub<5, 3>(this->get_fcsr()); - break; - case 3: // fcsr - val = this->get_fcsr(); - break; - default: - return iss::Err; - } - return iss::Ok; -} - -template iss::status riscv_hart_msu_vp::write_fcsr(unsigned addr, reg_t val) { - switch(addr) { - case 1: // fflags, 4:0 - this->set_fcsr((this->get_fcsr() & 0xffffffe0) | (val & 0x1f)); - break; - case 2: // frm, 7:5 - this->set_fcsr((this->get_fcsr() & 0xffffff1f) | ((val & 0x7) << 5)); - break; - case 3: // fcsr - this->set_fcsr(val & 0xff); - break; - default: - return iss::Err; - } - return iss::Ok; -} - template iss::status riscv_hart_msu_vp::read_mem(phys_addr_t paddr, unsigned length, uint8_t* const data) { switch(paddr.val) { default: { @@ -1000,14 +663,16 @@ template iss::status riscv_hart_msu_vp::write_mem(phys_add // tohost handling in case of riscv-test // according to https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754: if(paddr.access && iss::access_type::FUNC) { - if(paddr.val == tohost) { + if(paddr.val == this->tohost) { reg_t cur_data = *reinterpret_cast(data); // Extract Device (bits 63:56) - uint8_t device = traits::XLEN == 32 ? *reinterpret_cast(p.data() + ((tohost + 4) & mem.page_addr_mask)) >> 24 - : (cur_data >> 56) & 0xFF; + uint8_t device = traits::XLEN == 32 + ? *reinterpret_cast(p.data() + ((this->tohost + 4) & mem.page_addr_mask)) >> 24 + : (cur_data >> 56) & 0xFF; // Extract Command (bits 55:48) - uint8_t command = traits::XLEN == 32 ? *reinterpret_cast(p.data() + ((tohost + 4) & mem.page_addr_mask)) >> 16 - : (cur_data >> 48) & 0xFF; + uint8_t command = traits::XLEN == 32 + ? *reinterpret_cast(p.data() + ((this->tohost + 4) & mem.page_addr_mask)) >> 16 + : (cur_data >> 48) & 0xFF; // Extract payload (bits 47:0) uint64_t payload_addr = cur_data & 0xFFFFFFFFFFFFULL; if(payload_addr & 1) { @@ -1023,7 +688,7 @@ template iss::status riscv_hart_msu_vp::write_mem(phys_add CPPLOG(ERR) << "Syscall read went wrong"; uint64_t syscall_num = loaded_payload.at(0); if(syscall_num == 64) { // SYS_WRITE - return execute_sys_write(this, loaded_payload, traits::MEM); + return this->execute_sys_write(this, loaded_payload, traits::MEM); } else { CPPLOG(ERR) << "tohost syscall with number 0x" << std::hex << syscall_num << std::dec << " (" << syscall_num << ") not implemented"; @@ -1038,9 +703,9 @@ template iss::status riscv_hart_msu_vp::write_mem(phys_add return iss::Ok; } } - if((traits::XLEN == 32 && paddr.val == fromhost + 4) || (traits::XLEN == 64 && paddr.val == fromhost)) { - uint64_t fhostvar = *reinterpret_cast(p.data() + (fromhost & mem.page_addr_mask)); - *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; + if((traits::XLEN == 32 && paddr.val == this->fromhost + 4) || (traits::XLEN == 64 && paddr.val == this->fromhost)) { + uint64_t fhostvar = *reinterpret_cast(p.data() + (this->fromhost & mem.page_addr_mask)); + *reinterpret_cast(p.data() + (this->tohost & mem.page_addr_mask)) = fhostvar; } } return iss::Ok; @@ -1053,21 +718,21 @@ template inline void riscv_hart_msu_vp::reset(uint64_t add } template inline void riscv_hart_msu_vp::update_vm_info() { - vm[1] = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp); - BASE::addr_mode[3] = BASE::addr_mode[2] = vm[1].is_active() ? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; + this->vm[1] = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp); + BASE::addr_mode[3] = BASE::addr_mode[2] = this->vm[1].is_active() ? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; if(state.mstatus.MPRV) - vm[0] = hart_state_type::decode_vm_info(state.mstatus.MPP, state.satp); + this->vm[0] = hart_state_type::decode_vm_info(state.mstatus.MPP, state.satp); else - vm[0] = vm[1]; - BASE::addr_mode[1] = BASE::addr_mode[0] = vm[0].is_active() ? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; + this->vm[0] = this->vm[1]; + BASE::addr_mode[1] = BASE::addr_mode[0] = this->vm[0].is_active() ? iss::address_type::VIRTUAL : iss::address_type::PHYSICAL; ptw.clear(); } template void riscv_hart_msu_vp::check_interrupt() { auto status = state.mstatus; - auto ip = csr[mip]; - auto ie = csr[mie]; - auto ideleg = csr[mideleg]; + auto ip = this->csr[mip]; + auto ie = this->csr[mie]; + auto ideleg = this->csr[mideleg]; // Multiple simultaneous interrupts and traps at the same privilege level are // handled in the following decreasing priority order: // external interrupts, software interrupts, timer interrupts, then finally @@ -1144,7 +809,7 @@ template typename riscv_hart_msu_vp::phys_addr_t riscv_har break; } else if(!(pte & PTE_V) || (!(pte & PTE_R) && (pte & PTE_W))) { break; - } else if(type == (iss::access_type::FETCH ? !(pte & PTE_X) + } else if(type == (type == iss::access_type::FETCH ? !(pte & PTE_X) : type == iss::access_type::READ ? !(pte & PTE_R) && !(mxr && (pte & PTE_X)) : !((pte & PTE_R) && (pte & PTE_W)))) { break; @@ -1197,10 +862,10 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f // calculate effective privilege level auto new_priv = PRIV_M; if(trap_id == 0) { // exception - if(cur_priv != PRIV_M && ((csr[medeleg] >> cause) & 0x1) != 0) - new_priv = (csr[sedeleg] >> cause) & 0x1 ? PRIV_U : PRIV_S; + if(cur_priv != PRIV_M && ((this->csr[medeleg] >> cause) & 0x1) != 0) + new_priv = (this->csr[sedeleg] >> cause) & 0x1 ? PRIV_U : PRIV_S; // store ret addr in xepc register - csr[uepc | (new_priv << 8)] = static_cast(addr); // store actual address instruction of exception + this->csr[uepc | (new_priv << 8)] = static_cast(addr); // store actual address instruction of exception /* * write mtval if new_priv=M_MODE, spec says: * When a hardware breakpoint is triggered, or an instruction-fetch, load, @@ -1210,17 +875,17 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f */ switch(cause) { case 0: - csr[utval | (new_priv << 8)] = static_cast(addr); + this->csr[utval | (new_priv << 8)] = static_cast(addr); break; case 2: - csr[utval | (new_priv << 8)] = (instr & 0x3) == 3 ? instr : instr & 0xffff; + this->csr[utval | (new_priv << 8)] = (instr & 0x3) == 3 ? instr : instr & 0xffff; break; case 3: // TODO: implement debug mode behavior // csr[dpc] = addr; // csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1<<6) | PRIV_M; //FIXME: cause should not be 4 (stepi) - csr[utval | (new_priv << 8)] = addr; - if(semihosting_cb) { + this->csr[utval | (new_priv << 8)] = addr; + if(this->semihosting_cb) { // Check for semihosting call phys_addr_t p_addr(access_type::DEBUG_READ, traits::MEM, addr - 4); std::array data; @@ -1241,7 +906,7 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f #endif CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred "; - semihosting_callback(this, this->reg.X10 /*a0*/, this->reg.X11 /*a1*/); + this->semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); return this->reg.NEXT_PC; } } @@ -1249,20 +914,20 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f case 4: case 6: case 7: - csr[utval | (new_priv << 8)] = fault_data; + this->csr[utval | (new_priv << 8)] = this->fault_data; break; default: - csr[utval | (new_priv << 8)] = 0; + this->csr[utval | (new_priv << 8)] = 0; } - fault_data = 0; + this->fault_data = 0; } else { - if(cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) - new_priv = (csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S; - csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt + if(cur_priv != PRIV_M && ((this->csr[mideleg] >> cause) & 0x1) != 0) + new_priv = (this->csr[sideleg] >> cause) & 0x1 ? PRIV_U : PRIV_S; + this->csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt this->reg.pending_trap = 0; } size_t adr = ucause | (new_priv << 8); - csr[adr] = (trap_id << (traits::XLEN - 1)) + cause; + this->csr[adr] = (trap_id << (traits::XLEN - 1)) + cause; // update mstatus // xPP field of mstatus is written with the active privilege mode at the time // of the trap; the x PIE field of mstatus @@ -1290,7 +955,7 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f } // get trap vector - auto ivec = csr[utvec | (new_priv << 8)]; + auto ivec = this->csr[utvec | (new_priv << 8)]; // calculate addr// set NEXT_PC to trap addressess to jump to based on MODE // bits in mtvec this->reg.NEXT_PC = ivec & ~0x3UL; @@ -1299,10 +964,10 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f std::array buffer; sprintf(buffer.data(), "0x%016lx", addr); if((flags & 0xffffffff) != 0xffffffff) - CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" - << cause << ")" - << " at address " << buffer.data() << " occurred, changing privilege level from " << lvl[cur_priv] << " to " - << lvl[new_priv]; + CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" + << (trap_id ? this->irq_str[cause] : this->trap_str[cause]) << "' (" << cause << ")" + << " at address " << buffer.data() << " occurred, changing privilege level from " << this->lvl[cur_priv] + << " to " << this->lvl[new_priv]; // reset trap state this->reg.PRIV = new_priv; this->reg.trap_state = 0; @@ -1344,8 +1009,8 @@ template uint64_t riscv_hart_msu_vp::leave_trap(uint64_t f break; } // sets the pc to the value stored in the x epc register. - this->reg.NEXT_PC = csr[uepc | inst_priv << 8]; - CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to " << lvl[this->reg.PRIV]; + this->reg.NEXT_PC = this->csr[uepc | inst_priv << 8]; + CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << this->lvl[cur_priv] << " to " << this->lvl[this->reg.PRIV]; update_vm_info(); check_interrupt(); return this->reg.NEXT_PC; diff --git a/src/iss/arch/riscv_hart_mu_p.h b/src/iss/arch/riscv_hart_mu_p.h index e70e27f..151bfdc 100644 --- a/src/iss/arch/riscv_hart_mu_p.h +++ b/src/iss/arch/riscv_hart_mu_p.h @@ -35,9 +35,7 @@ #ifndef _RISCV_HART_MU_P_H #define _RISCV_HART_MU_P_H -#include "iss/arch/traits.h" #include "iss/instrumentation_if.h" -#include "iss/log_categories.h" #include "iss/vm_if.h" #include "iss/vm_types.h" #include "riscv_hart_common.h" @@ -59,54 +57,20 @@ #include #include #include -#include -#include - -#include namespace iss { namespace arch { template -class riscv_hart_mu_p : public BASE, public riscv_hart_common { -protected: - const std::array lvl = {{'U', 'S', 'H', 'M'}}; - const std::array trap_str = {{"" - "Instruction address misaligned", // 0 - "Instruction access fault", // 1 - "Illegal instruction", // 2 - "Breakpoint", // 3 - "Load address misaligned", // 4 - "Load access fault", // 5 - "Store/AMO address misaligned", // 6 - "Store/AMO access fault", // 7 - "Environment call from U-mode", // 8 - "Environment call from S-mode", // 9 - "Reserved", // a - "Environment call from M-mode", // b - "Instruction page fault", // c - "Load page fault", // d - "Reserved", // e - "Store/AMO page fault"}}; - const std::array irq_str = {{"User software interrupt", "Supervisor software interrupt", "Reserved", - "Machine software interrupt", "User timer interrupt", "Supervisor timer interrupt", - "Reserved", "Machine timer interrupt", "User external interrupt", - "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; - +class riscv_hart_mu_p : public riscv_hart_common { public: using core = BASE; + using base = riscv_hart_common; using this_class = riscv_hart_mu_p; using phys_addr_t = typename core::phys_addr_t; using reg_t = typename core::reg_t; using addr_t = typename core::addr_t; - using rd_csr_f = iss::status (this_class::*)(unsigned addr, reg_t&); - using wr_csr_f = iss::status (this_class::*)(unsigned addr, reg_t); - using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t* const); - using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const* const); - - constexpr static unsigned MEM = traits::MEM; - // primary template template struct hart_state {}; // specialization 32bit @@ -287,109 +251,41 @@ public: return m[mode]; } - constexpr bool has_compressed() { return traits::MISA_VAL & 0b0100; } - constexpr reg_t get_pc_mask() { return has_compressed() ? ~1 : ~3; } - riscv_hart_mu_p(feature_config cfg = feature_config{}); virtual ~riscv_hart_mu_p() = default; void reset(uint64_t address) override; - std::pair load_file(std::string name, int type = -1) override; - iss::status read(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, uint8_t* const data) override; iss::status write(const address_type type, const access_type access, const uint32_t space, const uint64_t addr, const unsigned length, const uint8_t* const data) override; - uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, fault_data, fault_data); } + uint64_t enter_trap(uint64_t flags) override { return riscv_hart_mu_p::enter_trap(flags, this->fault_data, this->fault_data); } uint64_t enter_trap(uint64_t flags, uint64_t addr, uint64_t instr) override; uint64_t leave_trap(uint64_t flags) override; - const reg_t& get_mhartid() const { return mhartid_reg; } - void set_mhartid(reg_t mhartid) { mhartid_reg = mhartid; }; - - void disass_output(uint64_t pc, const std::string instr) override { - NSCLOG(INFO, LOGCAT) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]", pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, - this->reg.cycle + cycle_offset); - }; - - iss::instrumentation_if* get_instrumentation_if() override { return &instr_if; } - - void set_csr(unsigned addr, reg_t val) { csr[addr & csr.page_addr_mask] = val; } + void set_csr(unsigned addr, reg_t val) { this->csr[addr & this->csr.page_addr_mask] = val; } void set_irq_num(unsigned i) { mcause_max_irq = 1 << util::ilog2(i); } - void set_semihosting_callback(semihosting_cb_t cb) { semihosting_cb = cb; }; - protected: - struct riscv_instrumentation_if : public iss::instrumentation_if { - - riscv_instrumentation_if(riscv_hart_mu_p& arch) - : arch(arch) {} - /** - * get the name of this architecture - * - * @return the name of this architecture - */ - const std::string core_type_name() const override { return traits::core_type; } - - uint64_t get_pc() override { return arch.reg.PC; } - - uint64_t get_next_pc() override { return arch.reg.NEXT_PC; } - - uint64_t get_instr_word() override { return arch.reg.instruction; } - - uint64_t get_instr_count() override { return arch.reg.icount; } - - uint64_t get_pendig_traps() override { return arch.reg.trap_state; } - - uint64_t get_total_cycles() override { return arch.reg.cycle + arch.cycle_offset; } - - void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; } - - bool is_branch_taken() override { return arch.reg.last_branch; } - - unsigned get_reg_num() override { return traits::NUM_REGS; } - - unsigned get_reg_size(unsigned num) override { return traits::reg_bit_widths[num]; } - - std::unordered_map const& get_symbol_table(std::string name) override { return arch.symbol_table; } - - riscv_hart_mu_p& arch; - }; - - friend struct riscv_instrumentation_if; - virtual iss::status read_mem(phys_addr_t addr, unsigned length, uint8_t* const data); virtual iss::status write_mem(phys_addr_t addr, unsigned length, const uint8_t* const data); iss::status read_clic(uint64_t addr, unsigned length, uint8_t* const data); iss::status write_clic(uint64_t addr, unsigned length, const uint8_t* const data); - virtual iss::status read_csr(unsigned addr, reg_t& val); - virtual iss::status write_csr(unsigned addr, reg_t val); + using mem_read_f = iss::status(phys_addr_t addr, unsigned, uint8_t* const); + using mem_write_f = iss::status(phys_addr_t addr, unsigned, uint8_t const* const); hart_state_type state; - int64_t cycle_offset{0}; - uint64_t mcycle_csr{0}; - int64_t instret_offset{0}; - uint64_t minstret_csr{0}; - reg_t fault_data; - riscv_instrumentation_if instr_if; - - semihosting_cb_t semihosting_cb; using mem_type = util::sparse_array; - using csr_type = util::sparse_array::reg_t, 1ULL << 12, 12>; - using csr_page_type = typename csr_type::page_type; mem_type mem; - csr_type csr; std::unordered_map ptw; std::unordered_map atomic_reservation; - std::unordered_map csr_rd_cb; - std::unordered_map csr_wr_cb; uint8_t clic_cfg_reg{0}; std::array clic_inttrig_reg; union clic_int_reg_t { @@ -407,16 +303,6 @@ protected: std::vector tcm; - iss::status read_plain(unsigned addr, reg_t& val); - iss::status write_plain(unsigned addr, reg_t val); - iss::status read_null(unsigned addr, reg_t& val); - iss::status write_null(unsigned addr, reg_t val) { return iss::status::Ok; } - iss::status read_cycle(unsigned addr, reg_t& val); - iss::status write_cycle(unsigned addr, reg_t val); - iss::status read_instret(unsigned addr, reg_t& val); - iss::status write_instret(unsigned addr, reg_t val); - iss::status read_tvec(unsigned addr, reg_t& val); - iss::status read_time(unsigned addr, reg_t& val); iss::status read_status(unsigned addr, reg_t& val); iss::status write_status(unsigned addr, reg_t val); iss::status read_cause(unsigned addr, reg_t& val); @@ -424,10 +310,6 @@ protected: iss::status read_ie(unsigned addr, reg_t& val); iss::status write_ie(unsigned addr, reg_t val); iss::status read_ip(unsigned addr, reg_t& val); - iss::status write_ideleg(unsigned addr, reg_t val); - iss::status write_edeleg(unsigned addr, reg_t val); - iss::status read_hartid(unsigned addr, reg_t& val); - iss::status write_epc(unsigned addr, reg_t val); iss::status read_intstatus(unsigned addr, reg_t& val); iss::status write_intthresh(unsigned addr, reg_t val); iss::status write_xtvt(unsigned addr, reg_t val); @@ -436,18 +318,10 @@ protected: iss::status write_dscratch(unsigned addr, reg_t val); iss::status read_dpc(unsigned addr, reg_t& val); iss::status write_dpc(unsigned addr, reg_t val); - iss::status read_fcsr(unsigned addr, reg_t& val); - iss::status write_fcsr(unsigned addr, reg_t val); + iss::status write_ideleg(unsigned addr, reg_t val); + iss::status write_edeleg(unsigned addr, reg_t val); iss::status write_pmpcfg(unsigned addr, reg_t val); - virtual iss::status read_custom_csr(unsigned addr, reg_t& val) { return iss::status::Err; }; - virtual iss::status write_custom_csr(unsigned addr, reg_t val) { return iss::status::Err; }; - - void register_custom_csr_rd(unsigned addr) { csr_rd_cb[addr] = &this_class::read_custom_csr_reg; } - void register_custom_csr_wr(unsigned addr) { csr_wr_cb[addr] = &this_class::write_custom_csr_reg; } - - reg_t mhartid_reg{0x0}; - void check_interrupt(); bool pmp_check(const access_type type, const uint64_t addr, const unsigned len); std::vector> memfn_range; @@ -456,7 +330,6 @@ protected: void insert_mem_range(uint64_t, uint64_t, std::function, std::function); feature_config cfg; unsigned mcause_max_irq{(FEAT & features_e::FEAT_CLIC) ? std::max(16U, static_cast(traits::CLIC_NUM_IRQ)) : 16U}; - inline bool debug_mode_active() { return this->reg.PRIV & 0x4; } std::pair, std::function> replace_mem_access(std::function rd, std::function wr) { @@ -472,44 +345,7 @@ protected: template riscv_hart_mu_p::riscv_hart_mu_p(feature_config cfg) : state() -, instr_if(*this) , cfg(cfg) { - // reset values - csr[misa] = traits::MISA_VAL; - csr[mvendorid] = 0x669; - csr[marchid] = traits::MARCHID_VAL; - csr[mimpid] = 1; - - if(traits::FLEN > 0) { - csr_rd_cb[fcsr] = &this_class::read_fcsr; - csr_wr_cb[fcsr] = &this_class::write_fcsr; - } - for(unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_plain; - } - if(traits::XLEN == 32) - for(unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_plain; - } - for(unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - csr_wr_cb[addr] = &this_class::write_plain; - } - for(unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - } - if(traits::XLEN == 32) - for(unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr) { - csr_rd_cb[addr] = &this_class::read_null; - } - // common regs - const std::array roaddrs{{misa, mvendorid, marchid, mimpid}}; - for(auto addr : roaddrs) { - csr_rd_cb[addr] = &this_class::read_plain; - csr_wr_cb[addr] = &this_class::write_null; - } const std::array rwaddrs{{ mepc, mtvec, @@ -521,103 +357,79 @@ riscv_hart_mu_p::riscv_hart_mu_p(feature_config cfg) utval, }}; for(auto addr : rwaddrs) { - csr_rd_cb[addr] = &this_class::read_plain; - csr_wr_cb[addr] = &this_class::write_plain; + this->csr_rd_cb[addr] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[addr] = MK_CSR_WR_CB(write_plain); } - // special handling & overrides - csr_rd_cb[time] = &this_class::read_time; - if(traits::XLEN == 32) - csr_rd_cb[timeh] = &this_class::read_time; - csr_rd_cb[cycle] = &this_class::read_cycle; - if(traits::XLEN == 32) - csr_rd_cb[cycleh] = &this_class::read_cycle; - csr_rd_cb[instret] = &this_class::read_instret; - if(traits::XLEN == 32) - csr_rd_cb[instreth] = &this_class::read_instret; - - csr_rd_cb[mcycle] = &this_class::read_cycle; - csr_wr_cb[mcycle] = &this_class::write_cycle; - if(traits::XLEN == 32) - csr_rd_cb[mcycleh] = &this_class::read_cycle; - if(traits::XLEN == 32) - csr_wr_cb[mcycleh] = &this_class::write_cycle; - csr_rd_cb[minstret] = &this_class::read_instret; - csr_wr_cb[minstret] = &this_class::write_instret; - if(traits::XLEN == 32) - csr_rd_cb[minstreth] = &this_class::read_instret; - if(traits::XLEN == 32) - csr_wr_cb[minstreth] = &this_class::write_instret; - csr_rd_cb[mstatus] = &this_class::read_status; - csr_wr_cb[mstatus] = &this_class::write_status; - csr_rd_cb[mcause] = &this_class::read_cause; - csr_wr_cb[mcause] = &this_class::write_cause; - csr_rd_cb[mtvec] = &this_class::read_tvec; - csr_wr_cb[mepc] = &this_class::write_epc; - csr_rd_cb[mip] = &this_class::read_ip; - csr_wr_cb[mip] = &this_class::write_null; - csr_rd_cb[mie] = &this_class::read_ie; - csr_wr_cb[mie] = &this_class::write_ie; - csr_rd_cb[mhartid] = &this_class::read_hartid; - csr_rd_cb[mcounteren] = &this_class::read_null; - csr_wr_cb[mcounteren] = &this_class::write_null; - csr_wr_cb[misa] = &this_class::write_null; - csr_wr_cb[mvendorid] = &this_class::write_null; - csr_wr_cb[marchid] = &this_class::write_null; - csr_wr_cb[mimpid] = &this_class::write_null; + this->csr_rd_cb[mstatus] = MK_CSR_RD_CB(read_status); + this->csr_wr_cb[mstatus] = MK_CSR_WR_CB(write_status); + this->csr_rd_cb[mcause] = MK_CSR_RD_CB(read_cause); + this->csr_wr_cb[mcause] = MK_CSR_WR_CB(write_cause); + this->csr_rd_cb[mtvec] = MK_CSR_RD_CB(read_tvec); + this->csr_wr_cb[mepc] = MK_CSR_WR_CB(write_epc); + this->csr_rd_cb[mip] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[mip] = MK_CSR_WR_CB(write_null); + this->csr_rd_cb[mie] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[mie] = MK_CSR_WR_CB(write_ie); + this->csr_rd_cb[mcounteren] = MK_CSR_RD_CB(read_null); + this->csr_wr_cb[mcounteren] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[misa] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[mvendorid] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[marchid] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[mimpid] = MK_CSR_WR_CB(write_null); if(FEAT & FEAT_PMP) { for(size_t i = pmpaddr0; i <= pmpaddr15; ++i) { - csr_rd_cb[i] = &this_class::read_plain; - csr_wr_cb[i] = &this_class::write_plain; + this->csr_rd_cb[i] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[i] = MK_CSR_WR_CB(write_plain); } for(size_t i = pmpcfg0; i < pmpcfg0 + 16 / sizeof(reg_t); ++i) { - csr_rd_cb[i] = &this_class::read_plain; - csr_wr_cb[i] = &this_class::write_pmpcfg; + this->csr_rd_cb[i] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[i] = MK_CSR_WR_CB(write_pmpcfg); } } if(FEAT & FEAT_EXT_N) { - csr_rd_cb[mideleg] = &this_class::read_plain; - csr_wr_cb[mideleg] = &this_class::write_ideleg; - csr_rd_cb[medeleg] = &this_class::read_plain; - csr_wr_cb[medeleg] = &this_class::write_edeleg; - csr_rd_cb[uie] = &this_class::read_ie; - csr_wr_cb[uie] = &this_class::write_ie; - csr_rd_cb[uip] = &this_class::read_ip; - csr_wr_cb[uip] = &this_class::write_null; - csr_wr_cb[uepc] = &this_class::write_epc; - csr_rd_cb[ustatus] = &this_class::read_status; - csr_wr_cb[ustatus] = &this_class::write_status; - csr_rd_cb[ucause] = &this_class::read_cause; - csr_wr_cb[ucause] = &this_class::write_cause; - csr_rd_cb[utvec] = &this_class::read_tvec; + this->csr_rd_cb[mideleg] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[mideleg] = MK_CSR_WR_CB(write_ideleg); + this->csr_rd_cb[medeleg] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[medeleg] = MK_CSR_WR_CB(write_edeleg); + this->csr_rd_cb[uie] = MK_CSR_RD_CB(read_ie); + this->csr_wr_cb[uie] = MK_CSR_WR_CB(write_ie); + this->csr_rd_cb[uip] = MK_CSR_RD_CB(read_ip); + this->csr_wr_cb[uip] = MK_CSR_WR_CB(write_null); + this->csr_wr_cb[uepc] = MK_CSR_WR_CB(write_epc); + this->csr_rd_cb[ustatus] = MK_CSR_RD_CB(read_status); + this->csr_wr_cb[ustatus] = MK_CSR_WR_CB(write_status); + this->csr_rd_cb[ucause] = MK_CSR_RD_CB(read_cause); + this->csr_wr_cb[ucause] = MK_CSR_WR_CB(write_cause); + this->csr_rd_cb[utvec] = MK_CSR_RD_CB(read_tvec); } if(FEAT & FEAT_CLIC) { - csr_rd_cb[mtvt] = &this_class::read_plain; - csr_wr_cb[mtvt] = &this_class::write_xtvt; - // csr_rd_cb[mxnti] = &this_class::read_csr_reg; - // csr_wr_cb[mxnti] = &this_class::write_csr_reg; - csr_rd_cb[mintstatus] = &this_class::read_intstatus; - csr_wr_cb[mintstatus] = &this_class::write_null; - // csr_rd_cb[mscratchcsw] = &this_class::read_csr_reg; - // csr_wr_cb[mscratchcsw] = &this_class::write_csr_reg; - // csr_rd_cb[mscratchcswl] = &this_class::read_csr_reg; - // csr_wr_cb[mscratchcswl] = &this_class::write_csr_reg; - csr_rd_cb[mintthresh] = &this_class::read_plain; - csr_wr_cb[mintthresh] = &this_class::write_intthresh; + this->csr_rd_cb[mtvt] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[mtvt] = MK_CSR_WR_CB(write_xtvt); + // this->csr_rd_cb[mxnti] = MK_CSR_RD_CB(read_plain(a,r);}; + // this->csr_wr_cb[mxnti] = MK_CSR_WR_CB(write_plain(a,r);}; + this->csr_rd_cb[mintstatus] = MK_CSR_RD_CB(read_intstatus); + this->csr_wr_cb[mintstatus] = MK_CSR_WR_CB(write_null); + // this->csr_rd_cb[mscratchcsw] = MK_CSR_RD_CB(read_plain(a,r);}; + // this->csr_wr_cb[mscratchcsw] = MK_CSR_WR_CB(write_plain(a,r);}; + // this->csr_rd_cb[mscratchcswl] = MK_CSR_RD_CB(read_plain(a,r);}; + // this->csr_wr_cb[mscratchcswl] = MK_CSR_WR_CB(write_plain(a,r);}; + this->csr_rd_cb[mintthresh] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[mintthresh] = MK_CSR_WR_CB(write_intthresh); if(FEAT & FEAT_EXT_N) { - csr_rd_cb[utvt] = &this_class::read_plain; - csr_wr_cb[utvt] = &this_class::write_xtvt; - csr_rd_cb[uintstatus] = &this_class::read_intstatus; - csr_wr_cb[uintstatus] = &this_class::write_null; - csr_rd_cb[uintthresh] = &this_class::read_plain; - csr_wr_cb[uintthresh] = &this_class::write_intthresh; + this->csr_rd_cb[utvt] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[utvt] = MK_CSR_WR_CB(write_xtvt); + this->csr_rd_cb[uintstatus] = MK_CSR_RD_CB(read_intstatus); + this->csr_wr_cb[uintstatus] = MK_CSR_WR_CB(write_null); + this->csr_rd_cb[uintthresh] = MK_CSR_RD_CB(read_plain); + this->csr_wr_cb[uintthresh] = MK_CSR_WR_CB(write_intthresh); } clic_int_reg.resize(cfg.clic_num_irq, clic_int_reg_t{.raw = 0}); clic_cfg_reg = 0x30; clic_mact_lvl = clic_mprev_lvl = (1 << (cfg.clic_int_ctl_bits)) - 1; clic_uact_lvl = clic_uprev_lvl = (1 << (cfg.clic_int_ctl_bits)) - 1; - csr[mintthresh] = (1 << (cfg.clic_int_ctl_bits)) - 1; - csr[uintthresh] = (1 << (cfg.clic_int_ctl_bits)) - 1; + this->csr[mintthresh] = (1 << (cfg.clic_int_ctl_bits)) - 1; + this->csr[uintthresh] = (1 << (cfg.clic_int_ctl_bits)) - 1; insert_mem_range( cfg.clic_base, 0x5000UL, [this](phys_addr_t addr, unsigned length, uint8_t* const data) { return read_clic(addr.val, length, data); }, @@ -638,31 +450,19 @@ riscv_hart_mu_p::riscv_hart_mu_p(feature_config cfg) insert_mem_range(cfg.tcm_base, cfg.tcm_size, read_clic_cb, write_clic_cb); } if(FEAT & FEAT_DEBUG) { - csr_wr_cb[dscratch0] = &this_class::write_dscratch; - csr_rd_cb[dscratch0] = &this_class::read_debug; - csr_wr_cb[dscratch1] = &this_class::write_dscratch; - csr_rd_cb[dscratch1] = &this_class::read_debug; - csr_wr_cb[dpc] = &this_class::write_dpc; - csr_rd_cb[dpc] = &this_class::read_dpc; - csr_wr_cb[dcsr] = &this_class::write_dcsr; - csr_rd_cb[dcsr] = &this_class::read_debug; + this->csr_wr_cb[dscratch0] = MK_CSR_WR_CB(write_dscratch); + this->csr_rd_cb[dscratch0] = MK_CSR_RD_CB(read_debug); + this->csr_wr_cb[dscratch1] = MK_CSR_WR_CB(write_dscratch); + this->csr_rd_cb[dscratch1] = MK_CSR_RD_CB(read_debug); + this->csr_wr_cb[dpc] = MK_CSR_WR_CB(write_dpc); + this->csr_rd_cb[dpc] = MK_CSR_RD_CB(read_dpc); + this->csr_wr_cb[dcsr] = MK_CSR_WR_CB(write_dcsr); + this->csr_rd_cb[dcsr] = MK_CSR_RD_CB(read_debug); } hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return this->read_mem(a, l, d); }; hart_mem_wr_delegate = [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { return this->write_mem(a, l, d); }; } -template -std::pair riscv_hart_mu_p::load_file(std::string name, int type) { - if(read_elf_file(name, sizeof(reg_t) == 4 ? ELFIO::ELFCLASS32 : ELFIO::ELFCLASS64, - [this](uint64_t addr, uint64_t size, const uint8_t* const data) -> iss::status { - return this->write(iss::address_type::PHYSICAL, iss::access_type::DEBUG_WRITE, traits::MEM, addr, size, - data); - })) { - return std::make_pair(entry_address, true); - } - return std::make_pair(entry_address, false); -} - template inline void riscv_hart_mu_p::insert_mem_range(uint64_t base, uint64_t size, std::function rd_f, std::function wr_fn) { @@ -678,7 +478,7 @@ inline void riscv_hart_mu_p::insert_mem_range(uint64_t base, template inline iss::status riscv_hart_mu_p::write_pmpcfg(unsigned addr, reg_t val) { - csr[addr] = val & 0x9f9f9f9f; + this->csr[addr] = val & 0x9f9f9f9f; return iss::Ok; } @@ -697,15 +497,15 @@ bool riscv_hart_mu_p::pmp_check(const access_type type, cons auto any_active = false; auto const cfg_reg_size = sizeof(reg_t); for(size_t i = 0; i < 16; i++) { - reg_t tor = csr[pmpaddr0 + i] << PMP_SHIFT; - uint8_t cfg = csr[pmpcfg0 + (i / cfg_reg_size)] >> (i % cfg_reg_size); + reg_t tor = this->csr[pmpaddr0 + i] << PMP_SHIFT; + uint8_t cfg = this->csr[pmpcfg0 + (i / cfg_reg_size)] >> (i % cfg_reg_size); if(cfg & PMP_A) { any_active = true; auto pmp_a = (cfg & PMP_A) >> 3; auto is_tor = pmp_a == PMP_TOR; auto is_na4 = pmp_a == PMP_NA4; - reg_t mask = (csr[pmpaddr0 + i] << 1) | (!is_na4); + reg_t mask = (this->csr[pmpaddr0 + i] << 1) | (!is_na4); mask = ~(mask & ~(mask + 1)) << PMP_SHIFT; // Check each 4-byte sector of the access @@ -780,16 +580,16 @@ iss::status riscv_hart_mu_p::read(const address_type type, c case traits::MEM: { if(FEAT & FEAT_PMP) { if(!pmp_check(access, addr, length) && !is_debug(access)) { - fault_data = addr; + this->fault_data = addr; if(is_debug(access)) throw trap_access(0, addr); this->reg.trap_state = (1UL << 31) | ((access == access_type::FETCH ? 1 : 5) << 16); // issue trap 1 return iss::Err; } } - auto alignment = is_fetch(access) ? (has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); + auto alignment = is_fetch(access) ? (this->has_compressed() ? 2 : 4) : std::min(length, sizeof(reg_t)); if(unlikely(is_fetch(access) && (addr & (alignment - 1)))) { - fault_data = addr; + this->fault_data = addr; if(is_debug(access)) throw trap_access(0, addr); this->reg.trap_state = (1UL << 31); // issue trap 0 @@ -798,7 +598,7 @@ iss::status riscv_hart_mu_p::read(const address_type type, c try { if(!is_debug(access) && (addr & (alignment - 1))) { this->reg.trap_state = (1UL << 31) | 4 << 16; - fault_data = addr; + this->fault_data = addr; return iss::Err; } phys_addr_t phys_addr{access, space, addr}; @@ -818,13 +618,13 @@ iss::status riscv_hart_mu_p::read(const address_type type, c } if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { this->reg.trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault - fault_data = addr; + this->fault_data = addr; } return res; } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } @@ -832,7 +632,7 @@ iss::status riscv_hart_mu_p::read(const address_type type, c case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; - return read_csr(addr, *reinterpret_cast(data)); + return this->read_csr(addr, *reinterpret_cast(data)); } break; case traits::FENCE: { if((addr + length) > mem.size()) @@ -854,7 +654,7 @@ iss::status riscv_hart_mu_p::read(const address_type type, c } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } @@ -883,7 +683,7 @@ iss::status riscv_hart_mu_p::write(const address_type type, << std::hex << addr; break; default: - CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr " << addr; + CPPLOG(TRACE) << prefix << "write of " << length << " bytes @addr 0x" << std::hex << addr; } #endif try { @@ -891,7 +691,7 @@ iss::status riscv_hart_mu_p::write(const address_type type, case traits::MEM: { if(FEAT & FEAT_PMP) { if(!pmp_check(access, addr, length) && (access & access_type::DEBUG) != access_type::DEBUG) { - fault_data = addr; + this->fault_data = addr; if(access && iss::access_type::DEBUG) throw trap_access(0, addr); this->reg.trap_state = (1UL << 31) | (7 << 16); // issue trap 1 @@ -899,7 +699,7 @@ iss::status riscv_hart_mu_p::write(const address_type type, } } if(unlikely(is_fetch(access) && (addr & 0x1) == 1)) { - fault_data = addr; + this->fault_data = addr; if(access && iss::access_type::DEBUG) throw trap_access(0, addr); this->reg.trap_state = (1UL << 31); // issue trap 0 @@ -909,7 +709,7 @@ iss::status riscv_hart_mu_p::write(const address_type type, auto alignment = std::min(length, sizeof(reg_t)); if(length > 1 && (addr & (alignment - 1)) && !is_debug(access)) { this->reg.trap_state = (1UL << 31) | 6 << 16; - fault_data = addr; + this->fault_data = addr; return iss::Err; } phys_addr_t phys_addr{access, space, addr}; @@ -929,19 +729,19 @@ iss::status riscv_hart_mu_p::write(const address_type type, } if(unlikely(res != iss::Ok && (access & access_type::DEBUG) == 0)) { this->reg.trap_state = (1UL << 31) | (7UL << 16); // issue trap 7 (Store/AMO access fault) - fault_data = addr; + this->fault_data = addr; } return res; } catch(trap_access& ta) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; return iss::Err; } } break; case traits::CSR: { if(length != sizeof(reg_t)) return iss::Err; - return write_csr(addr, *reinterpret_cast(data)); + return this->write_csr(addr, *reinterpret_cast(data)); } break; case traits::FENCE: { if((addr + length) > mem.size()) @@ -965,128 +765,12 @@ iss::status riscv_hart_mu_p::write(const address_type type, } catch(trap_access& ta) { if((access & access_type::DEBUG) == 0) { this->reg.trap_state = (1UL << 31) | ta.id; - fault_data = ta.addr; + this->fault_data = ta.addr; } return iss::Err; } } -template -iss::status riscv_hart_mu_p::read_csr(unsigned addr, reg_t& val) { - if(addr >= csr.size()) - return iss::Err; - auto req_priv_lvl = (addr >> 8) & 0x3; - if(this->reg.PRIV < req_priv_lvl) // not having required privileges - throw illegal_instruction_fault(this->fault_data); - auto it = csr_rd_cb.find(addr); - if(it == csr_rd_cb.end() || !it->second) // non existent register - throw illegal_instruction_fault(this->fault_data); - return (this->*(it->second))(addr, val); -} - -template -iss::status riscv_hart_mu_p::write_csr(unsigned addr, reg_t val) { - if(addr >= csr.size()) - return iss::Err; - auto req_priv_lvl = (addr >> 8) & 0x3; - if(this->reg.PRIV < req_priv_lvl) // not having required privileges - throw illegal_instruction_fault(this->fault_data); - if((addr & 0xc00) == 0xc00) // writing to read-only region - throw illegal_instruction_fault(this->fault_data); - auto it = csr_wr_cb.find(addr); - if(it == csr_wr_cb.end() || !it->second) // non existent register - throw illegal_instruction_fault(this->fault_data); - return (this->*(it->second))(addr, val); -} - -template -iss::status riscv_hart_mu_p::read_null(unsigned addr, reg_t& val) { - val = 0; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::read_plain(unsigned addr, reg_t& val) { - val = csr[addr]; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_plain(unsigned addr, reg_t val) { - csr[addr] = val; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::read_cycle(unsigned addr, reg_t& val) { - auto cycle_val = this->reg.cycle + cycle_offset; - if(addr == mcycle) { - val = static_cast(cycle_val); - } else if(addr == mcycleh) { - val = static_cast(cycle_val >> 32); - } - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_cycle(unsigned addr, reg_t val) { - if(sizeof(typename traits::reg_t) != 4) { - mcycle_csr = static_cast(val); - } else { - if(addr == mcycle) { - mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val; - } else { - mcycle_csr = (static_cast(val) << 32) + (mcycle_csr & 0xffffffff); - } - } - cycle_offset = mcycle_csr - this->reg.cycle; // TODO: relying on wrap-around - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::read_instret(unsigned addr, reg_t& val) { - if((addr & 0xff) == (minstret & 0xff)) { - val = static_cast(this->reg.instret); - } else if((addr & 0xff) == (minstreth & 0xff)) { - val = static_cast(this->reg.instret >> 32); - } - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_instret(unsigned addr, reg_t val) { - if(sizeof(typename traits::reg_t) != 4) { - this->reg.instret = static_cast(val); - } else { - if((addr & 0xff) == (minstret & 0xff)) { - this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val; - } else { - this->reg.instret = (static_cast(val) << 32) + (this->reg.instret & 0xffffffff); - } - } - this->reg.instret--; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::read_time(unsigned addr, reg_t& val) { - uint64_t time_val = this->reg.cycle / (100000000 / 32768 - 1); //-> ~3052; - if(addr == time) { - val = static_cast(time_val); - } else if(addr == timeh) { - if(sizeof(typename traits::reg_t) != 4) - return iss::Err; - val = static_cast(time_val >> 32); - } - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::read_tvec(unsigned addr, reg_t& val) { - val = FEAT & features_e::FEAT_CLIC ? csr[addr] : csr[addr] & ~2; - return iss::Ok; -} - template iss::status riscv_hart_mu_p::read_status(unsigned addr, reg_t& val) { val = state.mstatus & hart_state_type::get_mask((addr >> 8) & 0x3); @@ -1102,8 +786,8 @@ iss::status riscv_hart_mu_p::write_status(unsigned addr, reg template iss::status riscv_hart_mu_p::read_cause(unsigned addr, reg_t& val) { - if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec] & 0x3) == 3) { - val = csr[addr] & ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16)); + if((FEAT & features_e::FEAT_CLIC) && (this->csr[mtvec] & 0x3) == 3) { + val = this->csr[addr] & ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16)); auto mode = (addr >> 8) & 0x3; switch(mode) { case 0: @@ -1117,15 +801,15 @@ iss::status riscv_hart_mu_p::read_cause(unsigned addr, reg_t break; } } else - val = csr[addr] & ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1)); + val = this->csr[addr] & ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1)); return iss::Ok; } template iss::status riscv_hart_mu_p::write_cause(unsigned addr, reg_t val) { - if((FEAT & features_e::FEAT_CLIC) && (csr[mtvec] & 0x3) == 3) { + if((FEAT & features_e::FEAT_CLIC) && (this->csr[mtvec] & 0x3) == 3) { auto mask = ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1) | (0xfUL << 16)); - csr[addr] = (val & mask) | (csr[addr] & ~mask); + this->csr[addr] = (val & mask) | (this->csr[addr] & ~mask); auto mode = (addr >> 8) & 0x3; switch(mode) { case 0: @@ -1140,30 +824,24 @@ iss::status riscv_hart_mu_p::write_cause(unsigned addr, reg_ } } else { auto mask = ((1UL << (traits::XLEN - 1)) | (mcause_max_irq - 1)); - csr[addr] = (val & mask) | (csr[addr] & ~mask); + this->csr[addr] = (val & mask) | (this->csr[addr] & ~mask); } return iss::Ok; } -template -iss::status riscv_hart_mu_p::read_hartid(unsigned addr, reg_t& val) { - val = mhartid_reg; - return iss::Ok; -} - template iss::status riscv_hart_mu_p::read_ie(unsigned addr, reg_t& val) { auto mask = get_irq_mask((addr >> 8) & 0x3); - val = csr[mie] & mask; + val = this->csr[mie] & mask; if(this->reg.PRIV != 3) - val &= csr[mideleg]; + val &= this->csr[mideleg]; return iss::Ok; } template iss::status riscv_hart_mu_p::write_ie(unsigned addr, reg_t val) { auto mask = get_irq_mask((addr >> 8) & 0x3); - csr[mie] = (csr[mie] & ~mask) | (val & mask); + this->csr[mie] = (this->csr[mie] & ~mask) | (val & mask); check_interrupt(); return iss::Ok; } @@ -1171,73 +849,23 @@ iss::status riscv_hart_mu_p::write_ie(unsigned addr, reg_t v template iss::status riscv_hart_mu_p::read_ip(unsigned addr, reg_t& val) { auto mask = get_irq_mask((addr >> 8) & 0x3); - val = csr[mip] & mask; + val = this->csr[mip] & mask; if(this->reg.PRIV != 3) - val &= csr[mideleg]; + val &= this->csr[mideleg]; return iss::Ok; } template iss::status riscv_hart_mu_p::write_ideleg(unsigned addr, reg_t val) { auto mask = 0b000100010001; // only U mode supported - csr[mideleg] = (csr[mideleg] & ~mask) | (val & mask); + this->csr[mideleg] = (this->csr[mideleg] & ~mask) | (val & mask); return iss::Ok; } template iss::status riscv_hart_mu_p::write_edeleg(unsigned addr, reg_t val) { auto mask = 0b1011001111110111; // bit 14/10 (reserved), bit 11 (Env call), and 3 (break) are hardwired to 0 - csr[medeleg] = (csr[medeleg] & ~mask) | (val & mask); - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_epc(unsigned addr, reg_t val) { - csr[addr] = val & get_pc_mask(); - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_dcsr(unsigned addr, reg_t val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - // +-------------- ebreakm - // | +---------- stepi - // | | +++----- cause - // | | ||| +- step - csr[addr] = val & 0b1000100111000100U; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::read_debug(unsigned addr, reg_t& val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - val = csr[addr]; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_dscratch(unsigned addr, reg_t val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - csr[addr] = val; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::read_dpc(unsigned addr, reg_t& val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - val = this->reg.DPC; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_dpc(unsigned addr, reg_t val) { - if(!debug_mode_active()) - throw illegal_instruction_fault(this->fault_data); - this->reg.DPC = val; + this->csr[medeleg] = (this->csr[medeleg] & ~mask) | (val & mask); return iss::Ok; } @@ -1250,27 +878,9 @@ iss::status riscv_hart_mu_p::read_intstatus(unsigned addr, r return iss::Ok; } -template -iss::status riscv_hart_mu_p::read_fcsr(unsigned addr, reg_t& val) { - val = this->get_fcsr(); - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_fcsr(unsigned addr, reg_t val) { - this->set_fcsr(val); - return iss::Ok; -} - template iss::status riscv_hart_mu_p::write_intthresh(unsigned addr, reg_t val) { - csr[addr] = (val & 0xff) | (1 << (cfg.clic_int_ctl_bits)) - 1; - return iss::Ok; -} - -template -iss::status riscv_hart_mu_p::write_xtvt(unsigned addr, reg_t val) { - csr[addr] = val & ~0x3fULL; + this->csr[addr] = (val & 0xff) | (1 << (cfg.clic_int_ctl_bits)) - 1; return iss::Ok; } @@ -1292,14 +902,16 @@ iss::status riscv_hart_mu_p::write_mem(phys_addr_t paddr, un // tohost handling in case of riscv-test // according to https://github.com/riscv-software-src/riscv-isa-sim/issues/364#issuecomment-607657754: if(paddr.access && iss::access_type::FUNC) { - if(paddr.val == tohost) { + if(paddr.val == this->tohost) { reg_t cur_data = *reinterpret_cast(data); // Extract Device (bits 63:56) - uint8_t device = traits::XLEN == 32 ? *reinterpret_cast(p.data() + ((tohost + 4) & mem.page_addr_mask)) >> 24 - : (cur_data >> 56) & 0xFF; + uint8_t device = traits::XLEN == 32 + ? *reinterpret_cast(p.data() + ((this->tohost + 4) & mem.page_addr_mask)) >> 24 + : (cur_data >> 56) & 0xFF; // Extract Command (bits 55:48) - uint8_t command = traits::XLEN == 32 ? *reinterpret_cast(p.data() + ((tohost + 4) & mem.page_addr_mask)) >> 16 - : (cur_data >> 48) & 0xFF; + uint8_t command = traits::XLEN == 32 + ? *reinterpret_cast(p.data() + ((this->tohost + 4) & mem.page_addr_mask)) >> 16 + : (cur_data >> 48) & 0xFF; // Extract payload (bits 47:0) uint64_t payload_addr = cur_data & 0xFFFFFFFFFFFFULL; if(payload_addr & 1) { @@ -1315,7 +927,7 @@ iss::status riscv_hart_mu_p::write_mem(phys_addr_t paddr, un CPPLOG(ERR) << "Syscall read went wrong"; uint64_t syscall_num = loaded_payload.at(0); if(syscall_num == 64) { // SYS_WRITE - return execute_sys_write(this, loaded_payload, traits::MEM); + return this->execute_sys_write(this, loaded_payload, traits::MEM); } else { CPPLOG(ERR) << "tohost syscall with number 0x" << std::hex << syscall_num << std::dec << " (" << syscall_num << ") not implemented"; @@ -1330,9 +942,9 @@ iss::status riscv_hart_mu_p::write_mem(phys_addr_t paddr, un return iss::Ok; } } - if((traits::XLEN == 32 && paddr.val == fromhost + 4) || (traits::XLEN == 64 && paddr.val == fromhost)) { - uint64_t fhostvar = *reinterpret_cast(p.data() + (fromhost & mem.page_addr_mask)); - *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)) = fhostvar; + if((traits::XLEN == 32 && paddr.val == this->fromhost + 4) || (traits::XLEN == 64 && paddr.val == this->fromhost)) { + uint64_t fhostvar = *reinterpret_cast(p.data() + (this->fromhost & mem.page_addr_mask)); + *reinterpret_cast(p.data() + (this->tohost & mem.page_addr_mask)) = fhostvar; } } return iss::Ok; @@ -1381,12 +993,12 @@ template inline void riscv_har template void riscv_hart_mu_p::check_interrupt() { // TODO: Implement CLIC functionality - auto ideleg = csr[mideleg]; + auto ideleg = this->csr[mideleg]; // Multiple simultaneous interrupts and traps at the same privilege level are // handled in the following decreasing priority order: // external interrupts, software interrupts, timer interrupts, then finally // any synchronous traps. - auto ena_irq = csr[mip] & csr[mie]; + auto ena_irq = this->csr[mip] & this->csr[mie]; bool mstatus_mie = state.mstatus.MIE; auto m_enabled = this->reg.PRIV < PRIV_M || mstatus_mie; @@ -1415,10 +1027,10 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ // calculate effective privilege level unsigned new_priv = PRIV_M; if(trap_id == 0) { // exception - if(this->reg.PRIV != PRIV_M && ((csr[medeleg] >> cause) & 0x1) != 0) + if(this->reg.PRIV != PRIV_M && ((this->csr[medeleg] >> cause) & 0x1) != 0) new_priv = PRIV_U; // store ret addr in xepc register - csr[uepc | (new_priv << 8)] = static_cast(addr); // store actual address instruction of exception + this->csr[uepc | (new_priv << 8)] = static_cast(addr); // store actual address instruction of exception /* * write mtval if new_priv=M_MODE, spec says: * When a hardware breakpoint is triggered, or an instruction-fetch, load, @@ -1428,20 +1040,20 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ */ switch(cause) { case 0: - csr[utval | (new_priv << 8)] = static_cast(addr); + this->csr[utval | (new_priv << 8)] = static_cast(addr); break; case 2: - csr[utval | (new_priv << 8)] = (!has_compressed() || (instr & 0x3) == 3) ? instr : instr & 0xffff; + this->csr[utval | (new_priv << 8)] = (!this->has_compressed() || (instr & 0x3) == 3) ? instr : instr & 0xffff; break; case 3: - if((FEAT & FEAT_DEBUG) && (csr[dcsr] & 0x8000)) { + if((FEAT & FEAT_DEBUG) && (this->csr[dcsr] & 0x8000)) { this->reg.DPC = addr; - csr[dcsr] = (csr[dcsr] & ~0x1c3) | (1 << 6) | PRIV_M; // FIXME: cause should not be 4 (stepi) + this->csr[dcsr] = (this->csr[dcsr] & ~0x1c3) | (1 << 6) | PRIV_M; // FIXME: cause should not be 4 (stepi) new_priv = this->reg.PRIV | PRIV_D; } else { - csr[utval | (new_priv << 8)] = addr; + this->csr[utval | (new_priv << 8)] = addr; } - if(semihosting_cb) { + if(this->semihosting_cb) { // Check for semihosting call phys_addr_t p_addr(access_type::DEBUG_READ, traits::MEM, addr - 4); std::array data; @@ -1462,7 +1074,7 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ #endif CLOG(INFO, disass) << "Semihosting call at address " << buffer.data() << " occurred "; - semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); + this->semihosting_cb(this, &(this->reg.X10) /*a0*/, &(this->reg.X11) /*a1*/); return this->reg.NEXT_PC; } } @@ -1470,20 +1082,20 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ case 4: case 6: case 7: - csr[utval | (new_priv << 8)] = fault_data; + this->csr[utval | (new_priv << 8)] = this->fault_data; break; default: - csr[utval | (new_priv << 8)] = 0; + this->csr[utval | (new_priv << 8)] = 0; } - fault_data = 0; + this->fault_data = 0; } else { - if(this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0) + if(this->reg.PRIV != PRIV_M && ((this->csr[mideleg] >> cause) & 0x1) != 0) new_priv = PRIV_U; - csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt + this->csr[uepc | (new_priv << 8)] = this->reg.NEXT_PC; // store next address if interrupt this->reg.pending_trap = 0; } size_t adr = ucause | (new_priv << 8); - csr[adr] = (trap_id << (traits::XLEN - 1)) + cause; + this->csr[adr] = (trap_id << (traits::XLEN - 1)) + cause; // update mstatus // xPP field of mstatus is written with the active privilege mode at the time // of the trap; the x PIE field of mstatus @@ -1506,12 +1118,12 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ } // get trap vector - auto xtvec = csr[utvec | (new_priv << 8)]; + auto xtvec = this->csr[utvec | (new_priv << 8)]; // calculate addr// set NEXT_PC to trap addressess to jump to based on MODE // bits in mtvec if((FEAT & features_e::FEAT_CLIC) && trap_id != 0 && (xtvec & 0x3UL) == 3UL) { reg_t data; - auto ret = read(address_type::LOGICAL, access_type::READ, 0, csr[mtvt], sizeof(reg_t), reinterpret_cast(&data)); + auto ret = read(address_type::LOGICAL, access_type::READ, 0, this->csr[mtvt], sizeof(reg_t), reinterpret_cast(&data)); if(ret == iss::Err) return this->reg.PC; this->reg.NEXT_PC = data; @@ -1527,10 +1139,10 @@ uint64_t riscv_hart_mu_p::enter_trap(uint64_t flags, uint64_ sprintf(buffer.data(), "0x%016lx", addr); #endif if((flags & 0xffffffff) != 0xffffffff) - CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" << (trap_id ? irq_str[cause] : trap_str[cause]) << "' (" - << cause << ")" - << " at address " << buffer.data() << " occurred, changing privilege level from " << lvl[this->reg.PRIV] - << " to " << lvl[new_priv]; + CLOG(INFO, disass) << (trap_id ? "Interrupt" : "Trap") << " with cause '" + << (trap_id ? this->irq_str[cause] : this->trap_str[cause]) << "' (" << cause << ")" + << " at address " << buffer.data() << " occurred, changing privilege level from " << this->lvl[this->reg.PRIV] + << " to " << this->lvl[new_priv]; // reset trap state this->reg.PRIV = new_priv; this->reg.trap_state = 0; @@ -1562,8 +1174,9 @@ template uint64_t riscv_hart_m break; } // sets the pc to the value stored in the x epc register. - this->reg.NEXT_PC = csr[uepc | inst_priv << 8]; - CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to " << lvl[this->reg.PRIV]; + this->reg.NEXT_PC = this->csr[uepc | inst_priv << 8]; + CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << this->lvl[cur_priv] << " to " + << this->lvl[this->reg.PRIV]; check_interrupt(); } return this->reg.NEXT_PC; diff --git a/src/vm/interp/vm_tgc5c.cpp b/src/vm/interp/vm_tgc5c.cpp index 3284e85..e23b520 100644 --- a/src/vm/interp/vm_tgc5c.cpp +++ b/src/vm/interp/vm_tgc5c.cpp @@ -2695,11 +2695,12 @@ std::unique_ptr create(arch::tgc5c *core, unsigned short por } // namespace iss #include +#include #include #include namespace iss { namespace { -volatile std::array dummy = { +volatile std::array dummy = { core_factory::instance().register_creator("tgc5c|m_p|interp", [](unsigned port, void* init_data) -> std::tuple{ auto* cpu = new iss::arch::riscv_hart_m_p(); auto vm = new interp::tgc5c::vm_impl(*cpu, false); @@ -2719,6 +2720,16 @@ volatile std::array dummy = { cpu->set_semihosting_callback(*cb); } return {cpu_ptr{cpu}, vm_ptr{vm}}; + }), + core_factory::instance().register_creator("tgc5c|mus_vp|interp", [](unsigned port, void* init_data) -> std::tuple{ + auto* cpu = new iss::arch::riscv_hart_msu_vp(); + auto vm = new interp::tgc5c::vm_impl(*cpu, false); + if (port != 0) debugger::server::run_server(vm, port); + if(init_data){ + auto* cb = reinterpret_cast::reg_t>*>(init_data); + cpu->set_semihosting_callback(*cb); + } + return {cpu_ptr{cpu}, vm_ptr{vm}}; }) }; }