diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index dfe2b573d..3a8b7fe03 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -41,8 +41,6 @@ jobs:
tags: ${{ github.repository_owner }}/machine-emulator:devel.build
push: false
load: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
@@ -60,8 +58,6 @@ jobs:
tags: cartesi/machine-emulator:amd64_deb
push: false
load: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
@@ -82,8 +78,6 @@ jobs:
tags: cartesi/machine-emulator:arm64_deb
push: false
load: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
@@ -146,8 +140,6 @@ jobs:
tags: ${{ github.repository_owner }}/machine-emulator:builder
push: false
load: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
@@ -164,8 +156,6 @@ jobs:
tags: ${{ github.repository_owner }}/machine-emulator:devel
push: false
load: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
@@ -321,8 +311,6 @@ jobs:
tags: ${{ github.repository_owner }}/machine-emulator:builder
push: false
load: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
@@ -339,8 +327,6 @@ jobs:
tags: ${{ github.repository_owner }}/machine-emulator:devel
push: false
load: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
@@ -478,8 +464,6 @@ jobs:
tags: ${{ github.repository_owner }}/machine-emulator:devel
push: false
load: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
@@ -541,8 +525,6 @@ jobs:
tags: ${{ github.repository_owner }}/machine-emulator:builder
push: false
load: true
- cache-from: type=gha,scope=debian-coverage
- cache-to: type=gha,mode=max,scope=debian-coverage
build-args: |
GIT_COMMIT=${GITHUB_SHA}
DEBUG=yes
@@ -623,8 +605,6 @@ jobs:
tags: ${{ github.repository_owner }}/machine-emulator:builder
push: false
load: true
- cache-from: type=gha,scope=debian-sanitize
- cache-to: type=gha,mode=max,scope=debian-sanitize
build-args: |
DEBUG=yes
GIT_COMMIT=${GITHUB_SHA}
@@ -703,8 +683,6 @@ jobs:
platforms: linux/amd64,linux/arm64
tags: ${{ steps.docker_image_tags.outputs.tags }}
push: true
- cache-from: type=gha,scope=debian
- cache-to: type=gha,mode=max,scope=debian
build-args: |
DEBUG=${{ (startsWith(github.ref, 'refs/tags/v') && 'no' || 'yes') }}
GIT_COMMIT=${GITHUB_SHA}
diff --git a/.gitignore b/.gitignore
index 80177f4d5..ef549f836 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
*.a
*.lib
*.wasm
+*.TODO
build
pkg
diff --git a/src/Makefile b/src/Makefile
index e183c8b51..c4b2a54fa 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -151,7 +151,8 @@ HASH_LIBS=
#DEFS+= -DMT_ALL_DIRTY
-WARNS=-Wall -Wextra -Wpedantic
+C_WARNS=-Wall -Wextra -Wpedantic
+CXX_WARNS=$(C_WARNS) -Wno-missing-field-initializers
# Place our include directories before the system's
INCS+= \
@@ -305,8 +306,8 @@ else
DEFS+=-DNO_THREADS
endif
-CXXFLAGS+=$(OPTFLAGS) -std=gnu++20 -fvisibility=hidden -MMD $(PICCFLAGS) $(CC_MARCH) $(INCS) $(GCFLAGS) $(UBFLAGS) $(DEFS) $(WARNS)
-CFLAGS+=$(OPTFLAGS) -std=gnu99 -fvisibility=hidden -MMD $(PICCFLAGS) $(CC_MARCH) $(INCS) $(GCFLAGS) $(UBFLAGS) $(DEFS) $(WARNS)
+CXXFLAGS+=$(OPTFLAGS) -std=gnu++20 -fvisibility=hidden -MMD $(PICCFLAGS) $(CC_MARCH) $(INCS) $(GCFLAGS) $(UBFLAGS) $(DEFS) $(CXX_WARNS)
+CFLAGS+=$(OPTFLAGS) -std=gnu99 -fvisibility=hidden -MMD $(PICCFLAGS) $(CC_MARCH) $(INCS) $(GCFLAGS) $(UBFLAGS) $(DEFS) $(C_WARNS)
LDFLAGS+=$(UBFLAGS)
ifeq ($(coverage),yes)
@@ -357,14 +358,12 @@ LIBCARTESI_OBJS:= \
machine.o \
memory-address-range.o \
os.o \
+ os-mmap.o \
plic-address-range.o \
pristine-merkle-tree.o \
replay-step-state-access-interop.o \
send-cmio-response.o \
sha3.o \
- shadow-state-address-range.o \
- shadow-tlb-address-range.o \
- shadow-uarch-state-address-range.o \
uarch-pristine-hash.o \
uarch-pristine-ram.o \
uarch-pristine-state-hash.o \
diff --git a/src/address-range-constants.h b/src/address-range-constants.h
index 1c4fdb65f..77f07e279 100644
--- a/src/address-range-constants.h
+++ b/src/address-range-constants.h
@@ -25,14 +25,16 @@ namespace cartesi {
/// \brief Fixed address ranges.
enum AR_ranges : uint64_t {
- AR_SHADOW_STATE_START = EXPAND_UINT64_C(AR_SHADOW_STATE_START_DEF), ///< Start of shadow state range
- AR_SHADOW_STATE_LENGTH = EXPAND_UINT64_C(AR_SHADOW_STATE_LENGTH_DEF), ///< Length of shadow state range
- AR_PMAS_START = EXPAND_UINT64_C(AR_PMAS_START_DEF), ///< Start of PMAS list range
- AR_PMAS_LENGTH = EXPAND_UINT64_C(AR_PMAS_LENGTH_DEF), ///< Length of PMAS list range
- AR_DTB_START = EXPAND_UINT64_C(AR_DTB_START_DEF), ///< Start of DTB range
- AR_DTB_LENGTH = EXPAND_UINT64_C(AR_DTB_LENGTH_DEF), ///< Length of DTB range
- AR_SHADOW_TLB_START = EXPAND_UINT64_C(AR_SHADOW_TLB_START_DEF), ///< Start of shadow TLB range
- AR_SHADOW_TLB_LENGTH = EXPAND_UINT64_C(AR_SHADOW_TLB_LENGTH_DEF), ///< Length of shadow TLB range
+ AR_SHADOW_STATE_START = EXPAND_UINT64_C(AR_SHADOW_STATE_START_DEF), ///< Start of shadow state range
+ AR_SHADOW_STATE_LENGTH = EXPAND_UINT64_C(AR_SHADOW_STATE_LENGTH_DEF), ///< Length of shadow state range
+ AR_SHADOW_REGISTERS_START = EXPAND_UINT64_C(AR_SHADOW_REGISTERS_START_DEF), ///< Start of shadow registers range
+ AR_SHADOW_REGISTERS_LENGTH = EXPAND_UINT64_C(AR_SHADOW_REGISTERS_LENGTH_DEF), ///< Length of shadow registers range
+ AR_SHADOW_TLB_START = EXPAND_UINT64_C(AR_SHADOW_TLB_START_DEF), ///< Start of shadow TLB range
+ AR_SHADOW_TLB_LENGTH = EXPAND_UINT64_C(AR_SHADOW_TLB_LENGTH_DEF), ///< Length of shadow TLB range
+ AR_PMAS_START = EXPAND_UINT64_C(AR_PMAS_START_DEF), ///< Start of PMAS list range
+ AR_PMAS_LENGTH = EXPAND_UINT64_C(AR_PMAS_LENGTH_DEF), ///< Length of PMAS list range
+ AR_DTB_START = EXPAND_UINT64_C(AR_DTB_START_DEF), ///< Start of DTB range
+ AR_DTB_LENGTH = EXPAND_UINT64_C(AR_DTB_LENGTH_DEF), ///< Length of DTB range
AR_SHADOW_UARCH_STATE_START =
EXPAND_UINT64_C(AR_SHADOW_UARCH_STATE_START_DEF), ///< Start of uarch shadow state range
AR_SHADOW_UARCH_STATE_LENGTH =
@@ -61,6 +63,10 @@ enum AR_ranges : uint64_t {
AR_RAM_START = EXPAND_UINT64_C(AR_RAM_START_DEF), ///< Start of RAM range
};
+static_assert(AR_SHADOW_STATE_LENGTH >= AR_SHADOW_REGISTERS_LENGTH + AR_SHADOW_TLB_LENGTH);
+static_assert(AR_SHADOW_TLB_START == AR_SHADOW_REGISTERS_START + AR_SHADOW_REGISTERS_LENGTH);
+static_assert(AR_SHADOW_STATE_START == AR_SHADOW_REGISTERS_START);
+
/// \brief PMA constants.
enum AR_constants : uint64_t {
AR_PAGE_SIZE_LOG2 = EXPAND_UINT64_C(AR_PAGE_SIZE_LOG2_DEF), ///< Log2 of physical memory page size.
diff --git a/src/address-range-defines.h b/src/address-range-defines.h
index 4f49e9141..dd89cc9a9 100644
--- a/src/address-range-defines.h
+++ b/src/address-range-defines.h
@@ -19,11 +19,13 @@
// NOLINTBEGIN(cppcoreguidelines-macro-usage,cppcoreguidelines-macro-to-enum,modernize-macro-to-enum)
#define AR_SHADOW_STATE_START_DEF 0x0 ///< Shadow start address
-#define AR_SHADOW_STATE_LENGTH_DEF 0x1000 ///< Shadow length in bytes
+#define AR_SHADOW_STATE_LENGTH_DEF 0x8000 ///< Shadow length in bytes
+#define AR_SHADOW_REGISTERS_START_DEF 0x0 ///< Shadow registers start address
+#define AR_SHADOW_REGISTERS_LENGTH_DEF 0x1000 ///< Shadow registers length in bytes
+#define AR_SHADOW_TLB_START_DEF 0x1000 ///< Shadow TLB start address
+#define AR_SHADOW_TLB_LENGTH_DEF 0x6000 ///< Shadow TLB length in bytes
#define AR_PMAS_START_DEF 0x10000 ///< PMA Array start address
#define AR_PMAS_LENGTH_DEF 0x1000 ///< PMA Array length in bytes
-#define AR_SHADOW_TLB_START_DEF 0x20000 ///< TLB start address
-#define AR_SHADOW_TLB_LENGTH_DEF 0x6000 ///< TLB length in bytes
#define AR_SHADOW_UARCH_STATE_START_DEF 0x400000 ///< microarchitecture shadow state start address
#define AR_SHADOW_UARCH_STATE_LENGTH_DEF 0x1000 ///< microarchitecture shadow state length
#define AR_UARCH_RAM_START_DEF 0x600000 ///< microarchitecture RAM start address
diff --git a/src/address-range.h b/src/address-range.h
index be681ccfb..c179d387d 100644
--- a/src/address-range.h
+++ b/src/address-range.h
@@ -220,6 +220,20 @@ class address_range {
return m_flags.IW;
}
+ /// \brief Tests if range can be replaced
+ /// \returns True if and only if range can be replaced
+ bool is_replaceable() const noexcept {
+ switch (m_flags.DID) {
+ case PMA_ISTART_DID::memory:
+ case PMA_ISTART_DID::flash_drive:
+ case PMA_ISTART_DID::cmio_rx_buffer:
+ case PMA_ISTART_DID::cmio_tx_buffer:
+ return true;
+ default:
+ return false;
+ }
+ }
+
/// \brief Returns driver ID associated to range
/// \returns Teh driver ID
PMA_ISTART_DID get_driver_id() const noexcept {
@@ -327,6 +341,18 @@ class address_range {
return do_is_page_marked_dirty(offset);
}
+ /// \brief Returns true if the mapped memory is read-only on the host
+ /// \returns True if the memory is read-only in the host
+ bool is_host_read_only() const noexcept {
+ return do_is_host_read_only();
+ }
+
+ /// \brief Returns true if pages marked as dirty once are uncleanable
+ /// \returns True if and only if dirty pages are uncleanable
+ bool is_page_uncleanable() const noexcept {
+ return do_is_page_uncleanable();
+ }
+
private:
// Default implementation of peek() always fails
virtual bool do_peek(const machine & /*m*/, uint64_t /*offset*/, uint64_t /*length*/,
@@ -371,6 +397,14 @@ class address_range {
virtual bool do_is_page_marked_dirty(uint64_t /*offset*/) const noexcept {
return true;
}
+
+ virtual bool do_is_host_read_only() const noexcept {
+ return false;
+ }
+
+ virtual bool do_is_page_uncleanable() const noexcept {
+ return false;
+ }
};
template
diff --git a/src/cartesi-machine.lua b/src/cartesi-machine.lua
index a339a0985..9ac3e285e 100755
--- a/src/cartesi-machine.lua
+++ b/src/cartesi-machine.lua
@@ -107,6 +107,9 @@ where options are:
data_filename:
dht_filename:
shared
+ create
+ truncate
+ read_only
mount:
user:
@@ -137,6 +140,18 @@ where options are:
target modifications to flash drive modify the memory and hash tree files.
by default, image files are not modified and changes are lost.
+ create (optional)
+ create the backing storage file, shared must also be true.
+
+ truncate (optional)
+ truncate the memory length to match memory lengths different from the backing storage,
+ in case of shared flash drive, then it also truncates the underlying backing file.
+ by default, when a length is present it must also match the backing storage length.
+
+ read_only (optional)
+ mark flash drive as read-only, disallowing write attempts from the host or the guest.
+ by default, flash drives are not read-only, thus writable.
+
mount (optional)
whether the flash drive should be mounted automatically in init.
by default, the drive is mounted if there is an image file backing it,
@@ -171,11 +186,12 @@ where options are:
--ram=:[,:[,...]...]
--dtb=:[,:[,...]...]
- --tlb=:[,:[,...]...]
+ --processor=:[,:[,...]...]
--cmio-rx-buffer=:[,:[,...]...]
--cmio-tx-buffer=:[,:[,...]...]
--pmas=:[,:[,...]...]
--uarch-ram=:[,:[,...]...]
+ --uarch-processor=:[,:[,...]...]
configures file storage for other memory ranges in the machine
: is one of
@@ -471,6 +487,31 @@ where options are:
--load=
load machine previously stored in .
+ --init-shared=
+ initialize a machine sharing snapshot created in .
+ writable address ranges are shared, thus runtime modifications persist in the snapshot.
+ writable address ranges use reflinks on copy-on-write filesystems for efficient copying.
+ read-only address ranges use hard links to avoid unnecessary copying.
+ address ranges sparsity is preserved to minimize host storage usage.
+
+ MUST BE USED WITH --no-rollback
+
+ --load-shared=
+ load an existing machine sharing snapshot from ,
+ writable address ranges are shared, thus runtime modifications persists in the snapshot.
+ address ranges sparsity is preserved to minimize host storage usage.
+
+ MUST BE USED WITH --no-rollback
+
+ --clone-shared=,
+ clones a snapshot from source directory to destination directory and load a machine sharing it.
+ writable address ranges are shared, thus runtime modifications persist in the snapshot.
+ writable address ranges use reflinks on copy-on-write filesystems for efficient copying.
+ read-only address ranges use hard links to avoid unnecessary copying.
+ address ranges sparsity is preserved to minimize host storage usage.
+
+ MUST BE USED WITH --no-rollback
+
--initial-hash
print initial state hash before running machine.
@@ -614,6 +655,9 @@ local flash_data_filename = { root = images_path .. "rootfs.ext2" }
local flash_dht_filename = {}
local flash_label_order = { "root" }
local flash_shared = {}
+local flash_create = {}
+local flash_truncate = {}
+local flash_read_only = {}
local flash_mount = {}
local flash_user = {}
local flash_start = {}
@@ -1012,13 +1056,6 @@ local options = {
return true
end,
},
- {
- "^(%-%-tlb%=(.+))$",
- function(all, opts)
- tlb.backing_store = parse_backing_store(opts, "tlb", all, tlb.backing_store)
- return true
- end,
- },
{
"^(%-%-pmas%=(.+))$",
function(all, opts)
@@ -1146,6 +1183,9 @@ local options = {
data_filename = true,
dht_filename = true,
shared = true,
+ create = true,
+ truncate = true,
+ read_only = true,
mount = true,
user = true,
length = true,
@@ -1155,6 +1195,9 @@ local options = {
if f.data_filename == true then f.data_filename = "" end
if f.dht_filename == true then f.dht_filename = "" end
assert(not f.shared or f.shared == true, "invalid flash drive shared value in " .. all)
+ assert(not f.create or f.create == true, "invalid flash drive create value in " .. all)
+ assert(not f.truncate or f.truncate == true, "invalid flash drive read_only value in " .. all)
+ assert(not f.read_only or f.read_only == true, "invalid flash drive truncate value in " .. all)
if f.mount == nil then
-- mount only if there is a file backing
if f.data_filename and f.data_filename ~= "" then
@@ -1179,8 +1222,14 @@ local options = {
flash_start[d] = f.start or flash_start[d]
flash_length[d] = f.length or flash_length[d]
flash_shared[d] = f.shared or flash_shared[d]
+ flash_create[d] = f.create or flash_create[d]
+ flash_truncate[d] = f.truncate or flash_truncate[d]
+ flash_read_only[d] = f.read_only or flash_read_only[d]
flash_mount[d] = f.mount or flash_mount[d]
flash_user[d] = f.user or flash_user[d]
+ if d == "root" and f.read_only then -- Mount root filesystem as read-only
+ dtb.bootargs = dtb.bootargs:gsub("rw", "ro")
+ end
return true
end,
},
@@ -1335,6 +1384,9 @@ local options = {
flash_start.root = nil
flash_length.root = nil
flash_shared.root = nil
+ flash_create.root = nil
+ flash_truncate.root = nil
+ flash_read_only.root = nil
table.remove(flash_label_order, 1)
dtb.bootargs = dtb.bootargs:gsub(" root=$", "")
return true
@@ -1719,7 +1771,7 @@ end
local function dump_value_proofs(machine, desired_proofs, config)
if #desired_proofs > 0 then
- assert(config.processor.iunrep == 0, "proofs are meaningless in unreproducible mode")
+ assert(config.processor.registers.iunrep == 0, "proofs are meaningless in unreproducible mode")
end
for _, desired in ipairs(desired_proofs) do
local proof = machine:get_proof(desired.address, desired.log2_size)
@@ -1800,17 +1852,20 @@ else
-- Build machine config
local config = {
processor = {
- iunrep = unreproducible and 1 or 0,
+ registers = {
+ iunrep = unreproducible and 1 or 0,
+ htif = {
+ iconsole = (htif_console_getchar and cartesi.HTIF_CONSOLE_CMD_GETCHAR_MASK or 0)
+ | cartesi.HTIF_CONSOLE_CMD_PUTCHAR_MASK,
+ iyield = (htif_yield_automatic and cartesi.HTIF_YIELD_CMD_AUTOMATIC_MASK or 0)
+ | (htif_yield_manual and cartesi.HTIF_YIELD_CMD_MANUAL_MASK or 0),
+ },
+ },
},
ram = ram,
dtb = dtb,
flash_drive = {},
tlb = tlb,
- htif = {
- console_getchar = htif_console_getchar,
- yield_automatic = htif_yield_automatic,
- yield_manual = htif_yield_manual,
- },
virtio = virtio,
cmio = cmio,
pmas = pmas,
@@ -1843,7 +1898,10 @@ echo "
data_filename = flash_data_filename[label],
dht_filename = flash_dht_filename[label],
shared = flash_shared[label],
+ create = flash_create[label],
+ truncate = flash_truncate[label],
},
+ read_only = flash_read_only[label],
start = flash_start[label],
length = flash_length[label] or -1,
}
@@ -1990,15 +2048,20 @@ local cmio_yield_command = {
}
local function check_cmio_htif_config(htif)
- assert(not htif.console_getchar, "console getchar must be disabled for cmio")
- assert(htif.yield_manual, "yield manual must be enabled for cmio")
- assert(htif.yield_automatic, "yield automatic must be enabled for cmio")
+ assert((htif.iconsole & cartesi.HTIF_CONSOLE_CMD_GETCHAR_MASK) == 0, "console getchar must be disabled for cmio")
+ assert(
+ htif.iyield == (cartesi.HTIF_YIELD_CMD_MANUAL_MASK | cartesi.HTIF_YIELD_CMD_AUTOMATIC_MASK),
+ "yield manual must be enabled for cmio"
+ )
end
local function get_and_print_yield(machine, htif)
local cmd, reason, data = machine:receive_cmio_request()
if cmd == cartesi.CMIO_YIELD_COMMAND_AUTOMATIC and reason == cartesi.CMIO_YIELD_AUTOMATIC_REASON_PROGRESS then
- stderr("Progress: %6.2f" .. (htif.console_getchar and "\n" or "\r"), string.unpack("I4", data) / 10)
+ stderr(
+ "Progress: %6.2f" .. ((htif.iconsole & cartesi.HTIF_CONSOLE_CMD_GETCHAR_MASK) ~= 0 and "\n" or "\r"),
+ string.unpack("I4", data) / 10
+ )
return cmd, reason, data
end
local cmd_str = cmio_yield_command[cmd] or "Unknown"
@@ -2068,7 +2131,7 @@ local function save_cmio_inspect_state_report(inspect, data)
end
local function store_machine(machine, config, dir)
- assert(config.processor.iunrep == 0, "hashes are meaningless in unreproducible mode")
+ assert(config.processor.registers.iunrep == 0, "hashes are meaningless in unreproducible mode")
stderr("Storing machine: please wait\n")
local values = {}
if dir:find("%%h") then values.h = util.hexhash(machine:get_root_hash()) end
@@ -2097,13 +2160,13 @@ if gdb_address then
assert(address and port, "invalid address for GDB")
gdb_stub:listen_and_wait_gdb(address, tonumber(port))
end
-if config.processor.iunrep ~= 0 then stderr("Running in unreproducible mode!\n") end
+if config.processor.registers.iunrep ~= 0 then stderr("Running in unreproducible mode!\n") end
if cmio_advance or cmio_inspect then
- check_cmio_htif_config(config.htif)
+ check_cmio_htif_config(config.processor.registers.htif)
assert(remote_address or not perform_rollbacks, "cmio requires --remote-address for snapshot/commit/rollback")
end
if initial_hash then
- assert(config.processor.iunrep == 0, "hashes are meaningless in unreproducible mode")
+ assert(config.processor.registers.iunrep == 0, "hashes are meaningless in unreproducible mode")
print_root_hash(machine, stderr_unsilenceable)
end
dump_value_proofs(machine, initial_proof, config)
@@ -2190,7 +2253,7 @@ while math.ult(machine:read_reg("mcycle"), max_mcycle) do
break
-- deal with yield manual
elseif machine:read_reg("iflags_Y") ~= 0 then
- local _, reason, data = get_and_print_yield(machine, config.htif)
+ local _, reason, data = get_and_print_yield(machine, config.processor.registers.htif)
-- there was an exception
if reason == cartesi.CMIO_YIELD_MANUAL_REASON_TX_EXCEPTION then
stderr("cmio exception with payload: %q\n", data)
@@ -2254,7 +2317,7 @@ while math.ult(machine:read_reg("mcycle"), max_mcycle) do
end
-- deal with yield automatic
elseif machine:read_reg("iflags_X") ~= 0 then
- local _, reason, data = get_and_print_yield(machine, config.htif)
+ local _, reason, data = get_and_print_yield(machine, config.processor.registers.htif)
-- we have fed an advance state input
if cmio_advance and cmio_advance.next_input_index > cmio_advance.input_index_begin then
if reason == cartesi.CMIO_YIELD_AUTOMATIC_REASON_TX_OUTPUT then
@@ -2310,7 +2373,7 @@ if max_uarch_cycle > 0 then
end
if gdb_stub then gdb_stub:close() end
if log_step_uarch then
- assert(config.processor.iunrep == 0, "micro step proof is meaningless in unreproducible mode")
+ assert(config.processor.registers.iunrep == 0, "micro step proof is meaningless in unreproducible mode")
stderr("Gathering micro step log: please wait\n")
util.dump_log(machine:log_step_uarch(cartesi.ACCESS_LOG_TYPE_ANNOTATIONS), io.stderr)
end
@@ -2320,7 +2383,7 @@ if log_reset_uarch then
end
if dump_memory_ranges then dump_pmas(machine) end
if final_hash then
- assert(config.processor.iunrep == 0, "hashes are meaningless in unreproducible mode")
+ assert(config.processor.registers.iunrep == 0, "hashes are meaningless in unreproducible mode")
print_root_hash(machine, stderr_unsilenceable)
end
dump_value_proofs(machine, final_proof, config)
diff --git a/src/clua-cartesi.cpp b/src/clua-cartesi.cpp
index 1326f0806..5a196b45c 100644
--- a/src/clua-cartesi.cpp
+++ b/src/clua-cartesi.cpp
@@ -30,6 +30,7 @@ extern "C" {
#include "base64.h"
#include "clua-i-machine.h"
#include "clua.h"
+#include "htif-constants.h"
#include "keccak-256-hasher.h"
#include "machine-c-api.h"
#include "machine-c-version.h"
@@ -225,6 +226,12 @@ CM_API int luaopen_cartesi(lua_State *L) {
clua_setintegerfield(L, CM_AR_CMIO_TX_BUFFER_START, "AR_CMIO_TX_BUFFER_START", -1);
clua_setintegerfield(L, CM_AR_CMIO_TX_BUFFER_LOG2_SIZE, "AR_CMIO_TX_BUFFER_LOG2_SIZE", -1);
clua_setintegerfield(L, CM_AR_RAM_START, "AR_RAM_START", -1);
+ // HTIF masks
+ clua_setintegerfield(L, HTIF_HALT_CMD_HALT_MASK, "HTIF_HALT_CMD_HALT_MASK", -1);
+ clua_setintegerfield(L, HTIF_CONSOLE_CMD_GETCHAR_MASK, "HTIF_CONSOLE_CMD_GETCHAR_MASK", -1);
+ clua_setintegerfield(L, HTIF_CONSOLE_CMD_PUTCHAR_MASK, "HTIF_CONSOLE_CMD_PUTCHAR_MASK", -1);
+ clua_setintegerfield(L, HTIF_YIELD_CMD_MANUAL_MASK, "HTIF_YIELD_CMD_MANUAL_MASK", -1);
+ clua_setintegerfield(L, HTIF_YIELD_CMD_AUTOMATIC_MASK, "HTIF_YIELD_CMD_AUTOMATIC_MASK", -1);
// Set other constants used by internal tests
clua_setintegerfield(L, UARCH_STATE_START_ADDRESS, "UARCH_STATE_START_ADDRESS", -1);
clua_setintegerfield(L, UARCH_STATE_LOG2_SIZE, "UARCH_STATE_LOG2_SIZE", -1);
diff --git a/src/dtb.cpp b/src/dtb.cpp
index 7024fd3ad..077eb113f 100644
--- a/src/dtb.cpp
+++ b/src/dtb.cpp
@@ -98,7 +98,7 @@ void dtb_init(const machine_config &c, unsigned char *dtb_start, uint64_t dtb_le
fdt.prop_u32("reg", 0);
fdt.prop_string("status", "okay");
fdt.prop_string("compatible", "riscv");
- fdt.prop_string("riscv,isa", misa_to_isa_string(c.processor.misa));
+ fdt.prop_string("riscv,isa", misa_to_isa_string(c.processor.registers.misa));
fdt.prop_string("mmu-type", "riscv,sv39");
fdt.prop_u32("clock-frequency", RTC_CLOCK_FREQ);
{ // interrupt-controller
@@ -207,13 +207,13 @@ void dtb_init(const machine_config &c, unsigned char *dtb_start, uint64_t dtb_le
fdt.end_node();
// yield
- if (c.htif.yield_manual || c.htif.yield_automatic) {
+ if (c.processor.registers.htif.iyield != 0) {
fdt.begin_node("yield");
fdt.prop_string("compatible", "ctsi-yield");
- if (c.htif.yield_manual) {
+ if ((c.processor.registers.htif.iyield & HTIF_YIELD_CMD_MANUAL_MASK) != 0) {
fdt.prop_empty("manual");
}
- if (c.htif.yield_automatic) {
+ if ((c.processor.registers.htif.iyield & HTIF_YIELD_CMD_AUTOMATIC_MASK) != 0) {
fdt.prop_empty("automatic");
}
fdt.end_node();
diff --git a/src/hot-tlb.h b/src/hot-tlb.h
new file mode 100644
index 000000000..471d461c3
--- /dev/null
+++ b/src/hot-tlb.h
@@ -0,0 +1,53 @@
+// Copyright Cartesi and individual authors (see AUTHORS)
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// This program is free software: you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+// PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License along
+// with this program (see COPYING). If not, see .
+//
+
+#ifndef HOT_TLB_H
+#define HOT_TLB_H
+
+/// \file
+/// \brief TLB definitions
+/// \details The Translation Lookaside Buffer is a small cache used to speed up translation between address spaces.
+
+#include
+#include
+#include
+
+#include "host-addr.h"
+#include "shadow-tlb.h"
+
+namespace cartesi {
+
+/// \brief Hot TLB slot.
+/// \details
+/// Given a target virtual address vaddr within a page matching vaddr_page in TLB slot, the corresponding host address
+/// haddr = vaddr + vh_offset.
+struct hot_tlb_slot final {
+ uint64_t vaddr_page{TLB_INVALID_PAGE}; ///< Target virtual address of start of page
+ host_addr vh_offset{0}; ///< Offset from target virtual address in the same page to host address
+};
+
+using hot_tlb_set = std::array;
+using hot_tlb_state = std::array;
+
+static_assert(sizeof(uint64_t) >= sizeof(uintptr_t), "TLB expects host pointer fit in 64 bits");
+
+// We need to ensure TLB state sizes are fixed across different platforms
+static_assert(sizeof(hot_tlb_state) == 3 * TLB_SET_SIZE * 2 * sizeof(uint64_t), "unexpected hot TLB state size");
+static_assert(alignof(hot_tlb_state) == sizeof(uint64_t), "unexpected hot TLB state alignment");
+
+} // namespace cartesi
+
+#endif
diff --git a/src/htif-constants.h b/src/htif-constants.h
index 1a57a13f6..744f69bba 100644
--- a/src/htif-constants.h
+++ b/src/htif-constants.h
@@ -102,6 +102,15 @@ enum HTIF_commands : uint64_t {
HTIF_YIELD_CMD_AUTOMATIC = HTIF_YIELD_CMD_AUTOMATIC_DEF,
};
+/// \brief HTIF commands masks
+enum HTIF_commands_masks : uint64_t {
+ HTIF_HALT_CMD_HALT_MASK = UINT64_C(1) << HTIF_HALT_CMD_HALT,
+ HTIF_CONSOLE_CMD_GETCHAR_MASK = UINT64_C(1) << HTIF_CONSOLE_CMD_GETCHAR,
+ HTIF_CONSOLE_CMD_PUTCHAR_MASK = UINT64_C(1) << HTIF_CONSOLE_CMD_PUTCHAR,
+ HTIF_YIELD_CMD_MANUAL_MASK = UINT64_C(1) << HTIF_YIELD_CMD_MANUAL,
+ HTIF_YIELD_CMD_AUTOMATIC_MASK = UINT64_C(1) << HTIF_YIELD_CMD_AUTOMATIC,
+};
+
/// \brief HTIF yield reasons
enum HTIF_yield_reason : uint64_t {
HTIF_YIELD_AUTOMATIC_REASON_PROGRESS = HTIF_YIELD_AUTOMATIC_REASON_PROGRESS_DEF,
diff --git a/src/i-prefer-shadow-state.h b/src/i-prefer-shadow-state.h
index 4d4f83213..dd75b9f56 100644
--- a/src/i-prefer-shadow-state.h
+++ b/src/i-prefer-shadow-state.h
@@ -25,8 +25,8 @@
#include
#include "meta.h"
-#include "shadow-state.h"
-#include "tlb.h"
+#include "shadow-registers.h"
+#include "shadow-tlb.h"
namespace cartesi {
@@ -48,12 +48,12 @@ class i_prefer_shadow_state { // CRTP
}
public:
- uint64_t read_shadow_state(shadow_state_what what) const {
- return derived().do_read_shadow_state(what);
+ uint64_t read_shadow_register(shadow_registers_what what) const {
+ return derived().do_read_shadow_register(what);
}
- void write_shadow_state(shadow_state_what what, uint64_t val) const {
- derived().do_write_shadow_state(what, val);
+ void write_shadow_register(shadow_registers_what what, uint64_t val) const {
+ derived().do_write_shadow_register(what, val);
}
};
diff --git a/src/i-prefer-shadow-uarch-state.h b/src/i-prefer-shadow-uarch-state.h
index f540cff75..af9319cf1 100644
--- a/src/i-prefer-shadow-uarch-state.h
+++ b/src/i-prefer-shadow-uarch-state.h
@@ -25,8 +25,8 @@
#include
#include "meta.h"
+#include "shadow-tlb.h"
#include "shadow-uarch-state.h"
-#include "tlb.h"
namespace cartesi {
diff --git a/src/i-state-access.h b/src/i-state-access.h
index c9cbb1a0d..e216b3d4e 100644
--- a/src/i-state-access.h
+++ b/src/i-state-access.h
@@ -30,7 +30,7 @@
#include "i-prefer-shadow-state.h"
#include "meta.h"
#include "poor-type-name.h"
-#include "tlb.h"
+#include "shadow-tlb.h"
namespace cartesi {
@@ -51,7 +51,7 @@ using i_state_access_fast_addr_t = typename i_state_access_fast_addr(this);
}
- uint64_t prefer_read_shadow_state(shadow_state_what what) const {
- const auto val = derived().read_shadow_state(what);
- [[maybe_unused]] const auto *const what_name = shadow_state_get_what_name(what);
- dsa_printf("%s::read_shadow_state(%s) = %" PRIu64 "(0x%" PRIx64 ")\n", get_name(), what_name, val, val);
+ uint64_t prefer_read_shadow_register(shadow_registers_what what) const {
+ const auto val = derived().read_shadow_register(what);
+ [[maybe_unused]] const auto *const what_name = shadow_registers_get_what_name(what);
+ dsa_printf("%s::read_shadow_register(%s) = %" PRIu64 "(0x%" PRIx64 ")\n", get_name(), what_name, val, val);
return val;
}
- void prefer_write_shadow_state(shadow_state_what what, uint64_t val) const {
- derived().write_shadow_state(what, val);
- [[maybe_unused]] const auto *const what_name = shadow_state_get_what_name(what);
- dsa_printf("%s::write_shadow_state(%s, %" PRIu64 "(0x%" PRIx64 "))\n", get_name(), what_name, val, val);
+ void prefer_write_shadow_register(shadow_registers_what what, uint64_t val) const {
+ derived().write_shadow_register(what, val);
+ [[maybe_unused]] const auto *const what_name = shadow_registers_get_what_name(what);
+ dsa_printf("%s::write_shadow_register(%s, %" PRIu64 "(0x%" PRIx64 "))\n", get_name(), what_name, val, val);
}
public:
@@ -146,7 +146,7 @@ class i_state_access { // CRTP
dsa_printf("%s::read_x(%d) = %" PRIu64 "(0x%" PRIx64 ")\n", get_name(), i, val, val);
return val;
} else {
- return prefer_read_shadow_state(shadow_state_get_what(shadow_state_what::x0, i));
+ return prefer_read_shadow_register(shadow_registers_get_what(shadow_registers_what::x0, i));
}
}
@@ -160,7 +160,7 @@ class i_state_access { // CRTP
derived().do_write_x(i, val);
dsa_printf("%s::write_x(%d, %" PRIu64 "(0x%" PRIx64 "))\n", get_name(), i, val, val);
} else {
- prefer_write_shadow_state(shadow_state_get_what(shadow_state_what::x0, i), val);
+ prefer_write_shadow_register(shadow_registers_get_what(shadow_registers_what::x0, i), val);
}
}
@@ -173,7 +173,7 @@ class i_state_access { // CRTP
dsa_printf("%s::read_f(%d) = %" PRIu64 "(0x%" PRIx64 ")\n", get_name(), i, val, val);
return val;
} else {
- return prefer_read_shadow_state(shadow_state_get_what(shadow_state_what::f0, i));
+ return prefer_read_shadow_register(shadow_registers_get_what(shadow_registers_what::f0, i));
}
}
@@ -185,7 +185,7 @@ class i_state_access { // CRTP
derived().do_write_f(i, val);
dsa_printf("%s::write_f(%d, %" PRIu64 "(%" PRIx64 "))\n", get_name(), i, val, val);
} else {
- prefer_write_shadow_state(shadow_state_get_what(shadow_state_what::f0, i), val);
+ prefer_write_shadow_register(shadow_registers_get_what(shadow_registers_what::f0, i), val);
}
}
@@ -377,15 +377,15 @@ class i_state_access { // CRTP
return val;
}
- /// \brief Reads TLB's vp_offset
+ /// \brief Reads TLB's vf_offset
/// \tparam USE TLB set
/// \param slot_index Slot index
/// \returns Value in slot.
template
- fast_addr read_tlb_vp_offset(uint64_t slot_index) const {
+ fast_addr read_tlb_vf_offset(uint64_t slot_index) const {
[[maybe_unused]] const auto fast_addr_name = std::is_same_v ? "phys_addr" : "fast_addr";
- const auto val = derived().template do_read_tlb_vp_offset(slot_index);
- dsa_printf("%s::read_tlb_vp_offset<%" PRIu64 ">(%" PRIu64 ") = %s{0x%" PRIx64 "}\n", get_name(), SET,
+ const auto val = derived().template do_read_tlb_vf_offset(slot_index);
+ dsa_printf("%s::read_tlb_vf_offset<%" PRIu64 ">(%" PRIu64 ") = %s{0x%" PRIx64 "}\n", get_name(), SET,
slot_index, fast_addr_name, static_cast(val));
return val;
}
@@ -406,16 +406,16 @@ class i_state_access { // CRTP
/// \tparam USE TLB set
/// \param slot_index Slot index
/// \param vaddr_page Value to write
- /// \param vp_offset Value to write
+ /// \param vf_offset Value to write
/// \param pma_index Value to write
/// \detail Writes to the TLB must be modify all fields atomically to prevent an inconsistent state.
/// This simplifies all state access implementations.
template
- void write_tlb(uint64_t slot_index, uint64_t vaddr_page, fast_addr vp_offset, uint64_t pma_index) const {
- derived().template do_write_tlb(slot_index, vaddr_page, vp_offset, pma_index);
+ void write_tlb(uint64_t slot_index, uint64_t vaddr_page, fast_addr vf_offset, uint64_t pma_index) const {
+ derived().template do_write_tlb(slot_index, vaddr_page, vf_offset, pma_index);
[[maybe_unused]] const auto fast_addr_name = std::is_same_v ? "phys_addr" : "fast_addr";
dsa_printf("%s::write_tlb<%" PRIu64 ">(%" PRIu64 ", 0x%" PRIx64 ", %s{0x%" PRIx64 "}, %" PRIu64 ")\n",
- get_name(), SET, slot_index, vaddr_page, fast_addr_name, static_cast(vp_offset), pma_index);
+ get_name(), SET, slot_index, vaddr_page, fast_addr_name, static_cast(vf_offset), pma_index);
}
/// \brief Marks a page as dirty
diff --git a/src/i-uarch-state-access.h b/src/i-uarch-state-access.h
index 3e290c768..d697eb153 100644
--- a/src/i-uarch-state-access.h
+++ b/src/i-uarch-state-access.h
@@ -24,7 +24,7 @@
#include "assert-printf.h"
#include "i-prefer-shadow-uarch-state.h"
#include "meta.h"
-#include "tlb.h"
+#include "shadow-tlb.h"
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
#define DEFINE_USA_READ(REG) \
diff --git a/src/interpret.cpp b/src/interpret.cpp
index 11c5a6f31..d3ebc3c44 100644
--- a/src/interpret.cpp
+++ b/src/interpret.cpp
@@ -102,6 +102,7 @@
#include "compiler-defines.h"
#include "device-state-access.h"
#include "find-pma.h"
+#include "hot-tlb.h"
#include "i-accept-counters.h"
#include "i-interactive-state-access.h"
#include "i-state-access.h"
@@ -109,7 +110,6 @@
#include "riscv-constants.h"
#include "rtc.h"
#include "soft-float.h"
-#include "tlb.h"
#include "translate-virtual-address.h"
#include "uint128.h"
@@ -876,16 +876,16 @@ static void flush_tlb_slot(const STATE_ACCESS a, uint64_t slot_index) {
const auto old_vaddr_page = a.template read_tlb_vaddr_page(slot_index);
if (old_vaddr_page != TLB_INVALID_PAGE) {
auto old_pma_index = a.template read_tlb_pma_index(slot_index);
- const auto old_faddr_page = old_vaddr_page + a.template read_tlb_vp_offset(slot_index);
+ const auto old_faddr_page = old_vaddr_page + a.template read_tlb_vf_offset(slot_index);
a.mark_dirty_page(old_faddr_page, old_pma_index);
}
}
// We do not leave garbage behind in empty slots
// (It would make state access classes trickier to implement)
const auto vaddr_page = TLB_INVALID_PAGE;
- const auto vp_offset = i_state_access_fast_addr_t{};
+ const auto vf_offset = i_state_access_fast_addr_t{};
const auto pma_index = TLB_INVALID_PMA_INDEX;
- a.template write_tlb(slot_index, vaddr_page, vp_offset, pma_index);
+ a.template write_tlb(slot_index, vaddr_page, vf_offset, pma_index);
}
/// \brief Flushes out an entire TLB set
@@ -930,18 +930,18 @@ static void flush_tlb_vaddr(const STATE_ACCESS a, uint64_t /* vaddr */) {
/// \param vaddr Virtual address of new mapping
/// \param paddr Corresponding physical address
/// \param paddr Index of PMA where paddr falls
-/// \param vp_offset Receives the new vp_offset that will be stored in the slot
+/// \param vf_offset Receives the new vf_offset that will be stored in the slot
/// \returns The implementation-defined fast address corresponding to paddr
template
static i_state_access_fast_addr_t replace_tlb_entry(const STATE_ACCESS a, uint64_t vaddr, uint64_t paddr,
- uint64_t pma_index, i_state_access_fast_addr_t &vp_offset) {
+ uint64_t pma_index, i_state_access_fast_addr_t &vf_offset) {
[[maybe_unused]] auto note = a.make_scoped_note("replace_tlb_entry");
const auto slot_index = tlb_slot_index(vaddr);
flush_tlb_slot(a, slot_index);
const auto vaddr_page = tlb_addr_page(vaddr);
const auto faddr = a.get_faddr(paddr, pma_index);
- vp_offset = faddr - vaddr;
- a.template write_tlb(slot_index, vaddr_page, vp_offset, pma_index);
+ vf_offset = faddr - vaddr;
+ a.template write_tlb(slot_index, vaddr_page, vf_offset, pma_index);
return faddr;
}
@@ -955,8 +955,8 @@ static i_state_access_fast_addr_t replace_tlb_entry(const STATE_AC
/// \returns The implementation-defined fast address corresponding to paddr
template
static FORCE_INLINE auto replace_tlb_entry(const STATE_ACCESS a, uint64_t vaddr, uint64_t paddr, uint64_t pma_index) {
- i_state_access_fast_addr_t vp_offset{0};
- return replace_tlb_entry(a, vaddr, paddr, pma_index, vp_offset);
+ i_state_access_fast_addr_t vf_offset{0};
+ return replace_tlb_entry(a, vaddr, paddr, pma_index, vf_offset);
}
/// \brief Read an aligned word from virtual memory (slow path that goes through virtual address translation).
@@ -1046,8 +1046,8 @@ static FORCE_INLINE bool read_virtual_memory(const STATE_ACCESS a, uint64_t &pc,
return status;
}
const auto pma_index = a.template read_tlb_pma_index(slot_index);
- const auto vp_offset = a.template read_tlb_vp_offset(slot_index);
- const auto faddr = vaddr + vp_offset;
+ const auto vf_offset = a.template read_tlb_vf_offset(slot_index);
+ const auto faddr = vaddr + vf_offset;
a.template read_memory_word(faddr, pma_index, pval);
DUMP_STATS_INCR(a, "tlb.rhit");
return true;
@@ -1128,8 +1128,8 @@ static FORCE_INLINE execute_status write_virtual_memory(const STATE_ACCESS a, ui
return status;
}
const auto pma_index = a.template read_tlb_pma_index(slot_index);
- const auto vp_offset = a.template read_tlb_vp_offset(slot_index);
- const auto faddr = vaddr + vp_offset;
+ const auto vf_offset = a.template read_tlb_vf_offset(slot_index);
+ const auto faddr = vaddr + vf_offset;
a.template write_memory_word(faddr, pma_index, static_cast(val64));
DUMP_STATS_INCR(a, "tlb.whit");
return execute_status::success;
@@ -5378,13 +5378,13 @@ enum class fetch_status : int {
/// \param a Machine state accessor object.
/// \param pc Virtual address for the current instruction being executed.
/// \param vaddr Virtual address to be fetched.
-/// \param vp_offset Receives vp_offset in the TLB slot
+/// \param vf_offset Receives vf_offset in the TLB slot
/// \param pma_index Receives the index of PMA where vaddr falls
/// \return Returns fetch_status::success if load succeeded, fetch_status::exception if it caused an exception.
// In that case, raise the exception.
template
static FORCE_INLINE fetch_status fetch_translate_pc_slow(const STATE_ACCESS a, uint64_t &pc, uint64_t vaddr,
- i_state_access_fast_addr_t &vp_offset, uint64_t &pma_index) {
+ i_state_access_fast_addr_t &vf_offset, uint64_t &pma_index) {
uint64_t paddr{};
// Walk page table and obtain the physical address
if (unlikely(!translate_virtual_address(a, &paddr, vaddr, PTE_XWR_X_SHIFT))) {
@@ -5399,7 +5399,7 @@ static FORCE_INLINE fetch_status fetch_translate_pc_slow(const STATE_ACCESS a, u
pc = raise_exception(a, pc, MCAUSE_INSN_ACCESS_FAULT, vaddr);
return fetch_status::exception;
}
- replace_tlb_entry(a, vaddr, paddr, pma_index, vp_offset);
+ replace_tlb_entry(a, vaddr, paddr, pma_index, vf_offset);
return fetch_status::success;
}
@@ -5408,22 +5408,22 @@ static FORCE_INLINE fetch_status fetch_translate_pc_slow(const STATE_ACCESS a, u
/// \param a Machine state accessor object.
/// \param pc Virtual address for the current instruction being executed.
/// \param vaddr Virtual address to be fetched.
-/// \param vp_offset Receives vp_offset in the TLB slot
+/// \param vf_offset Receives vf_offset in the TLB slot
/// \param pma_index Receives the index of PMA where vaddr falls
/// \return Returns fetch_status::success if load succeeded, fetch_status::exception if it caused an exception.
// In that case, raise the exception.
template
static FORCE_INLINE fetch_status fetch_translate_pc(const STATE_ACCESS a, uint64_t &pc, uint64_t vaddr,
- i_state_access_fast_addr_t &vp_offset, uint64_t &pma_index) {
+ i_state_access_fast_addr_t &vf_offset, uint64_t &pma_index) {
// Try to perform the address translation via TLB first
const uint64_t slot_index = tlb_slot_index(vaddr);
const uint64_t slot_vaddr_page = a.template read_tlb_vaddr_page(slot_index);
if (unlikely(!tlb_is_hit(slot_vaddr_page, vaddr))) {
DUMP_STATS_INCR(a, "tlb.cmiss");
// Outline the slow path into a function call to minimize host CPU code cache pressure
- return fetch_translate_pc_slow(a, pc, vaddr, vp_offset, pma_index);
+ return fetch_translate_pc_slow(a, pc, vaddr, vf_offset, pma_index);
}
- vp_offset = a.template read_tlb_vp_offset(slot_index);
+ vf_offset = a.template read_tlb_vf_offset(slot_index);
pma_index = a.template read_tlb_pma_index(slot_index);
DUMP_STATS_INCR(a, "tlb.chit");
return fetch_status::success;
@@ -5435,32 +5435,32 @@ static FORCE_INLINE fetch_status fetch_translate_pc(const STATE_ACCESS a, uint64
/// \param pc Virtual address for the current instruction being executed.
/// \param insn Receives the instruction.
/// \param last_vaddr_page Receives and updates vaddr_page for cache.
-/// \param last_vp_offset Receives and updates vp_offset for cache.
+/// \param last_vf_offset Receives and updates vf_offset for cache.
/// \param last_pma_index Receives and updates pma_index for cache.
/// \return Returns fetch_status::success if load succeeded, fetch_status::exception if it caused an exception.
// In that case, raise the exception.
template
static FORCE_INLINE fetch_status fetch_insn(const STATE_ACCESS a, uint64_t &pc, uint32_t &insn,
- uint64_t &last_vaddr_page, i_state_access_fast_addr_t &last_vp_offset, uint64_t &last_pma_index) {
+ uint64_t &last_vaddr_page, i_state_access_fast_addr_t &last_vf_offset, uint64_t &last_pma_index) {
[[maybe_unused]] auto note = a.make_scoped_note("fetch_insn");
i_state_access_fast_addr_t faddr{0};
const uint64_t pc_vaddr_page = tlb_addr_page(pc);
// If pc is in the same page as the last pc fetch,
// we can just reuse last fetch translation, skipping TLB or slow address translation altogether.
if (likely(pc_vaddr_page == last_vaddr_page)) {
- faddr = pc + last_vp_offset;
+ faddr = pc + last_vf_offset;
} else {
// Not in the same page as last the fetch, we need to perform address translation
- i_state_access_fast_addr_t pc_vp_offset{};
+ i_state_access_fast_addr_t pc_vf_offset{};
uint64_t pc_pma_index{};
- if (unlikely(fetch_translate_pc(a, pc, pc, pc_vp_offset, pc_pma_index) == fetch_status::exception)) {
+ if (unlikely(fetch_translate_pc(a, pc, pc, pc_vf_offset, pc_pma_index) == fetch_status::exception)) {
return fetch_status::exception;
}
// Update fetch address translation cache
last_vaddr_page = pc_vaddr_page;
- last_vp_offset = pc_vp_offset;
+ last_vf_offset = pc_vf_offset;
last_pma_index = pc_pma_index;
- faddr = pc + pc_vp_offset;
+ faddr = pc + pc_vf_offset;
}
// The following code assumes pc is always 2-byte aligned, this is guaranteed by RISC-V spec.
// If pc is pointing to the very last 2 bytes of a page, it's crossing a page boundary.
@@ -5473,15 +5473,15 @@ static FORCE_INLINE fetch_status fetch_insn(const STATE_ACCESS a, uint64_t &pc,
if (unlikely(insn_is_uncompressed(insn))) {
// We have to perform a new address translation to read the next 2 bytes since we changed pages.
const uint64_t pc2 = pc + 2;
- i_state_access_fast_addr_t pc2_vp_offset{};
+ i_state_access_fast_addr_t pc2_vf_offset{};
uint64_t pc2_pma_index{};
- if (unlikely(fetch_translate_pc(a, pc, pc2, pc2_vp_offset, pc2_pma_index) == fetch_status::exception)) {
+ if (unlikely(fetch_translate_pc(a, pc, pc2, pc2_vf_offset, pc2_pma_index) == fetch_status::exception)) {
return fetch_status::exception;
}
last_vaddr_page = tlb_addr_page(pc2);
- last_vp_offset = pc2_vp_offset;
+ last_vf_offset = pc2_vf_offset;
last_pma_index = pc2_pma_index;
- faddr = pc2 + last_vp_offset;
+ faddr = pc2 + last_vf_offset;
a.template read_memory_word(faddr, last_pma_index, &insn16);
insn |= insn16 << 16;
}
@@ -5524,7 +5524,7 @@ static NO_INLINE execute_status interpret_loop(const STATE_ACCESS a, uint64_t mc
// Initialize fetch address translation cache invalidated
uint64_t fetch_vaddr_page = TLB_INVALID_PAGE;
uint64_t fetch_pma_index = TLB_INVALID_PMA_INDEX;
- i_state_access_fast_addr_t fetch_vp_offset{};
+ i_state_access_fast_addr_t fetch_vf_offset{};
// The outer loop continues until there is an interruption that should be handled
// externally, or mcycle reaches mcycle_end
@@ -5563,7 +5563,7 @@ static NO_INLINE execute_status interpret_loop(const STATE_ACCESS a, uint64_t mc
uint32_t insn = 0;
// Try to fetch the next instruction
- if (likely(fetch_insn(a, pc, insn, fetch_vaddr_page, fetch_vp_offset, fetch_pma_index) ==
+ if (likely(fetch_insn(a, pc, insn, fetch_vaddr_page, fetch_vf_offset, fetch_pma_index) ==
fetch_status::success)) {
// clang-format off
// NOLINTBEGIN
diff --git a/src/json-util.cpp b/src/json-util.cpp
index 719578307..2349bd54c 100644
--- a/src/json-util.cpp
+++ b/src/json-util.cpp
@@ -1159,7 +1159,7 @@ template void ju_get_opt_field(const nlohmann::json &j, const std::
not_default_constructible &value, const std::string &path);
template
-void ju_get_opt_field(const nlohmann::json &j, const K &key, processor_config &value, const std::string &path) {
+void ju_get_opt_field(const nlohmann::json &j, const K &key, registers_state &value, const std::string &path) {
if (!contains(j, key, path)) {
return;
}
@@ -1259,10 +1259,28 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, processor_config &v
ju_get_opt_field(jconfig, "senvcfg"s, value.senvcfg, new_path);
ju_get_opt_field(jconfig, "ilrsc"s, value.ilrsc, new_path);
ju_get_opt_field(jconfig, "iprv"s, value.iprv, new_path);
- ju_get_opt_field(jconfig, "iflags_X"s, value.iflags_X, new_path);
- ju_get_opt_field(jconfig, "iflags_Y"s, value.iflags_Y, new_path);
- ju_get_opt_field(jconfig, "iflags_H"s, value.iflags_H, new_path);
+ ju_get_opt_field(jconfig, "iflags"s, value.iflags, new_path);
ju_get_opt_field(jconfig, "iunrep"s, value.iunrep, new_path);
+ ju_get_opt_field(jconfig, "clint"s, value.clint, new_path);
+ ju_get_opt_field(jconfig, "plic"s, value.plic, new_path);
+ ju_get_opt_field(jconfig, "htif"s, value.htif, new_path);
+}
+
+template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, registers_state &value,
+ const std::string &path);
+
+template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, registers_state &value,
+ const std::string &path);
+
+template
+void ju_get_opt_field(const nlohmann::json &j, const K &key, processor_config &value, const std::string &path) {
+ if (!contains(j, key, path)) {
+ return;
+ }
+ const auto &jconfig = j[key];
+ const auto new_path = path + to_string(key) + "/";
+ ju_get_opt_field(jconfig, "registers"s, value.registers, new_path);
+ ju_get_opt_field(jconfig, "backing_store"s, value.backing_store, new_path);
}
template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, processor_config &value,
@@ -1334,6 +1352,7 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, hash_tree_config &v
const auto &jconfig = j[key];
const auto new_path = path + to_string(key) + "/";
ju_get_opt_field(jconfig, "shared"s, value.shared, new_path);
+ ju_get_opt_field(jconfig, "create"s, value.create, new_path);
ju_get_opt_field(jconfig, "truncate"s, value.truncate, new_path);
ju_get_opt_field(jconfig, "hasher"s, value.hasher, new_path);
ju_get_opt_field(jconfig, "sht_filename"s, value.sht_filename, new_path);
@@ -1355,6 +1374,7 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, backing_store_confi
const auto &jconfig = j[key];
const auto new_path = path + to_string(key) + "/";
ju_get_opt_field(jconfig, "shared"s, value.shared, new_path);
+ ju_get_opt_field(jconfig, "create"s, value.create, new_path);
ju_get_opt_field(jconfig, "truncate"s, value.truncate, new_path);
ju_get_opt_field(jconfig, "data_filename"s, value.data_filename, new_path);
ju_get_opt_field(jconfig, "dht_filename"s, value.dht_filename, new_path);
@@ -1481,7 +1501,25 @@ template void ju_get_opt_field(const nlohmann::json &j, const std::
const std::string &path);
template
-void ju_get_opt_field(const nlohmann::json &j, const K &key, clint_config &value, const std::string &path) {
+void ju_get_opt_field(const nlohmann::json &j, const K &key, iflags_state &value, const std::string &path) {
+ if (!contains(j, key, path)) {
+ return;
+ }
+ const auto &jconfig = j[key];
+ const auto new_path = path + to_string(key) + "/";
+ ju_get_opt_field(jconfig, "X"s, value.X, new_path);
+ ju_get_opt_field(jconfig, "Y"s, value.Y, new_path);
+ ju_get_opt_field(jconfig, "H"s, value.H, new_path);
+}
+
+template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, iflags_state &value,
+ const std::string &path);
+
+template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, iflags_state &value,
+ const std::string &path);
+
+template
+void ju_get_opt_field(const nlohmann::json &j, const K &key, clint_state &value, const std::string &path) {
if (!contains(j, key, path)) {
return;
}
@@ -1490,14 +1528,14 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, clint_config &value
ju_get_opt_field(jconfig, "mtimecmp"s, value.mtimecmp, new_path);
}
-template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, clint_config &value,
+template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, clint_state &value,
const std::string &path);
-template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, clint_config &value,
+template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, clint_state &value,
const std::string &path);
template
-void ju_get_opt_field(const nlohmann::json &j, const K &key, plic_config &value, const std::string &path) {
+void ju_get_opt_field(const nlohmann::json &j, const K &key, plic_state &value, const std::string &path) {
if (!contains(j, key, path)) {
return;
}
@@ -1507,14 +1545,14 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, plic_config &value,
ju_get_opt_field(jconfig, "girqsrvd"s, value.girqsrvd, new_path);
}
-template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, plic_config &value,
+template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, plic_state &value,
const std::string &path);
-template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, plic_config &value,
+template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, plic_state &value,
const std::string &path);
template
-void ju_get_opt_field(const nlohmann::json &j, const K &key, htif_config &value, const std::string &path) {
+void ju_get_opt_field(const nlohmann::json &j, const K &key, htif_state &value, const std::string &path) {
if (!contains(j, key, path)) {
return;
}
@@ -1522,15 +1560,15 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, htif_config &value,
const auto new_path = path + to_string(key) + "/";
ju_get_opt_field(jconfig, "fromhost"s, value.fromhost, new_path);
ju_get_opt_field(jconfig, "tohost"s, value.tohost, new_path);
- ju_get_opt_field(jconfig, "console_getchar"s, value.console_getchar, new_path);
- ju_get_opt_field(jconfig, "yield_manual"s, value.yield_manual, new_path);
- ju_get_opt_field(jconfig, "yield_automatic"s, value.yield_automatic, new_path);
+ ju_get_opt_field(jconfig, "ihalt"s, value.ihalt, new_path);
+ ju_get_opt_field(jconfig, "iconsole"s, value.iconsole, new_path);
+ ju_get_opt_field(jconfig, "iyield"s, value.iyield, new_path);
}
-template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, htif_config &value,
+template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, htif_state &value,
const std::string &path);
-template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, htif_config &value,
+template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, htif_state &value,
const std::string &path);
template
@@ -1551,7 +1589,7 @@ template void ju_get_opt_field(const nlohmann::json &j, const std::
const std::string &path);
template
-void ju_get_opt_field(const nlohmann::json &j, const K &key, uarch_processor_config &value, const std::string &path) {
+void ju_get_opt_field(const nlohmann::json &j, const K &key, uarch_registers_state &value, const std::string &path) {
if (!contains(j, key, path)) {
return;
}
@@ -1594,6 +1632,23 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, uarch_processor_con
ju_get_opt_field(jconfig, "halt_flag"s, value.halt_flag, new_path);
}
+template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, uarch_registers_state &value,
+ const std::string &path);
+
+template void ju_get_opt_field(const nlohmann::json &j, const std::string &key,
+ uarch_registers_state &value, const std::string &path);
+
+template
+void ju_get_opt_field(const nlohmann::json &j, const K &key, uarch_processor_config &value, const std::string &path) {
+ if (!contains(j, key, path)) {
+ return;
+ }
+ const auto &jconfig = j[key];
+ const auto new_path = path + to_string(key) + "/";
+ ju_get_opt_field(jconfig, "registers"s, value.registers, new_path);
+ ju_get_opt_field(jconfig, "backing_store"s, value.backing_store, new_path);
+}
+
template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, uarch_processor_config &value,
const std::string &path);
@@ -1628,10 +1683,6 @@ void ju_get_opt_field(const nlohmann::json &j, const K &key, machine_config &val
ju_get_opt_field(config, "ram"s, value.ram, new_path);
ju_get_opt_field(config, "dtb"s, value.dtb, new_path);
ju_get_opt_field(config, "flash_drive"s, value.flash_drive, new_path);
- ju_get_opt_field(config, "tlb"s, value.tlb, new_path);
- ju_get_opt_field(config, "clint"s, value.clint, new_path);
- ju_get_opt_field(config, "plic"s, value.plic, new_path);
- ju_get_opt_field(config, "htif"s, value.htif, new_path);
ju_get_opt_field(config, "virtio"s, value.virtio, new_path);
ju_get_opt_field(config, "cmio"s, value.cmio, new_path);
ju_get_opt_field(config, "pmas"s, value.pmas, new_path);
@@ -1782,7 +1833,7 @@ void to_json(nlohmann::json &j, const access_log &log) {
}
void to_json(nlohmann::json &j, const backing_store_config &config) {
- j = nlohmann::json{{"shared", config.shared}, {"truncate", config.truncate},
+ j = nlohmann::json{{"shared", config.shared}, {"create", config.create}, {"truncate", config.truncate},
{"data_filename", config.data_filename}, {"dht_filename", config.dht_filename}};
}
@@ -1796,12 +1847,12 @@ void to_json(nlohmann::json &j, const memory_range_config &config) {
}
void to_json(nlohmann::json &j, const hash_tree_config &config) {
- j = nlohmann::json{{"hasher", config.hasher}, {"shared", config.shared}, {"truncate", config.truncate},
- {"sht_filename", config.sht_filename}, {"phtc_filename", config.phtc_filename},
+ j = nlohmann::json{{"hasher", config.hasher}, {"shared", config.shared}, {"create", config.create},
+ {"truncate", config.truncate}, {"sht_filename", config.sht_filename}, {"phtc_filename", config.phtc_filename},
{"phtc_size", config.phtc_size}};
}
-void to_json(nlohmann::json &j, const processor_config &config) {
+void to_json(nlohmann::json &j, const registers_state &config) {
j = nlohmann::json{{"x0", config.x[0]}, {"x1", config.x[1]}, {"x2", config.x[2]}, {"x3", config.x[3]},
{"x4", config.x[4]}, {"x5", config.x[5]}, {"x6", config.x[6]}, {"x7", config.x[7]}, {"x8", config.x[8]},
{"x9", config.x[9]}, {"x10", config.x[10]}, {"x11", config.x[11]}, {"x12", config.x[12]}, {"x13", config.x[13]},
@@ -1824,8 +1875,12 @@ void to_json(nlohmann::json &j, const processor_config &config) {
{"medeleg", config.medeleg}, {"mideleg", config.mideleg}, {"mcounteren", config.mcounteren},
{"menvcfg", config.menvcfg}, {"stvec", config.stvec}, {"sscratch", config.sscratch}, {"sepc", config.sepc},
{"scause", config.scause}, {"stval", config.stval}, {"satp", config.satp}, {"scounteren", config.scounteren},
- {"senvcfg", config.senvcfg}, {"ilrsc", config.ilrsc}, {"iprv", config.iprv}, {"iflags_X", config.iflags_X},
- {"iflags_Y", config.iflags_Y}, {"iflags_H", config.iflags_H}, {"iunrep", config.iunrep}};
+ {"senvcfg", config.senvcfg}, {"ilrsc", config.ilrsc}, {"iprv", config.iprv}, {"iflags", config.iflags},
+ {"iunrep", config.iunrep}, {"clint", config.clint}, {"plic", config.plic}, {"htif", config.htif}};
+}
+
+void to_json(nlohmann::json &j, const processor_config &config) {
+ j = nlohmann::json{{"registers", config.registers}, {"backing_store", config.backing_store}};
}
void to_json(nlohmann::json &j, const flash_drive_configs &fs) {
@@ -1887,26 +1942,34 @@ void to_json(nlohmann::json &j, const dtb_config &config) {
};
}
-void to_json(nlohmann::json &j, const clint_config &config) {
+void to_json(nlohmann::json &j, const iflags_state &config) {
+ j = nlohmann::json{
+ {"X", config.X},
+ {"Y", config.Y},
+ {"H", config.H},
+ };
+}
+
+void to_json(nlohmann::json &j, const clint_state &config) {
j = nlohmann::json{
{"mtimecmp", config.mtimecmp},
};
}
-void to_json(nlohmann::json &j, const plic_config &config) {
+void to_json(nlohmann::json &j, const plic_state &config) {
j = nlohmann::json{
{"girqpend", config.girqpend},
{"girqsrvd", config.girqsrvd},
};
}
-void to_json(nlohmann::json &j, const htif_config &config) {
+void to_json(nlohmann::json &j, const htif_state &config) {
j = nlohmann::json{
{"fromhost", config.fromhost},
{"tohost", config.tohost},
- {"console_getchar", config.console_getchar},
- {"yield_manual", config.yield_manual},
- {"yield_automatic", config.yield_automatic},
+ {"ihalt", config.ihalt},
+ {"iconsole", config.iconsole},
+ {"iyield", config.iyield},
};
}
@@ -1917,7 +1980,7 @@ void to_json(nlohmann::json &j, const cmio_config &config) {
};
}
-void to_json(nlohmann::json &j, const uarch_processor_config &config) {
+void to_json(nlohmann::json &j, const uarch_registers_state &config) {
j = nlohmann::json{
{"x0", config.x[0]},
{"x1", config.x[1]},
@@ -1957,6 +2020,10 @@ void to_json(nlohmann::json &j, const uarch_processor_config &config) {
};
}
+void to_json(nlohmann::json &j, const uarch_processor_config &config) {
+ j = nlohmann::json{{"registers", config.registers}, {"backing_store", config.backing_store}};
+}
+
void to_json(nlohmann::json &j, const uarch_config &config) {
j = nlohmann::json{
{"processor", config.processor},
@@ -1970,10 +2037,6 @@ void to_json(nlohmann::json &j, const machine_config &config) {
{"ram", config.ram},
{"dtb", config.dtb},
{"flash_drive", config.flash_drive},
- {"tlb", config.tlb},
- {"clint", config.clint},
- {"plic", config.plic},
- {"htif", config.htif},
{"virtio", config.virtio},
{"cmio", config.cmio},
{"pmas", config.pmas},
diff --git a/src/json-util.h b/src/json-util.h
index 2823e0cb7..4f6e9d186 100644
--- a/src/json-util.h
+++ b/src/json-util.h
@@ -307,6 +307,16 @@ template
void ju_get_opt_field(const nlohmann::json &j, const K &key, not_default_constructible &optional,
const std::string &path = "params/");
+/// \brief Attempts to load a registers_state object from a field in a JSON object
+/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
+/// \param j JSON object to load from
+/// \param key Key to load value from
+/// \param value Object to store value
+/// \param path Path to j
+template
+void ju_get_opt_field(const nlohmann::json &j, const K &key, registers_state &value,
+ const std::string &path = "params/");
+
/// \brief Attempts to load a processor_config object from a field in a JSON object
/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
/// \param j JSON object to load from
@@ -395,32 +405,41 @@ template
void ju_get_opt_field(const nlohmann::json &j, const K &key, virtio_configs &value,
const std::string &path = "params/");
-/// \brief Attempts to load a clint_config object from a field in a JSON object
+/// \brief Attempts to load a iflags_state object from a field in a JSON object
+/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
+/// \param j JSON object to load from
+/// \param key Key to load value from
+/// \param value Object to store value
+/// \param path Path to j
+template
+void ju_get_opt_field(const nlohmann::json &j, const K &key, iflags_state &value, const std::string &path = "params/");
+
+/// \brief Attempts to load a clint_state object from a field in a JSON object
/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
/// \param j JSON object to load from
/// \param key Key to load value from
/// \param value Object to store value
/// \param path Path to j
template
-void ju_get_opt_field(const nlohmann::json &j, const K &key, clint_config &value, const std::string &path = "params/");
+void ju_get_opt_field(const nlohmann::json &j, const K &key, clint_state &value, const std::string &path = "params/");
-/// \brief Attempts to load a plic_config object from a field in a JSON object
+/// \brief Attempts to load a plic_state object from a field in a JSON object
/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
/// \param j JSON object to load from
/// \param key Key to load value from
/// \param value Object to store value
/// \param path Path to j
template
-void ju_get_opt_field(const nlohmann::json &j, const K &key, plic_config &value, const std::string &path = "params/");
+void ju_get_opt_field(const nlohmann::json &j, const K &key, plic_state &value, const std::string &path = "params/");
-/// \brief Attempts to load an htif_config object from a field in a JSON object
+/// \brief Attempts to load an htif_state object from a field in a JSON object
/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
/// \param j JSON object to load from
/// \param key Key to load value from
/// \param value Object to store value
/// \param path Path to j
template
-void ju_get_opt_field(const nlohmann::json &j, const K &key, htif_config &value, const std::string &path = "params/");
+void ju_get_opt_field(const nlohmann::json &j, const K &key, htif_state &value, const std::string &path = "params/");
/// \brief Attempts to load a cmio_config object from a field in a JSON object
/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
@@ -441,6 +460,16 @@ template
void ju_get_opt_field(const nlohmann::json &j, const K &key, std::optional &optional,
const std::string &path = "params/");
+/// \brief Attempts to load an uarch_registers_state object from a field in a JSON object
+/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
+/// \param j JSON object to load from
+/// \param key Key to load value from
+/// \param value Object to store value
+/// \param path Path to j
+template
+void ju_get_opt_field(const nlohmann::json &j, const K &key, uarch_registers_state &value,
+ const std::string &path = "params/");
+
/// \brief Attempts to load an uarch_processor_config object from a field in a JSON object
/// \tparam K Key type (explicit extern declarations for uint64_t and std::string are provided)
/// \param j JSON object to load from
@@ -613,16 +642,19 @@ void to_json(nlohmann::json &j, const access_log &log);
void to_json(nlohmann::json &j, const backing_store_config &config);
void to_json(nlohmann::json &j, const backing_store_config_only &config);
void to_json(nlohmann::json &j, const memory_range_config &config);
+void to_json(nlohmann::json &j, const registers_state &config);
void to_json(nlohmann::json &j, const processor_config &config);
void to_json(nlohmann::json &j, const flash_drive_configs &fs);
void to_json(nlohmann::json &j, const virtio_device_config &config);
void to_json(nlohmann::json &j, const virtio_configs &vs);
void to_json(nlohmann::json &j, const ram_config &config);
void to_json(nlohmann::json &j, const dtb_config &config);
-void to_json(nlohmann::json &j, const clint_config &config);
-void to_json(nlohmann::json &j, const plic_config &config);
-void to_json(nlohmann::json &j, const htif_config &config);
+void to_json(nlohmann::json &j, const iflags_state &config);
+void to_json(nlohmann::json &j, const clint_state &config);
+void to_json(nlohmann::json &j, const plic_state &config);
+void to_json(nlohmann::json &j, const htif_state &config);
void to_json(nlohmann::json &j, const cmio_config &config);
+void to_json(nlohmann::json &j, const uarch_registers_state &config);
void to_json(nlohmann::json &j, const uarch_processor_config &config);
void to_json(nlohmann::json &j, const uarch_config &config);
void to_json(nlohmann::json &j, const hash_tree_config &config);
@@ -721,6 +753,10 @@ extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &k
not_default_constructible &value, const std::string &base = "params/");
extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key,
not_default_constructible &value, const std::string &base = "params/");
+extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, registers_state &value,
+ const std::string &base = "params/");
+extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, registers_state &value,
+ const std::string &base = "params/");
extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, processor_config &value,
const std::string &base = "params/");
extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, processor_config &value,
@@ -757,17 +793,21 @@ extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &k
const std::string &base = "params/");
extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, virtio_configs &value,
const std::string &base = "params/");
-extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, clint_config &value,
+extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, iflags_state &value,
+ const std::string &base = "params/");
+extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, iflags_state &value,
const std::string &base = "params/");
-extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, clint_config &value,
+extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, clint_state &value,
const std::string &base = "params/");
-extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, plic_config &value,
+extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, clint_state &value,
const std::string &base = "params/");
-extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, plic_config &value,
+extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, plic_state &value,
const std::string &base = "params/");
-extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, htif_config &value,
+extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, plic_state &value,
const std::string &base = "params/");
-extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, htif_config &value,
+extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, htif_state &value,
+ const std::string &base = "params/");
+extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, htif_state &value,
const std::string &base = "params/");
extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, cmio_config &value,
const std::string &base = "params/");
@@ -777,6 +817,10 @@ extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &k
const std::string &base = "params/");
extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key,
std::optional &value, const std::string &base = "params/");
+extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, uarch_registers_state &value,
+ const std::string &base = "params/");
+extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, uarch_registers_state &value,
+ const std::string &base = "params/");
extern template void ju_get_opt_field(const nlohmann::json &j, const uint64_t &key, uarch_processor_config &value,
const std::string &base = "params/");
extern template void ju_get_opt_field(const nlohmann::json &j, const std::string &key, uarch_processor_config &value,
diff --git a/src/jsonrpc-discover.json b/src/jsonrpc-discover.json
index 6cb89098c..b8619a03e 100644
--- a/src/jsonrpc-discover.json
+++ b/src/jsonrpc-discover.json
@@ -1000,8 +1000,8 @@
}
}
},
- "ProcessorConfig": {
- "title": "ProcessorConfig",
+ "RegistersConfig": {
+ "title": "RegistersConfig",
"type": "object",
"properties": {
"x0": {
@@ -1341,6 +1341,9 @@
"length": {
"$ref": "#/components/schemas/UnsignedInteger"
},
+ "read_only": {
+ "type": "boolean"
+ },
"backing_store": {
"$ref": "#/components/schemas/BackingStoreConfig"
}
@@ -1359,6 +1362,9 @@
"shared": {
"type": "boolean"
},
+ "create": {
+ "type": "boolean"
+ },
"truncate": {
"type": "boolean"
}
@@ -1430,15 +1436,6 @@
"$ref": "#/components/schemas/MemoryRangeConfig"
}
},
- "TLBConfig": {
- "title": "TLBConfig",
- "type": "object",
- "properties": {
- "backing_store": {
- "$ref": "#/components/schemas/BackingStoreConfig"
- }
- }
- },
"CLINTConfig": {
"title": "CLINTConfig",
"type": "object",
@@ -1481,8 +1478,8 @@
}
}
},
- "UarchProcessorConfig": {
- "title": "UarchProcessorConfig",
+ "UarchRegistersConfig": {
+ "title": "UarchRegistersConfig",
"type": "object",
"properties": {
"x0": {
@@ -1608,8 +1605,8 @@
"title": "UarchConfig",
"type": "object",
"properties": {
- "processor": {
- "$ref": "#/components/schemas/UarchProcessorConfig"
+ "registers": {
+ "$ref": "#/components/schemas/UarchRegistersConfig"
},
"ram": {
"$ref": "#/components/schemas/UarchRAMConfig"
@@ -1647,6 +1644,12 @@
"shared": {
"type": "boolean"
},
+ "create": {
+ "type": "boolean"
+ },
+ "truncate": {
+ "type": "boolean"
+ },
"sht_filename": {
"type": "string"
},
@@ -1669,8 +1672,8 @@
"title": "MachineConfig",
"type": "object",
"properties": {
- "processor": {
- "$ref": "#/components/schemas/ProcessorConfig"
+ "registers": {
+ "$ref": "#/components/schemas/RegistersConfig"
},
"ram": {
"$ref": "#/components/schemas/RAMConfig"
@@ -1681,9 +1684,6 @@
"flash_drive": {
"$ref": "#/components/schemas/FlashDriveConfigs"
},
- "tlb": {
- "$ref": "#/components/schemas/TLBConfig"
- },
"clint": {
"$ref": "#/components/schemas/CLINTConfig"
},
diff --git a/src/machine-c-api.h b/src/machine-c-api.h
index 9f486f255..90ba25073 100644
--- a/src/machine-c-api.h
+++ b/src/machine-c-api.h
@@ -130,7 +130,7 @@ typedef enum cm_cmio_yield_reason {
/// \brief Machine x, f, and control and status registers.
typedef enum cm_reg {
- // Processor x registers
+ // Machine x registers
CM_REG_X0,
CM_REG_X1,
CM_REG_X2,
@@ -163,7 +163,7 @@ typedef enum cm_reg {
CM_REG_X29,
CM_REG_X30,
CM_REG_X31,
- // Processor f registers
+ // Machine f registers
CM_REG_F0,
CM_REG_F1,
CM_REG_F2,
@@ -196,7 +196,7 @@ typedef enum cm_reg {
CM_REG_F29,
CM_REG_F30,
CM_REG_F31,
- // Processor CSRs
+ // Machine CSRs
CM_REG_PC,
CM_REG_FCSR,
CM_REG_MVENDORID,
diff --git a/src/machine-config.cpp b/src/machine-config.cpp
index ea11b6f98..c44d0c999 100644
--- a/src/machine-config.cpp
+++ b/src/machine-config.cpp
@@ -31,7 +31,7 @@
#include "json-util.h"
#include "pmas-constants.h"
-static constexpr uint32_t archive_version = 5;
+static constexpr uint32_t archive_version = 6;
namespace cartesi {
@@ -62,28 +62,34 @@ std::string machine_config::get_config_filename(const std::string &dir) {
return dir + "/config.json";
}
-static void adjust_backing_store(uint64_t start, uint64_t length, const std::string &dir, backing_store_config &c) {
+void machine_config::adjust_backing_store_config(uint64_t start, uint64_t length, const std::string &dir,
+ backing_store_config &c) {
+ c.shared = false;
+ c.create = false;
+ c.truncate = false;
c.data_filename = machine_config::get_data_filename(dir, start, length);
c.dht_filename = machine_config::get_dht_filename(dir, start, length);
}
-static void adjust_hash_tree(const std::string &dir, hash_tree_config &c) {
+void machine_config::adjust_hash_tree_config(const std::string &dir, hash_tree_config &c) {
c.sht_filename = machine_config::get_sht_filename(dir);
c.phtc_filename = machine_config::get_phtc_filename(dir);
}
-static void adjust_backing_store(machine_config &c, const std::string &dir) {
- adjust_backing_store(AR_RAM_START, c.ram.length, dir, c.ram.backing_store);
- adjust_backing_store(AR_DTB_START, AR_DTB_LENGTH, dir, c.dtb.backing_store);
- for (auto &f : c.flash_drive) {
- adjust_backing_store(f.start, f.length, dir, f.backing_store);
+void machine_config::adjust_backing_stores(const std::string &dir) {
+ adjust_backing_store_config(AR_RAM_START, ram.length, dir, ram.backing_store);
+ adjust_backing_store_config(AR_DTB_START, AR_DTB_LENGTH, dir, dtb.backing_store);
+ for (auto &f : flash_drive) {
+ adjust_backing_store_config(f.start, f.length, dir, f.backing_store);
}
- adjust_backing_store(AR_SHADOW_TLB_START, AR_SHADOW_TLB_LENGTH, dir, c.tlb.backing_store);
- adjust_backing_store(AR_CMIO_RX_BUFFER_START, AR_CMIO_RX_BUFFER_LENGTH, dir, c.cmio.rx_buffer.backing_store);
- adjust_backing_store(AR_CMIO_TX_BUFFER_START, AR_CMIO_TX_BUFFER_LENGTH, dir, c.cmio.tx_buffer.backing_store);
- adjust_backing_store(AR_PMAS_START, AR_PMAS_LENGTH, dir, c.pmas.backing_store);
- adjust_backing_store(AR_UARCH_RAM_START, AR_UARCH_RAM_LENGTH, dir, c.uarch.ram.backing_store);
- adjust_hash_tree(dir, c.hash_tree);
+ adjust_backing_store_config(AR_SHADOW_STATE_START, AR_SHADOW_STATE_LENGTH, dir, processor.backing_store);
+ adjust_backing_store_config(AR_CMIO_RX_BUFFER_START, AR_CMIO_RX_BUFFER_LENGTH, dir, cmio.rx_buffer.backing_store);
+ adjust_backing_store_config(AR_CMIO_TX_BUFFER_START, AR_CMIO_TX_BUFFER_LENGTH, dir, cmio.tx_buffer.backing_store);
+ adjust_backing_store_config(AR_PMAS_START, AR_PMAS_LENGTH, dir, pmas.backing_store);
+ adjust_backing_store_config(AR_SHADOW_UARCH_STATE_START, AR_SHADOW_UARCH_STATE_LENGTH, dir,
+ uarch.processor.backing_store);
+ adjust_backing_store_config(AR_UARCH_RAM_START, AR_UARCH_RAM_LENGTH, dir, uarch.ram.backing_store);
+ adjust_hash_tree_config(dir, hash_tree);
}
machine_config machine_config::load(const std::string &dir) {
@@ -107,7 +113,7 @@ machine_config machine_config::load(const std::string &dir) {
std::to_string(jv.get()) + ")");
}
ju_get_field(j, std::string("config"), c, "");
- adjust_backing_store(c, dir);
+ c.adjust_backing_stores(dir);
} catch (std::exception &e) {
throw std::runtime_error{e.what()};
}
diff --git a/src/machine-config.h b/src/machine-config.h
index e8b058ca5..687171ca6 100644
--- a/src/machine-config.h
+++ b/src/machine-config.h
@@ -24,6 +24,8 @@
#include
#include "riscv-constants.h"
+#include "shadow-registers.h"
+#include "shadow-uarch-state.h"
namespace cartesi {
@@ -34,57 +36,21 @@ enum machine_config_constants {
VIRTIO_HOSTFWD_MAX = 16, ///< Maximum number of virtio net user host forward ports
};
-/// \brief Processor state config
-struct processor_config final {
- std::array x{REG_X0, REG_X1, REG_X2, REG_X3, REG_X4, REG_X5, REG_X6, REG_X7, REG_X8, REG_X9,
- REG_X10, REG_X11, REG_X12, REG_X13, REG_X14, REG_X15, REG_X16, REG_X17, REG_X18, REG_X19, REG_X20, REG_X21,
- REG_X22, REG_X23, REG_X24, REG_X25, REG_X26, REG_X27, REG_X28, REG_X29, REG_X30,
- REG_X31}; ///< Value of general-purpose registers
- std::array f{}; ///< Value of floating-point registers
- uint64_t pc{PC_INIT}; ///< Value of pc
- uint64_t fcsr{FCSR_INIT}; ///< Value of fcsr CSR
- uint64_t mvendorid{MVENDORID_INIT}; ///< Value of mvendorid CSR
- uint64_t marchid{MARCHID_INIT}; ///< Value of marchid CSR
- uint64_t mimpid{MIMPID_INIT}; ///< Value of mimpid CSR
- uint64_t mcycle{MCYCLE_INIT}; ///< Value of mcycle CSR
- uint64_t icycleinstret{ICYCLEINSTRET_INIT}; ///< Value of icycleinstret CSR
- uint64_t mstatus{MSTATUS_INIT}; ///< Value of mstatus CSR
- uint64_t mtvec{MTVEC_INIT}; ///< Value of mtvec CSR
- uint64_t mscratch{MSCRATCH_INIT}; ///< Value of mscratch CSR
- uint64_t mepc{MEPC_INIT}; ///< Value of mepc CSR
- uint64_t mcause{MCAUSE_INIT}; ///< Value of mcause CSR
- uint64_t mtval{MTVAL_INIT}; ///< Value of mtval CSR
- uint64_t misa{MISA_INIT}; ///< Value of misa CSR
- uint64_t mie{MIE_INIT}; ///< Value of mie CSR
- uint64_t mip{MIP_INIT}; ///< Value of mip CSR
- uint64_t medeleg{MEDELEG_INIT}; ///< Value of medeleg CSR
- uint64_t mideleg{MIDELEG_INIT}; ///< Value of mideleg CSR
- uint64_t mcounteren{MCOUNTEREN_INIT}; ///< Value of mcounteren CSR
- uint64_t menvcfg{MENVCFG_INIT}; ///< Value of menvcfg CSR
- uint64_t stvec{STVEC_INIT}; ///< Value of stvec CSR
- uint64_t sscratch{SSCRATCH_INIT}; ///< Value of sscratch CSR
- uint64_t sepc{SEPC_INIT}; ///< Value of sepc CSR
- uint64_t scause{SCAUSE_INIT}; ///< Value of scause CSR
- uint64_t stval{STVAL_INIT}; ///< Value of stval CSR
- uint64_t satp{SATP_INIT}; ///< Value of satp CSR
- uint64_t scounteren{SCOUNTEREN_INIT}; ///< Value of scounteren CSR
- uint64_t senvcfg{SENVCFG_INIT}; ///< Value of senvcfg CSR
- uint64_t ilrsc{ILRSC_INIT}; ///< Value of ilrsc CSR
- uint64_t iprv{IPRV_INIT}; ///< Value of iprv CSR
- uint64_t iflags_X{IFLAGS_X_INIT}; ///< Value of iflags_X CSR
- uint64_t iflags_Y{IFLAGS_Y_INIT}; ///< Value of iflags_Y CSR
- uint64_t iflags_H{IFLAGS_H_INIT}; ///< Value of iflags_H CSR
- uint64_t iunrep{IUNREP_INIT}; ///< Value of iunrep CSR
-};
-
/// \brief Backing store config
struct backing_store_config final {
bool shared{false}; ///< Should changes be reflected in backing store?
+ bool create{false}; ///< Should backing store be created?
bool truncate{false}; ///< Should backing store be truncated to correct size?
std::string data_filename; ///< Backing store for associated memory address range
std::string dht_filename; ///< Backing store for corresponding dense hash-tree
};
+/// \brief Processor state config
+struct processor_config final {
+ registers_state registers;
+ backing_store_config backing_store;
+};
+
/// \brief Config with only backing store config field
struct backing_store_config_only final {
backing_store_config backing_store;
@@ -92,8 +58,8 @@ struct backing_store_config_only final {
/// \brief RAM state config
struct ram_config final {
- uint64_t length{0}; ///< RAM length
- backing_store_config backing_store; ///< Backing store
+ uint64_t length{0}; ///< RAM length
+ backing_store_config backing_store{.truncate = true}; ///< Backing store
};
/// \brief DTB state config
@@ -117,29 +83,6 @@ struct memory_range_config final {
/// \brief List of flash drives
using flash_drive_configs = std::vector;
-/// \brief TLB device state config
-using tlb_config = backing_store_config_only;
-
-/// \brief CLINT device state config
-struct clint_config final {
- uint64_t mtimecmp{MTIMECMP_INIT}; ///< Value of mtimecmp CSR
-};
-
-/// \brief PLIC device state config
-struct plic_config final {
- uint64_t girqpend{GIRQPEND_INIT}; ///< Value of girqpend CSR
- uint64_t girqsrvd{GIRQSRVD_INIT}; ///< Value of girqsrvd CSR
-};
-
-/// \brief HTIF device state config
-struct htif_config final {
- uint64_t fromhost{FROMHOST_INIT}; ///< Value of fromhost CSR
- uint64_t tohost{TOHOST_INIT}; ///< Value of tohost CSR
- bool console_getchar{false}; ///< Make console getchar available?
- bool yield_manual{true}; ///< Make yield manual available?
- bool yield_automatic{true}; ///< Make yield automatic available?
-};
-
/// \brief VirtIO console device state config
struct virtio_console_config final {};
@@ -193,24 +136,23 @@ using pmas_config = backing_store_config_only;
/// \brief Uarch RAM config
using uarch_ram_config = backing_store_config_only;
-/// \brief Uarch processor config
+/// \brief Uarch processor state config
struct uarch_processor_config final {
- std::array x{}; ///< Value of general-purpose registers
- uint64_t pc{UARCH_PC_INIT}; ///< Value of pc
- uint64_t cycle{UARCH_CYCLE_INIT}; ///< Value of ucycle counter
- uint64_t halt_flag{};
+ uarch_registers_state registers; ///< Uarch registers
+ backing_store_config backing_store;
};
/// \brief Uarch config
struct uarch_config final {
- uarch_processor_config processor{}; ///< Uarch processor
- uarch_ram_config ram{}; ///< Uarch RAM
+ uarch_processor_config processor{}; ///< Uarch processor
+ uarch_ram_config ram{.backing_store = {.truncate = true}}; ///< Uarch RAM
};
/// \brief Hash tree config
struct hash_tree_config final {
std::string hasher{"keccak"}; ///< What hashing function to use?
bool shared{false}; ///< Should changes be reflected in backing store?
+ bool create{false}; ///< Should backing store be created to correct size?
bool truncate{false}; ///< Should backing store be truncated to correct size?
std::string sht_filename; ///< Backing storage for sparse hash-tree
std::string phtc_filename; ///< Backing storage for page hash-tree cache
@@ -223,10 +165,6 @@ struct machine_config final {
ram_config ram{}; ///< RAM config
dtb_config dtb{}; ///< Device Tree config
flash_drive_configs flash_drive; ///< Flash drives config
- tlb_config tlb{}; ///< Translation Look-aside Buffer config
- clint_config clint{}; ///< Core-Local Interruptor config
- plic_config plic{}; ///< Platform-Level Interrupt Controller config
- htif_config htif{}; ///< Host-Target config InterFace config
virtio_configs virtio; ///< VirtIO devices config
cmio_config cmio{}; ///< Cartesi Machine IO config
pmas_config pmas{}; ///< Physical Memory Attributes config
@@ -248,6 +186,13 @@ struct machine_config final {
/// \brief Get the name where global page hash-tree cache will be stored in a directory
static std::string get_phtc_filename(const std::string &dir);
+ static void adjust_backing_store_config(uint64_t start, uint64_t length, const std::string &dir,
+ backing_store_config &c);
+
+ static void adjust_hash_tree_config(const std::string &dir, hash_tree_config &c);
+
+ void adjust_backing_stores(const std::string &dir);
+
/// \brief Loads a machine config from a directory
/// \param dir Directory from whence "config" will be loaded
/// \returns The config loaded
diff --git a/src/machine-reg.h b/src/machine-reg.h
index d8865c4a9..277b69bac 100644
--- a/src/machine-reg.h
+++ b/src/machine-reg.h
@@ -17,8 +17,7 @@
#ifndef MACHINE_REG_H
#define MACHINE_REG_H
-#include "shadow-state-address-range.h"
-#include "shadow-uarch-state-address-range.h"
+#include "shadow-uarch-state.h"
/// \file
/// \brief Cartesi machine registers
@@ -27,113 +26,112 @@ namespace cartesi {
/// \brief List of machine registers
enum class machine_reg : uint64_t {
- // Processor x registers
- x0 = static_cast(shadow_state_what::x0),
- x1 = static_cast(shadow_state_what::x1),
- x2 = static_cast(shadow_state_what::x2),
- x3 = static_cast(shadow_state_what::x3),
- x4 = static_cast(shadow_state_what::x4),
- x5 = static_cast(shadow_state_what::x5),
- x6 = static_cast(shadow_state_what::x6),
- x7 = static_cast(shadow_state_what::x7),
- x8 = static_cast(shadow_state_what::x8),
- x9 = static_cast(shadow_state_what::x9),
- x10 = static_cast(shadow_state_what::x10),
- x11 = static_cast(shadow_state_what::x11),
- x12 = static_cast(shadow_state_what::x12),
- x13 = static_cast(shadow_state_what::x13),
- x14 = static_cast(shadow_state_what::x14),
- x15 = static_cast(shadow_state_what::x15),
- x16 = static_cast(shadow_state_what::x16),
- x17 = static_cast(shadow_state_what::x17),
- x18 = static_cast(shadow_state_what::x18),
- x19 = static_cast(shadow_state_what::x19),
- x20 = static_cast(shadow_state_what::x20),
- x21 = static_cast(shadow_state_what::x21),
- x22 = static_cast(shadow_state_what::x22),
- x23 = static_cast(shadow_state_what::x23),
- x24 = static_cast(shadow_state_what::x24),
- x25 = static_cast(shadow_state_what::x25),
- x26 = static_cast(shadow_state_what::x26),
- x27 = static_cast(shadow_state_what::x27),
- x28 = static_cast(shadow_state_what::x28),
- x29 = static_cast(shadow_state_what::x29),
- x30 = static_cast(shadow_state_what::x30),
- x31 = static_cast(shadow_state_what::x31),
- f0 = static_cast(shadow_state_what::f0),
- f1 = static_cast(shadow_state_what::f1),
- f2 = static_cast(shadow_state_what::f2),
- f3 = static_cast(shadow_state_what::f3),
- f4 = static_cast(shadow_state_what::f4),
- f5 = static_cast(shadow_state_what::f5),
- f6 = static_cast(shadow_state_what::f6),
- f7 = static_cast(shadow_state_what::f7),
- f8 = static_cast(shadow_state_what::f8),
- f9 = static_cast(shadow_state_what::f9),
- f10 = static_cast(shadow_state_what::f10),
- f11 = static_cast(shadow_state_what::f11),
- f12 = static_cast(shadow_state_what::f12),
- f13 = static_cast(shadow_state_what::f13),
- f14 = static_cast(shadow_state_what::f14),
- f15 = static_cast(shadow_state_what::f15),
- f16 = static_cast(shadow_state_what::f16),
- f17 = static_cast(shadow_state_what::f17),
- f18 = static_cast(shadow_state_what::f18),
- f19 = static_cast(shadow_state_what::f19),
- f20 = static_cast(shadow_state_what::f20),
- f21 = static_cast(shadow_state_what::f21),
- f22 = static_cast(shadow_state_what::f22),
- f23 = static_cast(shadow_state_what::f23),
- f24 = static_cast(shadow_state_what::f24),
- f25 = static_cast(shadow_state_what::f25),
- f26 = static_cast(shadow_state_what::f26),
- f27 = static_cast(shadow_state_what::f27),
- f28 = static_cast(shadow_state_what::f28),
- f29 = static_cast(shadow_state_what::f29),
- f30 = static_cast(shadow_state_what::f30),
- f31 = static_cast(shadow_state_what::f31),
- pc = static_cast(shadow_state_what::pc),
- fcsr = static_cast(shadow_state_what::fcsr),
- mvendorid = static_cast(shadow_state_what::mvendorid),
- marchid = static_cast(shadow_state_what::marchid),
- mimpid = static_cast(shadow_state_what::mimpid),
- mcycle = static_cast(shadow_state_what::mcycle),
- icycleinstret = static_cast(shadow_state_what::icycleinstret),
- mstatus = static_cast(shadow_state_what::mstatus),
- mtvec = static_cast(shadow_state_what::mtvec),
- mscratch = static_cast(shadow_state_what::mscratch),
- mepc = static_cast(shadow_state_what::mepc),
- mcause = static_cast(shadow_state_what::mcause),
- mtval = static_cast(shadow_state_what::mtval),
- misa = static_cast