Skip to content

Commit

Permalink
feat: optimize double indirection when accessing X registers
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Oct 30, 2024
1 parent bd8af66 commit 8b3d48c
Show file tree
Hide file tree
Showing 8 changed files with 361 additions and 375 deletions.
4 changes: 2 additions & 2 deletions src/device-state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace cartesi {
template <typename STATE_ACCESS>
class device_state_access : public i_device_state_access {
public:
explicit device_state_access(STATE_ACCESS &a, uint64_t mcycle) : m_a(a), m_mcycle(mcycle) {
explicit device_state_access(STATE_ACCESS a, uint64_t mcycle) : m_a(a), m_mcycle(mcycle) {
static_assert(is_an_i_state_access<STATE_ACCESS>::value, "not an i_state_access");
}

Expand All @@ -52,7 +52,7 @@ class device_state_access : public i_device_state_access {
~device_state_access() override = default;

private:
STATE_ACCESS &m_a; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
STATE_ACCESS m_a; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members)
uint64_t m_mcycle;

void do_set_mip(uint64_t mask) override {
Expand Down
691 changes: 345 additions & 346 deletions src/interpret.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/interpret.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ enum class interpreter_break_reason {
/// \details The interpret may stop early if the machine halts permanently or becomes temporarily idle (waiting for
/// interrupts).
template <typename STATE_ACCESS>
interpreter_break_reason interpret(STATE_ACCESS &a, uint64_t mcycle_end);
interpreter_break_reason interpret(STATE_ACCESS a, uint64_t mcycle_end);

} // namespace cartesi

Expand Down
8 changes: 4 additions & 4 deletions src/machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2227,7 +2227,7 @@ void machine::fill_memory(uint64_t address, uint8_t data, uint64_t length) {
}

void machine::read_virtual_memory(uint64_t vaddr_start, unsigned char *data, uint64_t length) {
state_access a(*this);
const state_access a(*this);
if (length == 0) {
return;
}
Expand Down Expand Up @@ -2258,7 +2258,7 @@ void machine::read_virtual_memory(uint64_t vaddr_start, unsigned char *data, uin
}

void machine::write_virtual_memory(uint64_t vaddr_start, const unsigned char *data, uint64_t length) {
state_access a(*this);
const state_access a(*this);
if (length == 0) {
return;
}
Expand Down Expand Up @@ -2291,7 +2291,7 @@ void machine::write_virtual_memory(uint64_t vaddr_start, const unsigned char *da
}

uint64_t machine::translate_virtual_address(uint64_t vaddr) {
state_access a(*this);
const state_access a(*this);
// perform address translation using read access mode
uint64_t paddr = 0;
if (!cartesi::translate_virtual_address<state_access, false>(a, &paddr, vaddr, PTE_XWR_R_SHIFT)) {
Expand Down Expand Up @@ -2468,7 +2468,7 @@ interpreter_break_reason machine::run(uint64_t mcycle_end) {
if (mcycle_end < read_reg(reg::mcycle)) {
throw std::invalid_argument{"mcycle is past"};
}
state_access a(*this);
const state_access a(*this);
return interpret(a, mcycle_end);
}

Expand Down
11 changes: 0 additions & 11 deletions src/state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,6 @@ class state_access : public i_state_access<state_access, pma_entry> {
;
}

/// \brief No copy constructor
state_access(const state_access &) = delete;
/// \brief No copy assignment
state_access &operator=(const state_access &) = delete;
/// \brief No move constructor
state_access(state_access &&) = delete;
/// \brief No move assignment
state_access &operator=(state_access &&) = delete;
/// \brief Default destructor
~state_access() = default;

const machine &get_naked_machine() const {
return m_m;
}
Expand Down
6 changes: 3 additions & 3 deletions src/translate-virtual-address.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace cartesi {
/// \param val Value to write.
/// \returns True if succeeded, false otherwise.
template <typename STATE_ACCESS>
static inline bool write_ram_uint64(STATE_ACCESS &a, uint64_t paddr, uint64_t val) {
static inline bool write_ram_uint64(STATE_ACCESS a, uint64_t paddr, uint64_t val) {
auto &pma = a.template find_pma_entry<uint64_t>(paddr);
if (unlikely(!pma.get_istart_M() || !pma.get_istart_W())) {
return false;
Expand All @@ -79,7 +79,7 @@ static inline bool write_ram_uint64(STATE_ACCESS &a, uint64_t paddr, uint64_t va
/// \param pval Pointer to word.
/// \returns True if succeeded, false otherwise.
template <typename STATE_ACCESS>
static inline bool read_ram_uint64(STATE_ACCESS &a, uint64_t paddr, uint64_t *pval) {
static inline bool read_ram_uint64(STATE_ACCESS a, uint64_t paddr, uint64_t *pval) {
auto &pma = a.template find_pma_entry<uint64_t>(paddr);
if (unlikely(!pma.get_istart_M() || !pma.get_istart_R())) {
return false;
Expand All @@ -102,7 +102,7 @@ static inline bool read_ram_uint64(STATE_ACCESS &a, uint64_t paddr, uint64_t *pv
/// \details This function is outlined to minimize host CPU code cache pressure.
/// \returns True if succeeded, false otherwise.
template <typename STATE_ACCESS, bool UPDATE_PTE = true>
static NO_INLINE bool translate_virtual_address(STATE_ACCESS &a, uint64_t *ppaddr, uint64_t vaddr, int xwr_shift) {
static NO_INLINE bool translate_virtual_address(STATE_ACCESS a, uint64_t *ppaddr, uint64_t vaddr, int xwr_shift) {
auto priv = a.read_iflags_PRV();
const uint64_t mstatus = a.read_mstatus();

Expand Down
8 changes: 2 additions & 6 deletions uarch/uarch-machine-state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,14 +148,10 @@ class uarch_pma_entry final {

// Provides access to the state of the big emulator from microcode
class uarch_machine_state_access : public i_state_access<uarch_machine_state_access, uarch_pma_entry> {
std::array<std::optional<uarch_pma_entry>, PMA_MAX> m_pmas;
std::array<std::optional<uarch_pma_entry>, PMA_MAX> &m_pmas;

public:
uarch_machine_state_access() = default;
uarch_machine_state_access(const uarch_machine_state_access &other) = delete;
uarch_machine_state_access(uarch_machine_state_access &&other) = delete;
uarch_machine_state_access &operator=(const uarch_machine_state_access &other) = delete;
uarch_machine_state_access &operator=(uarch_machine_state_access &&other) = delete;
explicit uarch_machine_state_access(std::array<std::optional<uarch_pma_entry>, PMA_MAX>& pmas) : m_pmas(pmas) {}
~uarch_machine_state_access() = default;

private:
Expand Down
6 changes: 4 additions & 2 deletions uarch/uarch-run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,20 @@ static void set_uarch_halt_flag() {
}

// Let the state accessor be on static memory storage to speed up uarch initialization
static uarch_machine_state_access a; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)

static std::array<std::optional<uarch_pma_entry>, PMA_MAX> pmas;

namespace cartesi {

// Declaration of explicit instantiation in module interpret.cpp when compiled with microarchitecture
extern template interpreter_break_reason interpret(uarch_machine_state_access &a, uint64_t mcycle_end);
extern template interpreter_break_reason interpret(uarch_machine_state_access a, uint64_t mcycle_end);

} // namespace cartesi

/// \brief Advances one mcycle by executing the "big machine interpreter" compiled to the microarchitecture
/// \return This function never returns
extern "C" NO_RETURN void interpret_next_mcycle_with_uarch() {
uarch_machine_state_access a(pmas);
const uint64_t mcycle_end = a.read_mcycle() + 1;
interpret(a, mcycle_end);
// Finished executing a whole mcycle: halt the microarchitecture
Expand Down

0 comments on commit 8b3d48c

Please sign in to comment.