Skip to content

Commit

Permalink
feat: Replace uarch mmio with ecall
Browse files Browse the repository at this point in the history
  • Loading branch information
mpernambuco committed Mar 12, 2024
1 parent 9983630 commit fe558c6
Show file tree
Hide file tree
Showing 21 changed files with 350 additions and 254 deletions.
2 changes: 2 additions & 0 deletions src/clua-cartesi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ CM_API int luaopen_cartesi(lua_State *L) {
clua_setintegerfield(L, UARCH_SHADOW_LENGTH, "UARCH_SHADOW_LENGTH", -1);
clua_setintegerfield(L, UARCH_RAM_LENGTH, "UARCH_RAM_LENGTH", -1);
clua_setintegerfield(L, UARCH_RAM_START_ADDRESS, "UARCH_RAM_START_ADDRESS", -1);
clua_setintegerfield(L, UARCH_ECALL_FN_HALT, "UARCH_ECALL_FN_HALT", -1);
clua_setintegerfield(L, UARCH_ECALL_FN_PUTCHAR, "UARCH_ECALL_FN_PUTCHAR", -1);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
clua_setlstringfield(L, reinterpret_cast<const char *>(uarch_pristine_hash), uarch_pristine_hash_len,
"UARCH_PRISTINE_STATE_HASH", -1);
Expand Down
98 changes: 2 additions & 96 deletions src/uarch-bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class uarch_bridge {
/// \details \{
/// An exception is thrown if paddr can't me mapped to a valid state register.
//// \}
static void write_register(uint64_t paddr, machine_state &s, uarch_state &us, uint64_t data) {
static void write_register(uint64_t paddr, machine_state &s, uint64_t data) {
if (try_write_x(s, paddr, data)) {
return;
}
Expand All @@ -47,9 +47,6 @@ class uarch_bridge {
if (try_write_tlb(s, paddr, data)) {
return;
}
if (try_write_uarch_state(us, paddr, data)) {
return;
}
switch (static_cast<shadow_state_csr>(paddr)) {
case shadow_state_csr::pc:
s.pc = data;
Expand Down Expand Up @@ -150,27 +147,17 @@ class uarch_bridge {
default:
break;
}
switch (static_cast<uarch_mmio_address>(paddr)) {
case uarch_mmio_address::putchar:
return uarch_putchar(data);
case uarch_mmio_address::abort:
if (data != uarch_mmio_abort_value) {
throw std::runtime_error("invalid write attempt to microarchitecture abort address");
}
return uarch_abort();
}
throw std::runtime_error("invalid write memory access from microarchitecture");
}

/// \brief Reads a machine state register.
/// \param s Machine state.
/// \param us Microarchitecture (uarch) state.
/// \param paddr Address that identifies the machine register to be read.
/// \param data Receives the state register value.
/// \details \{
/// An exception is thrown if paddr can't me mapped to a valid state register.
//// \}
static uint64_t read_register(uint64_t paddr, machine_state &s, uarch_state &us) {
static uint64_t read_register(uint64_t paddr, machine_state &s) {
uint64_t data = 0;
if (try_read_x(s, paddr, &data)) {
return data;
Expand All @@ -184,9 +171,6 @@ class uarch_bridge {
if (try_read_pma(s, paddr, &data)) {
return data;
}
if (try_read_uarch_state(us, paddr, &data)) {
return data;
}
switch (static_cast<shadow_state_csr>(paddr)) {
case shadow_state_csr::pc:
return s.pc;
Expand Down Expand Up @@ -267,12 +251,6 @@ class uarch_bridge {
default:
break;
}
switch (static_cast<uarch_mmio_address>(paddr)) {
case uarch_mmio_address::putchar:
return 0;
case uarch_mmio_address::abort:
return 0;
}
throw std::runtime_error("invalid read memory access from microarchitecture");
}

Expand Down Expand Up @@ -360,21 +338,6 @@ class uarch_bridge {
default:
break;
}
switch (static_cast<uarch_mmio_address>(paddr)) {
case uarch_mmio_address::putchar:
return "uarch.putchar";
case uarch_mmio_address::abort:
return "uarch.abort";
}
if (paddr >= PMA_SHADOW_UARCH_STATE_START &&
paddr < PMA_SHADOW_UARCH_STATE_START + PMA_SHADOW_UARCH_STATE_LENGTH) {
switch (static_cast<shadow_uarch_state_csr>(paddr - PMA_SHADOW_UARCH_STATE_START)) {
case shadow_uarch_state_csr::halt_flag:
return "uarch.halt_flag";
default:
break;
}
}
if (paddr >= shadow_state_get_x_abs_addr(0) && paddr <= shadow_state_get_x_abs_addr(X_REG_COUNT - 1) &&
(paddr & 0b111) == 0) {
return "x";
Expand Down Expand Up @@ -662,48 +625,6 @@ class uarch_bridge {
}
}

/// \brief Tries to read a uarch CSR
/// \param us uarch state.
/// \param paddr Absolute address of the TLB entry fieldwithin shadow TLB range
/// \param data Pointer to word receiving value.
/// \return true if the register was successfully read
static bool try_read_uarch_state(uarch_state &us, uint64_t paddr, uint64_t *data) {
if (paddr < PMA_SHADOW_UARCH_STATE_START ||
paddr >= PMA_SHADOW_UARCH_STATE_START + PMA_SHADOW_UARCH_STATE_LENGTH) {
return false;
}
switch (static_cast<shadow_uarch_state_csr>(paddr - PMA_SHADOW_UARCH_STATE_START)) {
case shadow_uarch_state_csr::halt_flag:
*data = us.halt_flag;
return true;
default:
break;
}
return false;
}

/// \brief Tries to write a uarch CSR
/// \param us uarch state.
/// \param paddr Absolute address of the PMA entry property within shadow PMAs range
/// \param data Data to write
/// \return true if the register was successfully written
static bool try_write_uarch_state(uarch_state &us, uint64_t paddr, uint64_t data) {
if (paddr < PMA_SHADOW_UARCH_STATE_START ||
paddr >= PMA_SHADOW_UARCH_STATE_START + PMA_SHADOW_UARCH_STATE_LENGTH) {
return false;
}

if (static_cast<shadow_uarch_state_csr>(paddr - PMA_SHADOW_UARCH_STATE_START) ==
shadow_uarch_state_csr::halt_flag) {
if (data != uarch_halt_flag_halt_value) {
throw std::runtime_error("invalid value written microarchitecture halt flag");
}
uarch_halt(us);
return true;
}
return false;
}

/// \brief Obtain PMA entry that covers a given physical memory region
/// \tparam T Type of word.
/// \param s Mmachine state.
Expand All @@ -724,21 +645,6 @@ class uarch_bridge {
// Last PMA is always the empty range
return s.pmas.back();
}

/// \brief Writes a character to the console
static void uarch_putchar(uint64_t data) {
putchar(static_cast<char>(data));
}

/// \brief Halt request received from uarch
static void uarch_halt(uarch_state &us) {
us.halt_flag = true;
}

/// \brief Abort request received from uarch
static void uarch_abort() {
throw std::runtime_error("microarchitecture execution aborted");
}
};

} // namespace cartesi
Expand Down
14 changes: 4 additions & 10 deletions src/uarch-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,12 @@ static_assert((UARCH_SHADOW_LENGTH & (PMA_PAGE_SIZE - 1)) == 0,
"UARCH_SHADOW_LENGTH must be multiple of PMA_PAGE_SIZE");
static_assert((UARCH_RAM_LENGTH & (PMA_PAGE_SIZE - 1)) == 0, "UARCH_RAM_LENGTH must be multiple of PMA_PAGE_SIZE");

/// \briefThe value that halts the microarchitecture when written to shadow_state_csr::uarch_halt_flag:
constexpr uint64_t uarch_halt_flag_halt_value = UARCH_HALT_FLAG_HALT_VALUE_DEF;

/// \brief Memory addresses with special meaning to the microarchitecture
enum class uarch_mmio_address : uint64_t {
putchar = UARCH_MMIO_PUTCHAR_ADDR_DEF, ///< Write to this address for printing characters to the console
abort = UARCH_MMIO_ABORT_ADDR_DEF, ///< Write to this address to abort execution of the micro machine
/// \brief ecall function codes
enum uarch_ecall_functions : uint64_t {
UARCH_ECALL_FN_HALT = EXPAND_UINT64_C(UARCH_ECALL_FN_HALT_DEF), ///< halt uarch execution
UARCH_ECALL_FN_PUTCHAR = EXPAND_UINT64_C(UARCH_ECALL_FN_PUTCHAR_DEF), //< putchar
};

/// \briefThe value that aborts the micro machine execution written to uarch_mmio_address::abort
constexpr uint64_t uarch_mmio_abort_value = UARCH_MMIO_ABORT_VALUE_DEF;

} // namespace cartesi

#endif
19 changes: 3 additions & 16 deletions src/uarch-defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,9 @@
/// \brief Log2 size of the entire uarch memory range: shadow and ram
#define UARCH_STATE_LOG2_SIZE_DEF 22

/// \brief The address of uarch halt flag is the first dword in shadow uarch state
#define UARCH_HALT_FLAG_SHADOW_ADDR_DEF PMA_SHADOW_UARCH_STATE_START_DEF
// microarchitecture ecall function codes
#define UARCH_ECALL_FN_HALT_DEF 1 // halt uarch
#define UARCH_ECALL_FN_PUTCHAR_DEF 2 // putchar

/// \brief The value that halts the microarchitecture when written to UARCH_HALT_FLAG_SHADOW_ADDR_DEF
#define UARCH_HALT_FLAG_HALT_VALUE_DEF 1

/// \brief Base of microarchitecture special addresses
#define UARCH_MMIO_START_DEF 0x7ffff000 ///< Start of microarchitecture memory mapped IO addresses

/// \brief Abort execution of microarchitecture by writing to this address
#define UARCH_MMIO_ABORT_ADDR_DEF (UARCH_MMIO_START_DEF + 0)

/// \brief The value that aborts execution of the micro machine when written to UARCH_MMIO_ABORT_ADDR_DEF
#define UARCH_MMIO_ABORT_VALUE_DEF 1

/// \brief Prints a character to to console when written to UARCH_MMIO_HALT_ADDR_DEF
#define UARCH_MMIO_PUTCHAR_ADDR_DEF (UARCH_MMIO_START_DEF + 8)
// NOLINTEND(cppcoreguidelines-macro-usage,modernize-macro-to-enum)
#endif /* end of include guard: UARCH_DEFINES_H */
6 changes: 3 additions & 3 deletions src/uarch-record-step-state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ class uarch_record_step_state_access : public i_uarch_step_state_access<uarch_re
/// \param paddr Address of the state register
/// \param data Pointer receiving register value
uint64_t read_register(uint64_t paddr) {
auto data = uarch_bridge::read_register(paddr, m_s, m_us);
auto data = uarch_bridge::read_register(paddr, m_s);
const auto *name = uarch_bridge::get_register_name(paddr);
log_read(paddr, data, name);
return data;
Expand Down Expand Up @@ -376,10 +376,10 @@ class uarch_record_step_state_access : public i_uarch_step_state_access<uarch_re
/// \param paddr Address of the state register
/// \param data New register value
void write_register(uint64_t paddr, uint64_t data) {
auto old_data = uarch_bridge::read_register(paddr, m_s, m_us);
auto old_data = uarch_bridge::read_register(paddr, m_s);
const auto *name = uarch_bridge::get_register_name(paddr);
log_before_write(paddr, old_data, data, name);
uarch_bridge::write_register(paddr, m_s, m_us, data);
uarch_bridge::write_register(paddr, m_s, data);
update_after_write(paddr);
}

Expand Down
13 changes: 13 additions & 0 deletions src/uarch-solidity-compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef UARCH_INTERPRET_SOLIDITY_COMPAT_H
#define UARCH_INTERPRET_SOLIDITY_COMPAT_H

#include "os.h"
#include <cassert>

/// \file
Expand Down Expand Up @@ -95,6 +96,18 @@ static inline void resetState(UarchState &a) {
a.reset_state();
}

template <typename UarchState>
static inline void throwRuntimeError(UarchState &a, const char *message) {
(void) a;
throw std::runtime_error(message);
}

template <typename UarchState>
static inline void putChar(UarchState &a, unsigned char c) {
(void) a;
os_putchar(c);
}

// Conversions and arithmetic functions

static inline int32 uint64ToInt32(uint64 v) {
Expand Down
4 changes: 2 additions & 2 deletions src/uarch-step-state-access.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ class uarch_step_state_access : public i_uarch_step_state_access<uarch_step_stat
/// \param paddr Address of the state register
/// \param data Pointer receiving register value
uint64_t read_register(uint64_t paddr) {
return uarch_bridge::read_register(paddr, m_s, m_us);
return uarch_bridge::read_register(paddr, m_s);
}

/// \brief Fallback to error on all other word sizes
Expand All @@ -173,7 +173,7 @@ class uarch_step_state_access : public i_uarch_step_state_access<uarch_step_stat
/// \param paddr Address of the state register
/// \param data New register value
void write_register(uint64_t paddr, uint64_t data) {
return uarch_bridge::write_register(paddr, m_s, m_us, data);
return uarch_bridge::write_register(paddr, m_s, data);
}
};

Expand Down
31 changes: 28 additions & 3 deletions src/uarch-step.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,31 @@ static inline void executeSD(UarchState &a, uint32 insn, uint64 pc) {
return advancePc(a, pc);
}

template <typename UarchState>
static inline void executeECALL(UarchState &a, uint32 insn, uint64 pc) {
dumpInsn(a, pc, insn, "ecall");
auto note = a.make_scoped_note("ecall");
(void) note;
uint64 function = readX(a, 17); // a7 contains the function number
if (function == UARCH_ECALL_FN_HALT) {
setHaltFlag(a);
} else if (function == UARCH_ECALL_FN_PUTCHAR) {
uint64 character = readX(a, 16); // a6 contains the character to print
putChar(a, uint8(character));
} else {
throwRuntimeError(a, "unsupported ecall function");
}
return advancePc(a, pc);
}

template <typename UarchState>
static inline void executeEBREAK(UarchState &a, uint32 insn, uint64 pc) {
dumpInsn(a, pc, insn, "ebreak");
auto note = a.make_scoped_note("ebreak");
(void) note;
throwRuntimeError(a, "uarch aborted");
}

/// \brief Returns true if the opcode field of an instruction matches the provided argument
static inline bool insnMatchOpcode(uint32 insn, uint32 opcode) {
return ((insn & 0x7f)) == opcode;
Expand Down Expand Up @@ -1086,11 +1111,11 @@ static inline void executeInsn(UarchState &a, uint32 insn, uint64 pc) {
} else if (insnMatchOpcodeFunct3(insn, 0xf, 0x0)) {
return executeFENCE(a, insn, pc);
} else if (insn == uint32(0x73)) {
throw std::runtime_error("ECALL is not supported");
return executeECALL(a, insn, pc);
} else if (insn == uint32(0x100073)) {
throw std::runtime_error("EBREAK is not supported");
return executeEBREAK(a, insn, pc);
}
throw std::runtime_error("illegal instruction");
throwRuntimeError(a, "illegal instruction");
}

template <typename UarchState>
Expand Down
9 changes: 2 additions & 7 deletions tests/lua/cartesi/tests/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,10 @@ end

local ZERO_PAGE = string.rep("\x00", PAGE_SIZE)

-- Encodes: li t0, UARCH_HALT_FLAG_SHADOW_ADDR
-- The halt flag is located at the first dword starting from UARCH_SHADOW_START_ADDRESS
local li_t0_UARCH_SHADOW_START_ADDRESS = ((cartesi.UARCH_SHADOW_START_ADDRESS >> 12) << 12) | 0x02b7

test_util.uarch_programs = {
halt = {
li_t0_UARCH_SHADOW_START_ADDRESS, -- li t0,UARCH_HALT_FLAG_SHADOW_ADDR
0x00100313, -- li t1,1 UARCH_MMIO_HALT_VALUE
0x0062b023, -- sd t1,0(t0) Halt uarch
(cartesi.UARCH_ECALL_FN_HALT << 20) | 0x00893, -- li a7,halt
0x00000073, -- ecall
},
}

Expand Down
Loading

0 comments on commit fe558c6

Please sign in to comment.