diff --git a/src/htif-factory.cpp b/src/htif-factory.cpp index c48add94..151da7f0 100644 --- a/src/htif-factory.cpp +++ b/src/htif-factory.cpp @@ -32,7 +32,7 @@ static bool htif_peek(const pma_entry &pma, const machine & /*m*/, uint64_t page return (page_offset % PMA_PAGE_SIZE) == 0 && page_offset < pma.get_length(); } -pma_entry make_htif_pma_entry(uint64_t start, uint64_t length, htif_runtime_config *context) { +pma_entry make_htif_pma_entry(uint64_t start, uint64_t length) { const pma_entry::flags f{ true, // R true, // W @@ -41,7 +41,7 @@ pma_entry make_htif_pma_entry(uint64_t start, uint64_t length, htif_runtime_conf false, // IW PMA_ISTART_DID::HTIF // DID }; - return make_device_pma_entry("HTIF device", start, length, htif_peek, &htif_driver, context).set_flags(f); + return make_device_pma_entry("HTIF device", start, length, htif_peek, &htif_driver).set_flags(f); } } // namespace cartesi diff --git a/src/htif-factory.h b/src/htif-factory.h index 97dde77c..9a680768 100644 --- a/src/htif-factory.h +++ b/src/htif-factory.h @@ -25,7 +25,7 @@ namespace cartesi { /// \brief Creates a PMA entry for the HTIF device -pma_entry make_htif_pma_entry(uint64_t start, uint64_t length, htif_runtime_config *context); +pma_entry make_htif_pma_entry(uint64_t start, uint64_t length); } // namespace cartesi diff --git a/src/htif.cpp b/src/htif.cpp index 24358d6d..d6490a93 100644 --- a/src/htif.cpp +++ b/src/htif.cpp @@ -19,7 +19,6 @@ #include "htif.h" #include "i-device-state-access.h" #include "interpret.h" -#include "machine-runtime-config.h" #include "os.h" #include "pma-driver.h" @@ -89,17 +88,12 @@ static execute_status htif_yield(i_device_state_access *a, uint64_t cmd, uint64_ return status; } -static execute_status htif_console(htif_runtime_config *runtime_config, i_device_state_access *a, uint64_t cmd, - uint64_t data) { +static execute_status htif_console(i_device_state_access *a, uint64_t cmd, uint64_t data) { // If console command is enabled, perform it and acknowledge if (cmd < 64 && (((a->read_htif_iconsole() >> cmd) & 1) != 0)) { if (cmd == HTIF_CONSOLE_CMD_PUTCHAR) { const uint8_t ch = data & 0xff; - // In microarchitecture runtime_config will always be nullptr, - // therefore the HTIF runtime config is actually ignored. - if ((runtime_config == nullptr) || !runtime_config->no_console_putchar) { - os_putchar(ch); - } + os_putchar(ch); a->write_htif_fromhost(HTIF_BUILD(HTIF_DEV_CONSOLE, cmd, 0, 0)); } else if (cmd == HTIF_CONSOLE_CMD_GETCHAR) { // In blockchain, this command will never be enabled as there is no way to input the same character @@ -115,8 +109,7 @@ static execute_status htif_console(htif_runtime_config *runtime_config, i_device return execute_status::success; } -static execute_status htif_write_tohost(htif_runtime_config *runtime_config, i_device_state_access *a, - uint64_t tohost) { +static execute_status htif_write_tohost(i_device_state_access *a, uint64_t tohost) { // Decode tohost const uint32_t device = HTIF_DEV_FIELD(tohost); const uint32_t cmd = HTIF_CMD_FIELD(tohost); @@ -128,7 +121,7 @@ static execute_status htif_write_tohost(htif_runtime_config *runtime_config, i_d case HTIF_DEV_HALT: return htif_halt(a, cmd, data); case HTIF_DEV_CONSOLE: - return htif_console(runtime_config, a, cmd, data); + return htif_console(a, cmd, data); case HTIF_DEV_YIELD: return htif_yield(a, cmd, data); //??D Unknown HTIF devices are silently ignored @@ -138,10 +131,8 @@ static execute_status htif_write_tohost(htif_runtime_config *runtime_config, i_d } /// \brief HTIF device write callback. See ::pma_write. -static execute_status htif_write(void *context, i_device_state_access *a, uint64_t offset, uint64_t val, +static execute_status htif_write(void * /*context*/, i_device_state_access *a, uint64_t offset, uint64_t val, int log2_size) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - auto *runtime_config = reinterpret_cast(context); // Our HTIF only supports 64-bit writes if (log2_size != 3) { return execute_status::failure; @@ -150,7 +141,7 @@ static execute_status htif_write(void *context, i_device_state_access *a, uint64 // Only these 64-bit aligned offsets are valid switch (offset) { case htif_tohost_rel_addr: - return htif_write_tohost(runtime_config, a, val); + return htif_write_tohost(a, val); case htif_fromhost_rel_addr: a->write_htif_fromhost(val); return execute_status::success; diff --git a/src/i-state-access.h b/src/i-state-access.h index 0d1433f2..2d8345ff 100644 --- a/src/i-state-access.h +++ b/src/i-state-access.h @@ -656,14 +656,6 @@ class i_state_access { // CRTP return derived().do_get_host_memory(pma); } - auto read_device(PMA_ENTRY_TYPE &pma, uint64_t mcycle, uint64_t offset, uint64_t *pval, int log2_size) { - return derived().do_read_device(pma, mcycle, offset, pval, log2_size); - } - - auto write_device(PMA_ENTRY_TYPE &pma, uint64_t mcycle, uint64_t offset, uint64_t pval, int log2_size) { - return derived().do_write_device(pma, mcycle, offset, pval, log2_size); - } - /// \brief Try to translate a virtual address to a host pointer through the TLB. /// \tparam ETYPE TLB entry type. /// \tparam T Type of word that would be read with the pointer. diff --git a/src/interpret.cpp b/src/interpret.cpp index e68e8fd6..fc02d88b 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -849,8 +849,11 @@ static NO_INLINE std::pair read_virtual_memory_slow(STATE_ACCESS if (likely(pma.get_istart_IO())) { const uint64_t offset = paddr - pma.get_start(); uint64_t val{}; + device_state_access da(a, mcycle); // If we do not know how to read, we treat this as a PMA violation - if (likely(a.read_device(pma, mcycle, offset, &val, log2_size::value))) { + const bool status = pma.get_device_noexcept().get_driver()->read(pma.get_device_noexcept().get_context(), + &da, offset, &val, log2_size::value); + if (likely(status)) { *pval = static_cast(val); // device logs its own state accesses return {true, pc}; @@ -924,8 +927,9 @@ static NO_INLINE std::pair write_virtual_memory_slow(S } if (likely(pma.get_istart_IO())) { const uint64_t offset = paddr - pma.get_start(); - auto status = - a.write_device(pma, mcycle, offset, static_cast(static_cast(val64)), log2_size::value); + device_state_access da(a, mcycle); + auto status = pma.get_device_noexcept().get_driver()->write(pma.get_device_noexcept().get_context(), &da, + offset, static_cast(static_cast(val64)), log2_size::value); // If we do not know how to write, we treat this as a PMA violation if (likely(status != execute_status::failure)) { return {status, pc}; diff --git a/src/machine.cpp b/src/machine.cpp index 406fd709..532f205a 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -392,7 +392,7 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) : m_c register_pma_entry(make_cmio_rx_buffer_pma_entry(m_c.cmio)); // Register HTIF device - register_pma_entry(make_htif_pma_entry(PMA_HTIF_START, PMA_HTIF_LENGTH, &m_r.htif)); + register_pma_entry(make_htif_pma_entry(PMA_HTIF_START, PMA_HTIF_LENGTH)); // Copy HTIF state to from config to machine write_reg(reg::htif_tohost, m_c.htif.tohost); @@ -545,6 +545,7 @@ machine::machine(const machine_config &c, const machine_runtime_config &r) : m_c } os_open_tty(); } + os_silence_putchar(m_r.htif.no_console_putchar); // Initialize memory range descriptions returned by get_memory_ranges method for (const auto *pma : m_merkle_pmas) { @@ -635,11 +636,9 @@ const machine_runtime_config &machine::get_runtime_config() const { /// \brief Changes the machine runtime config. void machine::set_runtime_config(const machine_runtime_config &r) { - if (r.htif.no_console_putchar != m_r.htif.no_console_putchar) { - throw std::runtime_error{"cannot change htif runtime configuration"}; - } m_r = r; m_s.soft_yield = m_r.soft_yield; + os_silence_putchar(r.htif.no_console_putchar); } machine_config machine::get_serialization_config() const { diff --git a/src/os.cpp b/src/os.cpp index e0531699..44d1ac52 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -120,6 +120,7 @@ using namespace std::string_literals; struct tty_state { bool initialized{false}; bool resize_pending{false}; + bool silence_putchar{false}; std::array buf{}; // Characters in console input buffer intptr_t buf_pos{}; intptr_t buf_len{}; @@ -135,12 +136,23 @@ struct tty_state { }; /// Returns pointer to the global TTY state -static tty_state *get_state() { +static tty_state *get_tty_state() { static tty_state data; return &data; } #endif // HAVE_TTY +/// \brief putchar global state +struct putchar_state { + bool silence; +}; + +/// Returns pointer to the global TTY state +static putchar_state *get_putchar_state() { + static putchar_state data; + return &data; +} + #ifdef HAVE_TERMIOS static int new_ttyfd(const char *path) { int fd{}; @@ -176,7 +188,7 @@ static int get_ttyfd() { #ifdef HAVE_SIGACTION /// \brief Signal raised whenever TTY size changes static void os_SIGWINCH_handler(int /*sig*/) { - auto *s = get_state(); + auto *s = get_tty_state(); if (!s->initialized) { return; } @@ -225,7 +237,7 @@ bool os_update_tty_size([[maybe_unused]] tty_state *s) { void os_open_tty() { #ifdef HAVE_TTY - auto *s = get_state(); + auto *s = get_tty_state(); if (s->initialized) { // Already initialized return; @@ -332,7 +344,7 @@ void os_open_tty() { void os_close_tty() { #ifdef HAVE_TTY #ifdef HAVE_TERMIOS - auto *s = get_state(); + auto *s = get_tty_state(); if (s->ttyfd >= 0) { // Restore old mode tcsetattr(s->ttyfd, TCSANOW, &s->oldtty); close(s->ttyfd); @@ -340,7 +352,7 @@ void os_close_tty() { } #elif defined(_WIN32) - auto *s = get_state(); + auto *s = get_tty_state(); if (s->hStdin) { SetConsoleMode(s->hStdin, s->dwOldStdinMode); s->hStdin = NULL; @@ -351,7 +363,7 @@ void os_close_tty() { } void os_get_tty_size(uint16_t *pwidth, uint16_t *pheight) { - auto *s = get_state(); + auto *s = get_tty_state(); if (!s->initialized) { // fallback values *pwidth = TTY_DEFAULT_COLS; @@ -370,7 +382,7 @@ void os_get_tty_size(uint16_t *pwidth, uint16_t *pheight) { void os_prepare_tty_select([[maybe_unused]] select_fd_sets *fds) { #ifdef HAVE_TTY - auto *s = get_state(); + auto *s = get_tty_state(); // Ignore if TTY is not initialized or stdin was closed if (!s->initialized) { return; @@ -387,7 +399,7 @@ void os_prepare_tty_select([[maybe_unused]] select_fd_sets *fds) { } bool os_poll_selected_tty([[maybe_unused]] int select_ret, [[maybe_unused]] select_fd_sets *fds) { - auto *s = get_state(); + auto *s = get_tty_state(); if (!s->initialized) { // We can't poll when TTY is not initialized return false; } @@ -444,7 +456,7 @@ bool os_poll_selected_tty([[maybe_unused]] int select_ret, [[maybe_unused]] sele bool os_poll_tty(uint64_t timeout_us) { #ifdef _WIN32 - auto *s = get_state(); + auto *s = get_tty_state(); if (!s->initialized) { // We can't poll when TTY is not initialized return false; } @@ -468,7 +480,7 @@ bool os_poll_tty(uint64_t timeout_us) { int os_getchar() { #ifdef HAVE_TTY - auto *s = get_state(); + auto *s = get_tty_state(); if (!s->initialized) { return -1; } @@ -501,9 +513,18 @@ static void fputc_with_line_buffering(uint8_t ch) { } } +void os_silence_putchar(bool yes) { + auto *ps = get_putchar_state(); + ps->silence = yes; +} + void os_putchar(uint8_t ch) { + auto *ps = get_putchar_state(); + if (ps->silence) { + return; + } #ifdef HAVE_TTY - auto *s = get_state(); + auto *s = get_tty_state(); if (!s->initialized) { // Write through fputc(), so we can take advantage of buffering. fputc_with_line_buffering(ch); @@ -520,6 +541,10 @@ void os_putchar(uint8_t ch) { } void os_putchars(const uint8_t *data, size_t len) { + auto *ps = get_putchar_state(); + if (ps->silence) { + return; + } for (size_t i = 0; i < len; ++i) { os_putchar(data[i]); } diff --git a/src/os.h b/src/os.h index ffb41ea2..dbca1554 100644 --- a/src/os.h +++ b/src/os.h @@ -86,6 +86,10 @@ void os_putchar(uint8_t ch); /// \param len Length of buffer. void os_putchars(const uint8_t *data, size_t len); +/// \brief Silences putchar (and putchars) output +/// \param yes If true, putchar is silenced +void os_silence_putchar(bool yes); + /// \brief Creates a new directory int os_mkdir(const char *path, int mode); diff --git a/src/record-step-state-access.h b/src/record-step-state-access.h index 00cfcfd8..eb70b926 100644 --- a/src/record-step-state-access.h +++ b/src/record-step-state-access.h @@ -630,18 +630,6 @@ class record_step_state_access : public i_state_access(index)]; } - bool do_read_device(pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t *pval, int log2_size) { - device_state_access da(*this, mcycle); - return pma.get_device_noexcept().get_driver()->read(pma.get_device_noexcept().get_context(), &da, offset, pval, - log2_size); - } - - execute_status do_write_device(pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t val, int log2_size) { - device_state_access da(*this, mcycle); - return pma.get_device_noexcept().get_driver()->write(pma.get_device_noexcept().get_context(), &da, offset, val, - log2_size); - } - template bool do_translate_vaddr_via_tlb(uint64_t vaddr, unsigned char **phptr) { const uint64_t eidx = tlb_get_entry_index(vaddr); diff --git a/src/replay-step-state-access.h b/src/replay-step-state-access.h index ac2d55ef..39637095 100644 --- a/src/replay-step-state-access.h +++ b/src/replay-step-state-access.h @@ -42,6 +42,8 @@ namespace cartesi { // \file this code is designed to be compiled for a free-standing environment. // Environment-specific functions have the prefix "interop_" and are declared in "replay-step-state-access-interop.h" +//??D can we merge this calss with uarch_pma_entry in uarch/uarch-machine-state-access.h ? +//??D maybe implement base class in pma.h and subclass here if there is some minor difference? class mock_pma_entry final { public: struct flags { @@ -61,22 +63,50 @@ class mock_pma_entry final { uint64_t m_start; uint64_t m_length; flags m_flags; - const pma_driver *m_device_driver; - void *m_device_context; + const pma_driver *m_driver{nullptr}; + + static constexpr flags split_flags(uint64_t istart) { + flags f{}; + f.M = ((istart & PMA_ISTART_M_MASK) >> PMA_ISTART_M_SHIFT) != 0; + f.IO = ((istart & PMA_ISTART_IO_MASK) >> PMA_ISTART_IO_SHIFT) != 0; + f.E = ((istart & PMA_ISTART_E_MASK) >> PMA_ISTART_E_SHIFT) != 0; + f.R = ((istart & PMA_ISTART_R_MASK) >> PMA_ISTART_R_SHIFT) != 0; + f.W = ((istart & PMA_ISTART_W_MASK) >> PMA_ISTART_W_SHIFT) != 0; + f.X = ((istart & PMA_ISTART_X_MASK) >> PMA_ISTART_X_SHIFT) != 0; + f.IR = ((istart & PMA_ISTART_IR_MASK) >> PMA_ISTART_IR_SHIFT) != 0; + f.IW = ((istart & PMA_ISTART_IW_MASK) >> PMA_ISTART_IW_SHIFT) != 0; + f.DID = static_cast((istart & PMA_ISTART_DID_MASK) >> PMA_ISTART_DID_SHIFT); + return f; + } public: - mock_pma_entry(uint64_t pma_index, uint64_t start, uint64_t length, flags flags, - const pma_driver *pma_driver = nullptr, void *device_context = nullptr) : + mock_pma_entry(uint64_t pma_index, uint64_t istart, uint64_t ilength) : m_pma_index{pma_index}, - m_start{start}, - m_length{length}, - m_flags{flags}, - m_device_driver{pma_driver}, - m_device_context{device_context} {} - - mock_pma_entry() : - mock_pma_entry(-1, 0, 0, {false, false, true, false, false, false, false, false, PMA_ISTART_DID{}}) { - ; + m_start{istart & PMA_ISTART_START_MASK}, + m_length{ilength}, + m_flags{split_flags(istart)} { + if (m_flags.IO) { + switch (m_flags.DID) { + case PMA_ISTART_DID::shadow_state: + m_driver = &shadow_state_driver; + break; + case PMA_ISTART_DID::shadow_TLB: + m_driver = &shadow_tlb_driver; + break; + case PMA_ISTART_DID::CLINT: + m_driver = &clint_driver; + break; + case PMA_ISTART_DID::PLIC: + m_driver = &plic_driver; + break; + case PMA_ISTART_DID::HTIF: + m_driver = &htif_driver; + break; + default: + interop_throw_runtime_error("unsupported device in build_mock_pma_entry"); + break; + } + } } uint64_t get_index() const { @@ -123,12 +153,16 @@ class mock_pma_entry final { return m_flags.IR; } - const pma_driver *get_device_driver() { - return m_device_driver; + const auto *get_driver() const { + return m_driver; } - void *get_device_context() { - return m_device_context; + const auto &get_device_noexcept() const { + return *this; + } + + static void *get_context() { + return nullptr; } // NOLINTNEXTLINE(readability-convert-member-functions-to-static) @@ -865,7 +899,7 @@ class replay_step_state_access : public i_state_access(index); if (!m_pmas[i]) { - m_pmas[i] = build_mock_pma_entry(index, istart, ilength); + m_pmas[i] = mock_pma_entry(index, istart, ilength); } // NOLINTNEXTLINE(bugprone-unchecked-optional-access) return m_pmas[i].value(); @@ -876,61 +910,6 @@ class replay_step_state_access : public i_state_accessread(pma.get_device_context(), &da, offset, pval, log2_size); - } - - execute_status do_write_device(mock_pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t val, int log2_size) { - device_state_access da(*this, mcycle); - return pma.get_device_driver()->write(pma.get_device_context(), &da, offset, val, log2_size); - } - - // NOLINTNEXTLINE(readability-convert-member-functions-to-static) - mock_pma_entry build_mock_pma_entry(uint64_t index, uint64_t istart, uint64_t ilength) { - uint64_t start{}; - mock_pma_entry::flags flags{}; - split_istart(istart, start, flags); - const pma_driver *driver = nullptr; - void *device_ctx = nullptr; - if (flags.IO) { - switch (flags.DID) { - case PMA_ISTART_DID::shadow_state: - driver = &shadow_state_driver; - break; - case PMA_ISTART_DID::shadow_TLB: - driver = &shadow_tlb_driver; - break; - case PMA_ISTART_DID::CLINT: - driver = &clint_driver; - break; - case PMA_ISTART_DID::PLIC: - driver = &plic_driver; - break; - case PMA_ISTART_DID::HTIF: - driver = &htif_driver; - break; - default: - interop_throw_runtime_error("Unsupported device in build_mock_pma_entry"); - break; - } - } - return mock_pma_entry{index, start, ilength, flags, driver, device_ctx}; - } - - static constexpr void split_istart(uint64_t istart, uint64_t &start, mock_pma_entry::flags &f) { - f.M = ((istart & PMA_ISTART_M_MASK) >> PMA_ISTART_M_SHIFT) != 0; - f.IO = ((istart & PMA_ISTART_IO_MASK) >> PMA_ISTART_IO_SHIFT) != 0; - f.E = ((istart & PMA_ISTART_E_MASK) >> PMA_ISTART_E_SHIFT) != 0; - f.R = ((istart & PMA_ISTART_R_MASK) >> PMA_ISTART_R_SHIFT) != 0; - f.W = ((istart & PMA_ISTART_W_MASK) >> PMA_ISTART_W_SHIFT) != 0; - f.X = ((istart & PMA_ISTART_X_MASK) >> PMA_ISTART_X_SHIFT) != 0; - f.IR = ((istart & PMA_ISTART_IR_MASK) >> PMA_ISTART_IR_SHIFT) != 0; - f.IW = ((istart & PMA_ISTART_IW_MASK) >> PMA_ISTART_IW_SHIFT) != 0; - f.DID = static_cast((istart & PMA_ISTART_DID_MASK) >> PMA_ISTART_DID_SHIFT); - start = istart & PMA_ISTART_START_MASK; - } - template volatile tlb_hot_entry &do_get_tlb_hot_entry(uint64_t eidx) { auto addr = tlb_get_entry_hot_abs_addr(eidx); diff --git a/src/state-access.h b/src/state-access.h index 7868e5e6..fd2a5cd6 100644 --- a/src/state-access.h +++ b/src/state-access.h @@ -500,18 +500,6 @@ class state_access : public i_state_access { return m_m.get_state().pmas[static_cast(index)]; } - bool do_read_device(pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t *pval, int log2_size) { - device_state_access da(*this, mcycle); - return pma.get_device_noexcept().get_driver()->read(pma.get_device_noexcept().get_context(), &da, offset, pval, - log2_size); - } - - execute_status do_write_device(pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t val, int log2_size) { - device_state_access da(*this, mcycle); - return pma.get_device_noexcept().get_driver()->write(pma.get_device_noexcept().get_context(), &da, offset, val, - log2_size); - } - template bool do_translate_vaddr_via_tlb(uint64_t vaddr, unsigned char **phptr) { const uint64_t eidx = tlb_get_entry_index(vaddr); diff --git a/uarch/uarch-machine-state-access.h b/uarch/uarch-machine-state-access.h index 65b04da9..da9d20e2 100644 --- a/uarch/uarch-machine-state-access.h +++ b/uarch/uarch-machine-state-access.h @@ -14,8 +14,8 @@ // with this program (see COPYING). If not, see . // -#ifndef uarch_machine_state_access_H -#define uarch_machine_state_access_H +#ifndef UARCH_MACHINE_STATE_ACCESS_H +#define UARCH_MACHINE_STATE_ACCESS_H #include "uarch-runtime.h" // must be included first, because of assert @@ -50,6 +50,8 @@ static void raw_write_memory(uint64_t paddr, T val) { *p = val; } +//??D can we merge this class with the mock_pma_entry in src/replay-step-state-access.h ? +//??D maybe implement base class in pma.h and subclass here if there is some minor difference? class uarch_pma_entry final { public: struct flags { @@ -65,28 +67,61 @@ class uarch_pma_entry final { }; private: - int m_pma_index{-1}; - uint64_t m_start{}; - uint64_t m_length{}; + + uint64_t m_pma_index; + uint64_t m_start; + uint64_t m_length; flags m_flags; - const pma_driver *m_device_driver{}; - void *m_device_context{}; + const pma_driver *m_driver{nullptr}; + + static constexpr flags split_flags(uint64_t istart) { + flags f{}; + f.M = (((istart & PMA_ISTART_M_MASK) >> PMA_ISTART_M_SHIFT) != 0); + f.IO = (((istart & PMA_ISTART_IO_MASK) >> PMA_ISTART_IO_SHIFT) != 0); + f.E = (((istart & PMA_ISTART_E_MASK) >> PMA_ISTART_E_SHIFT) != 0); + f.R = (((istart & PMA_ISTART_R_MASK) >> PMA_ISTART_R_SHIFT) != 0); + f.W = (((istart & PMA_ISTART_W_MASK) >> PMA_ISTART_W_SHIFT) != 0); + f.X = (((istart & PMA_ISTART_X_MASK) >> PMA_ISTART_X_SHIFT) != 0); + f.IR = (((istart & PMA_ISTART_IR_MASK) >> PMA_ISTART_IR_SHIFT) != 0); + f.IW = (((istart & PMA_ISTART_IW_MASK) >> PMA_ISTART_IW_SHIFT) != 0); + f.DID = static_cast((istart & PMA_ISTART_DID_MASK) >> PMA_ISTART_DID_SHIFT); + return f; + } public: - uarch_pma_entry(int pma_index, uint64_t start, uint64_t length, flags flags, - const pma_driver *pma_driver = nullptr, void *device_context = nullptr) : - m_pma_index{pma_index}, - m_start{start}, - m_length{length}, - m_flags{flags}, - m_device_driver{pma_driver}, - m_device_context{device_context} {} - uarch_pma_entry() : uarch_pma_entry(-1, 0, 0, {false, false, true /* empty */}) { - ; + uarch_pma_entry(uint64_t pma_index, uint64_t istart, uint64_t ilength) : + m_pma_index{pma_index}, + m_start{istart & PMA_ISTART_START_MASK}, + m_length{ilength}, + m_flags{split_flags(istart)}, + m_driver{nullptr} { + if (m_flags.IO) { + switch (m_flags.DID) { + case PMA_ISTART_DID::shadow_state: + m_driver = &shadow_state_driver; + break; + case PMA_ISTART_DID::shadow_TLB: + m_driver = &shadow_tlb_driver; + break; + case PMA_ISTART_DID::CLINT: + m_driver = &clint_driver; + break; + case PMA_ISTART_DID::PLIC: + m_driver = &plic_driver; + break; + case PMA_ISTART_DID::HTIF: + m_driver = &htif_driver; + break; + default: + // Other unsupported device in uarch (eg. VirtIO) + abort(); + break; + } + } } - int get_index() const { + uint64_t get_index() const { return m_pma_index; } @@ -130,12 +165,16 @@ class uarch_pma_entry final { return m_flags.IR; } - const pma_driver *get_device_driver() { - return m_device_driver; + const pma_driver *get_driver() const { + return m_driver; + } + + const auto &get_device_noexcept() const { + return *this; } - void *get_device_context() { - return m_device_context; + static void *get_context() { + return nullptr; } void mark_dirty_page(uint64_t /*address_in_range*/) { @@ -531,75 +570,22 @@ class uarch_machine_state_access : public i_state_access(index); + if (!m_pmas[i]) { + m_pmas[i] = uarch_pma_entry{index, istart, ilength}; } // NOLINTNEXTLINE(bugprone-unchecked-optional-access) - return m_pmas[index].value(); + return m_pmas[i].value(); } unsigned char *do_get_host_memory(uarch_pma_entry &/*pma*/) { return nullptr; } - bool do_read_device(uarch_pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t *pval, int log2_size) { - device_state_access da(*this, mcycle); - return pma.get_device_driver()->read(pma.get_device_context(), &da, offset, pval, log2_size); - } - - execute_status do_write_device(uarch_pma_entry &pma, uint64_t mcycle, uint64_t offset, uint64_t val, int log2_size) { - device_state_access da(*this, mcycle); - return pma.get_device_driver()->write(pma.get_device_context(), &da, offset, val, log2_size); - } - - uarch_pma_entry build_uarch_pma_entry(int index, uint64_t istart, uint64_t ilength) { - uint64_t start = 0; - uarch_pma_entry::flags flags; - split_istart(istart, start, flags); - const pma_driver *driver = nullptr; - void *device_ctx = nullptr; - if (flags.IO) { - switch (flags.DID) { - case PMA_ISTART_DID::shadow_state: - driver = &shadow_state_driver; - break; - case PMA_ISTART_DID::shadow_TLB: - driver = &shadow_tlb_driver; - break; - case PMA_ISTART_DID::CLINT: - driver = &clint_driver; - break; - case PMA_ISTART_DID::PLIC: - driver = &plic_driver; - break; - case PMA_ISTART_DID::HTIF: - driver = &htif_driver; - break; - default: - // Other unsupported device in uarch (eg. VirtIO) - abort(); - break; - } - } - return uarch_pma_entry{index, start, ilength, flags, driver, device_ctx}; - } - - static constexpr void split_istart(uint64_t istart, uint64_t &start, uarch_pma_entry::flags &f) { - f.M = (((istart & PMA_ISTART_M_MASK) >> PMA_ISTART_M_SHIFT) != 0); - f.IO = (((istart & PMA_ISTART_IO_MASK) >> PMA_ISTART_IO_SHIFT) != 0); - f.E = (((istart & PMA_ISTART_E_MASK) >> PMA_ISTART_E_SHIFT) != 0); - f.R = (((istart & PMA_ISTART_R_MASK) >> PMA_ISTART_R_SHIFT) != 0); - f.W = (((istart & PMA_ISTART_W_MASK) >> PMA_ISTART_W_SHIFT) != 0); - f.X = (((istart & PMA_ISTART_X_MASK) >> PMA_ISTART_X_SHIFT) != 0); - f.IR = (((istart & PMA_ISTART_IR_MASK) >> PMA_ISTART_IR_SHIFT) != 0); - f.IW = (((istart & PMA_ISTART_IW_MASK) >> PMA_ISTART_IW_SHIFT) != 0); - f.DID = static_cast((istart & PMA_ISTART_DID_MASK) >> PMA_ISTART_DID_SHIFT); - start = istart & PMA_ISTART_START_MASK; - } - template volatile tlb_hot_entry& do_get_tlb_hot_entry(uint64_t eidx) { // Volatile is used, so the compiler does not optimize out, or do of order writes.