From 2fa30c6c77546f4d474407d7e06f55c287b9de1a Mon Sep 17 00:00:00 2001 From: Marcos Pernambuco Motta <1091485+mpernambuco@users.noreply.github.com> Date: Wed, 23 Oct 2024 20:24:18 -0300 Subject: [PATCH] feat: add SendCmioResponse --- CHANGELOG.md | 2 + Makefile | 40 +- README.md | 2 +- helper_scripts/generate_EmulatorConstants.lua | 38 ++ ...tants.sh => generate_EmulatorConstants.sh} | 6 +- helper_scripts/generate_SendCmioResponse.sh | 54 ++ helper_scripts/generate_UArchConstants.lua | 32 -- helper_scripts/generate_UArchReset.sh | 6 +- helper_scripts/generate_UArchStep.sh | 12 +- shasum-mock | 4 +- shasum-prod | 4 +- src/AccessLogs.sol | 2 +- src/{UArchCompat.sol => EmulatorCompat.sol} | 79 ++- ...rchConstants.sol => EmulatorConstants.sol} | 28 +- src/MetaStep.sol | 6 +- src/SendCmioResponse.sol | 80 +++ src/UArchReset.sol | 4 +- src/UArchStep.sol | 476 +++++++++--------- templates/AccessLogs.sol.template | 14 +- ...emplate => EmulatorConstants.sol.template} | 7 +- templates/SendCmioResponse.sol.template | 32 ++ templates/UArchReset.sol.template | 2 +- templates/UArchStep.sol.template | 2 +- test/EmulatorCompat.t.sol | 161 ++++++ test/SendCmioResponse.t.sol | 177 +++++++ test/UArchCompat.t.sol | 145 ------ test/UArchInterpret.t.sol | 26 +- test/UArchReset.t.sol | 6 +- 28 files changed, 949 insertions(+), 498 deletions(-) create mode 100755 helper_scripts/generate_EmulatorConstants.lua rename helper_scripts/{generate_UArchConstants.sh => generate_EmulatorConstants.sh} (83%) create mode 100755 helper_scripts/generate_SendCmioResponse.sh delete mode 100755 helper_scripts/generate_UArchConstants.lua rename src/{UArchCompat.sol => EmulatorCompat.sol} (69%) rename src/{UArchConstants.sol => EmulatorConstants.sol} (58%) create mode 100644 src/SendCmioResponse.sol rename templates/{UArchConstants.sol.template => EmulatorConstants.sol.template} (84%) create mode 100644 templates/SendCmioResponse.sol.template create mode 100644 test/EmulatorCompat.t.sol create mode 100644 test/SendCmioResponse.t.sol delete mode 100644 test/UArchCompat.t.sol diff --git a/CHANGELOG.md b/CHANGELOG.md index 62b6b7e8..ecb380d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Added SendCmioResponse ## [0.12.1] - 2024-08-12 ### Changed diff --git a/Makefile b/Makefile index ff9df248..7f345c8f 100644 --- a/Makefile +++ b/Makefile @@ -21,26 +21,27 @@ DEPDIRS = $(TESTS_DATA_DIR) $(LOG_TEST_DIR) help: @echo 'Cleaning targets:' - @echo ' clean - clean the cache artifacts and generated files' + @echo ' clean - clean the cache artifacts and generated files' @echo 'Generic targets:' - @echo '* all - build solidity code. To build from a clean clone, run: make submodules all' - @echo ' build - build solidity code' - @echo ' generate-step - generate solidity-step code from cpp' - @echo ' generate-reset - generate solidity-reset code from cpp' - @echo ' generate-constants - generate solidity-constants code by querying the cartesi machine' - @echo ' generate-mock - generate mock library code' - @echo ' generate-prod - generate production library code' - @echo ' generate-replay - generate replay tests' - @echo ' pretest - download necessary files for tests' - @echo ' test-all - test all' - @echo ' test-mock - test binary files with mock library' - @echo ' test-prod - test production code' - @echo ' test-replay - test log files' + @echo '* all - build solidity code. To build from a clean clone, run: make submodules all' + @echo ' build - build solidity code' + @echo ' generate-step - generate solidity-step code from cpp' + @echo ' generate-reset - generate solidity-reset code from cpp' + @echo ' generate-send-cmio-response - generate solidity-send-cmio-response code from cpp' + @echo ' generate-constants - generate solidity-constants code by querying the cartesi machine' + @echo ' generate-mock - generate mock library code' + @echo ' generate-prod - generate production library code' + @echo ' generate-replay - generate replay tests' + @echo ' pretest - download necessary files for tests' + @echo ' test-all - test all' + @echo ' test-mock - test binary files with mock library' + @echo ' test-prod - test production code' + @echo ' test-replay - test log files' all: build test-all -build: generate-step generate-reset generate-constants generate-prod +build: generate-step generate-reset generate-send-cmio-response generate-constants generate-prod forge build --use 0.8.21 clean: @@ -64,7 +65,7 @@ test-prod: dep test-replay: dep $(MAKE) generate-prod $(MAKE) generate-replay - forge test --use 0.8.21 -vv --match-contract "UArchReplay|UArchReset" + forge test --use 0.8.21 -vv --match-contract "UArchReset|SendCmioResponse|UArchReplay" generate-mock: ./helper_scripts/generate_AccessLogs.sh mock @@ -79,7 +80,7 @@ generate-replay: $(MAKE) fmt generate-constants: $(EMULATOR_DIR) - EMULATOR_DIR=$(EMULATOR_DIR) ./helper_scripts/generate_UArchConstants.sh + EMULATOR_DIR=$(EMULATOR_DIR) ./helper_scripts/generate_EmulatorConstants.sh generate-step: $(EMULATOR_DIR)/src/uarch-step.h $(EMULATOR_DIR)/src/uarch-step.cpp EMULATOR_DIR=$(EMULATOR_DIR) ./helper_scripts/generate_UArchStep.sh @@ -87,6 +88,9 @@ generate-step: $(EMULATOR_DIR)/src/uarch-step.h $(EMULATOR_DIR)/src/uarch-step.c generate-reset: $(EMULATOR_DIR)/src/uarch-reset-state.cpp EMULATOR_DIR=$(EMULATOR_DIR) ./helper_scripts/generate_UArchReset.sh +generate-send-cmio-response: $(EMULATOR_DIR)/src/uarch-reset-state.cpp + EMULATOR_DIR=$(EMULATOR_DIR) ./helper_scripts/generate_SendCmioResponse.sh + fmt: forge fmt src test @@ -119,4 +123,4 @@ $(LOG_TEST_DIR): | download submodules: git submodule update --init --recursive -.PHONY: help all build clean checksum-download shasum-download fmt generate-mock generate-prod generate-replay generate-step pretest submodules test-all test-mock test-prod test-replay generate-constants generate-reset +.PHONY: help all build clean checksum-download shasum-download fmt generate-mock generate-prod generate-replay generate-step pretest submodules test-all test-mock test-prod test-replay generate-constants generate-reset geme gemerate=semd-cmio-response diff --git a/README.md b/README.md index 7692a1a0..b9e78727 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The `UArchExecuteInsn` contract consists of the machine instruction logic, such ## Compatibility Layer -The `UArchCompat` contract is taking care of all the differences in the two implementations. Ranging from programming languages (Cpp versus Solidity) to architectural differences (RISC-V versus EVM). +The `EmulatorCompat` contract is taking care of all the differences in the two implementations. Ranging from programming languages (Cpp versus Solidity) to architectural differences (RISC-V versus EVM). ## Getting Started diff --git a/helper_scripts/generate_EmulatorConstants.lua b/helper_scripts/generate_EmulatorConstants.lua new file mode 100755 index 00000000..886fb823 --- /dev/null +++ b/helper_scripts/generate_EmulatorConstants.lua @@ -0,0 +1,38 @@ +#!/usr/bin/lua5.4 + +-- This scripts generates a snippet of solidity code to be inserted +-- in the EmulatorhConstants.sol file. + +local cartesi = require("cartesi") + +local function hex(n) + return string.format("%x", n) +end + +local function hexstring(hash) + return (string.gsub(hash, ".", function(c) return string.format("%02x", string.byte(c)) end)) +end + +local out = io.stdout + +out:write(' uint64 constant UARCH_CYCLE_ADDRESS = 0x' .. hex(cartesi.machine.get_csr_address("uarch_cycle")) .. ';\n') +out:write(' uint64 constant UARCH_HALT_FLAG_ADDRESS = 0x' .. hex(cartesi.machine.get_csr_address("uarch_halt_flag")) .. ';\n') +out:write(' uint64 constant UARCH_PC_ADDRESS = 0x' .. hex(cartesi.machine.get_csr_address("uarch_pc")) .. ';\n') +out:write(' uint64 constant UARCH_X0_ADDRESS = 0x' .. hex(cartesi.machine.get_uarch_x_address(0)) .. ';\n') +out:write(' uint64 constant UARCH_SHADOW_START_ADDRESS = 0x' .. hex(cartesi.UARCH_SHADOW_START_ADDRESS) .. ';\n') +out:write(' uint64 constant UARCH_SHADOW_LENGTH = 0x' .. hex(cartesi.UARCH_SHADOW_LENGTH) .. ';\n') +out:write(' uint64 constant UARCH_RAM_START_ADDRESS = 0x' .. hex(cartesi.UARCH_RAM_START_ADDRESS) .. ';\n') +out:write(' uint64 constant UARCH_RAM_LENGTH = 0x' .. hex(cartesi.UARCH_RAM_LENGTH) .. ';\n') +out:write(' uint64 constant UARCH_STATE_START_ADDRESS = 0x' .. hex(cartesi.UARCH_STATE_START_ADDRESS) .. ';\n') +out:write(' uint8 constant UARCH_STATE_LOG2_SIZE = ' .. cartesi.UARCH_STATE_LOG2_SIZE .. ';\n') +out:write(' bytes32 constant UARCH_PRISTINE_STATE_HASH = 0x' .. hexstring(cartesi.UARCH_PRISTINE_STATE_HASH) .. ';\n') +out:write(' uint64 constant UARCH_ECALL_FN_HALT = ' .. cartesi.UARCH_ECALL_FN_HALT .. ';\n') +out:write(' uint64 constant UARCH_ECALL_FN_PUTCHAR = ' .. cartesi.UARCH_ECALL_FN_PUTCHAR .. ';\n') +out:write(' uint64 constant IFLAGS_ADDRESS = 0x' .. hex(cartesi.machine.get_csr_address("iflags")) .. ';\n') +out:write(' uint64 constant HTIF_FROMHOST_ADDRESS = 0x' .. hex(cartesi.machine.get_csr_address("htif_fromhost")) .. ';\n') +out:write(' uint32 constant TREE_LOG2_WORD_SIZE = 0x' .. hex(cartesi.TREE_LOG2_WORD_SIZE) .. ';\n') +out:write(' uint32 constant TREE_WORD_SIZE = uint32(1) << TREE_LOG2_WORD_SIZE;\n') +out:write(' uint64 constant PMA_CMIO_RX_BUFFER_START = 0x'.. hex(cartesi.PMA_CMIO_RX_BUFFER_START) .. ';\n') +out:close() + +out:close() diff --git a/helper_scripts/generate_UArchConstants.sh b/helper_scripts/generate_EmulatorConstants.sh similarity index 83% rename from helper_scripts/generate_UArchConstants.sh rename to helper_scripts/generate_EmulatorConstants.sh index 74a059cb..8a5b6020 100755 --- a/helper_scripts/generate_UArchConstants.sh +++ b/helper_scripts/generate_EmulatorConstants.sh @@ -4,8 +4,8 @@ set -e EMULATOR_DIR=${EMULATOR_DIR:-"../emulator"} -TEMPLATE_FILE="./templates/UArchConstants.sol.template" -TARGET_FILE="src/UArchConstants.sol" +TEMPLATE_FILE="./templates/EmulatorConstants.sol.template" +TARGET_FILE="src/EmulatorConstants.sol" KEYWORD_START="START OF AUTO-GENERATED CODE" KEYWORD_END="END OF AUTO-GENERATED CODE" @@ -28,7 +28,7 @@ constants=$(docker run --rm \ -v`pwd`:/opt/cartesi/machine-solidity-step \ -w /opt/cartesi/machine-solidity-step \ cartesi/machine-emulator:devel \ - /opt/cartesi/machine-solidity-step/helper_scripts/generate_UArchConstants.lua) + /opt/cartesi/machine-solidity-step/helper_scripts/generate_EmulatorConstants.lua) # compose the solidity file from all components echo -e "$h" "\n\n$constants" > $TARGET_FILE diff --git a/helper_scripts/generate_SendCmioResponse.sh b/helper_scripts/generate_SendCmioResponse.sh new file mode 100755 index 00000000..69a71d06 --- /dev/null +++ b/helper_scripts/generate_SendCmioResponse.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +set -e + +SED=${SED:-"sed"} +EMULATOR_DIR=${EMULATOR_DIR:-"../emulator"} +CPP_RESET_PATH=${EMULATOR_DIR}"/src/send-cmio-response.cpp" + +TEMPLATE_FILE="./templates/SendCmioResponse.sol.template" +TARGET_FILE="src/SendCmioResponse.sol" +COMPAT_FILE="src/EmulatorCompat.sol" +CONSTANTS_FILE="src/EmulatorConstants.sol" +KEYWORD_START="START OF AUTO-GENERATED CODE" +KEYWORD_END="END OF AUTO-GENERATED CODE" + +# get function names from EmulatorCompat.sol +COMPAT_FNS=`cat $COMPAT_FILE | grep -o "function [^(]*(" | $SED "s/function//g" | $SED "s/(//g"` +COMPAT_FNS=`echo $COMPAT_FNS | $SED -E "s/( |\n)/|/g"` + +# get constant names from EmulatorConstants.sol +CONSTANTS=`cat $CONSTANTS_FILE | grep -E -o 'constant\s+[^ ]*' | $SED -E "s/constant//g; s/ //g" | tr '\n' '|' | sed "s/.$//"` + +# grab head and tail of the template +start=`cat "$TEMPLATE_FILE" | grep "$KEYWORD_START" -n | grep -Eo "[0-9]*"` +end=`cat "$TEMPLATE_FILE" | grep "$KEYWORD_END" -n | grep -Eo "[0-9]*"` +total=`wc -l "$TEMPLATE_FILE" | grep -Eo "[0-9]*"` +let last=total-end+1 + +h=`head -n $start $TEMPLATE_FILE` +t=`tail -n -$last $TEMPLATE_FILE` + +cpp_src=`cat "$CPP_RESET_PATH"` +pattern="namespace cartesi \{(.*)\}" +[[ $cpp_src =~ $pattern ]] + +# replace cpp specific syntaxes with solidity ones +cpp_src=`echo "${BASH_REMATCH[1]}" \ + | $SED "/Explicit instantiatio/d" \ + | $SED "/template/d" \ + | $SED "s/machine_merkle_tree::get_log2_word_size()/TREE_LOG2_WORD_SIZE/g" \ + | $SED -E "s/($COMPAT_FNS)/EmulatorCompat.\1/g" \ + | $SED "s/writeMemoryWithPadding(a, PMA_CMIO_RX_BUFFER_START, data, dataLength, writeLengthLog2Size);/a.writeRegion(Memory.regionFromPhysicalAddress(PMA_CMIO_RX_BUFFER_START.toPhysicalAddress(),Memory.alignedSizeFromLog2(uint8(writeLengthLog2Size - TREE_LOG2_WORD_SIZE))),dataHash);"/g \ + | $SED -E "s/($CONSTANTS)([^a-zA-Z])/EmulatorConstants.\1\2/g" \ + | $SED "s/void send_cmio_response(STATE_ACCESS &a, uint16 reason, bytes data, uint32 dataLength) {/function sendCmioResponse(AccessLogs.Context memory a, uint16 reason, bytes32 dataHash, uint32 dataLength) internal pure {/" \ + | $SED "s/writeMemoryWithPadding(a, PMA_CMIO_RX_BUFFER_START, data, dataLength, writeLengthLog2Size);/a.writeRegion(Memory.regionFromPhysicalAddress(PMA_CMIO_RX_BUFFER_START.toPhysicalAddress(),Memory.alignedSizeFromLog2(writeLengthLog2Size)),dataHash);"/g \ + | $SED "s/const uint64/uint64/g" \ + | $SED "s/const uint32/uint32/g" \ + | $SED "/^$/N;/^\n$/D" + ` + +# compose the solidity file from all components +echo -e "$h" "\n\n$h_src" > $TARGET_FILE +echo "$cpp_src" >> $TARGET_FILE +echo -e "\n$t" >> $TARGET_FILE diff --git a/helper_scripts/generate_UArchConstants.lua b/helper_scripts/generate_UArchConstants.lua deleted file mode 100755 index 072b4cb4..00000000 --- a/helper_scripts/generate_UArchConstants.lua +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/lua5.4 - --- This scripts generates a snippet of solidity code to be inserted --- in the UarchConstants.sol file. - -local cartesi = require("cartesi") - -local function hex(n) - return string.format("%x", n) -end - -local function hexstring(hash) - return (string.gsub(hash, ".", function(c) return string.format("%02x", string.byte(c)) end)) -end - -local out = io.stdout - -out:write(' uint64 constant UCYCLE = 0x' .. hex(cartesi.machine.get_csr_address("uarch_cycle")) .. ';\n') -out:write(' uint64 constant UHALT = 0x' .. hex(cartesi.machine.get_csr_address("uarch_halt_flag")) .. ';\n') -out:write(' uint64 constant UPC = 0x' .. hex(cartesi.machine.get_csr_address("uarch_pc")) .. ';\n') -out:write(' uint64 constant UX0 = 0x' .. hex(cartesi.machine.get_uarch_x_address(0)) .. ';\n') -out:write(' uint64 constant UARCH_SHADOW_START_ADDRESS = 0x' .. hex(cartesi.UARCH_SHADOW_START_ADDRESS) .. ';\n') -out:write(' uint64 constant UARCH_SHADOW_LENGTH = 0x' .. hex(cartesi.UARCH_SHADOW_LENGTH) .. ';\n') -out:write(' uint64 constant UARCH_RAM_START_ADDRESS = 0x' .. hex(cartesi.UARCH_RAM_START_ADDRESS) .. ';\n') -out:write(' uint64 constant UARCH_RAM_LENGTH = 0x' .. hex(cartesi.UARCH_RAM_LENGTH) .. ';\n') -out:write(' uint64 constant RESET_POSITION = 0x' .. hex(cartesi.UARCH_STATE_START_ADDRESS) .. ';\n') -out:write(' uint8 constant RESET_ALIGNED_SIZE = ' .. cartesi.UARCH_STATE_LOG2_SIZE .. ';\n') -out:write(' bytes32 constant PRESTINE_STATE = 0x' .. hexstring(cartesi.UARCH_PRISTINE_STATE_HASH) .. ';\n') -out:write(' uint64 constant UARCH_ECALL_FN_HALT = ' .. cartesi.UARCH_ECALL_FN_HALT .. ';\n') -out:write(' uint64 constant UARCH_ECALL_FN_PUTCHAR = ' .. cartesi.UARCH_ECALL_FN_PUTCHAR .. ';\n') - -out:close() diff --git a/helper_scripts/generate_UArchReset.sh b/helper_scripts/generate_UArchReset.sh index 78937f27..bf3f1364 100755 --- a/helper_scripts/generate_UArchReset.sh +++ b/helper_scripts/generate_UArchReset.sh @@ -8,11 +8,11 @@ CPP_RESET_PATH=${EMULATOR_DIR}"/src/uarch-reset-state.cpp" TEMPLATE_FILE="./templates/UArchReset.sol.template" TARGET_FILE="src/UArchReset.sol" -COMPAT_FILE="src/UArchCompat.sol" +COMPAT_FILE="src/EmulatorCompat.sol" KEYWORD_START="START OF AUTO-GENERATED CODE" KEYWORD_END="END OF AUTO-GENERATED CODE" -# get function names from UArchCompat.sol +# get function names from EmulatorCompat.sol COMPAT_FNS=`cat $COMPAT_FILE | grep -o "function [^(]*(" | $SED "s/function//g" | $SED "s/(//g"` COMPAT_FNS=`echo $COMPAT_FNS | $SED -E "s/( |\n)/|/g"` @@ -33,7 +33,7 @@ pattern="namespace cartesi \{(.*)\}" cpp_src=`echo "${BASH_REMATCH[1]}" \ | $SED "/Explicit instantiatio/d" \ | $SED "/template/d" \ - | $SED -E "s/($COMPAT_FNS)/UArchCompat.\1/g" \ + | $SED -E "s/($COMPAT_FNS)/EmulatorCompat.\1/g" \ | $SED "s/void uarch_reset_state(UarchState &a) {/function reset(AccessLogs.Context memory a) internal pure {/"` # compose the solidity file from all components diff --git a/helper_scripts/generate_UArchStep.sh b/helper_scripts/generate_UArchStep.sh index 6e879239..d923a811 100755 --- a/helper_scripts/generate_UArchStep.sh +++ b/helper_scripts/generate_UArchStep.sh @@ -9,8 +9,8 @@ CPP_STEP_H_PATH=${EMULATOR_DIR}"/src/uarch-step.h" TEMPLATE_FILE="./templates/UArchStep.sol.template" TARGET_FILE="src/UArchStep.sol" -COMPAT_FILE="src/UArchCompat.sol" -CONSTANTS_FILE="src/UArchConstants.sol" +COMPAT_FILE="src/EmulatorCompat.sol" +CONSTANTS_FILE="src/EmulatorConstants.sol" KEYWORD_START="START OF AUTO-GENERATED CODE" KEYWORD_END="END OF AUTO-GENERATED CODE" @@ -32,11 +32,11 @@ pattern="enum class (.*) : int \{(.*)\};" # retrieve enum type from cpp header h_src=`echo "enum ${BASH_REMATCH[1]} {${BASH_REMATCH[2]}}"` -# get function names from UArchCompat.sol +# get function names from EmulatorCompat.sol COMPAT_FNS=`cat $COMPAT_FILE | grep -o "function [^(]*(" | $SED "s/function//g" | $SED "s/(//g"` COMPAT_FNS=`echo $COMPAT_FNS | $SED -E "s/( |\n)/|/g"` -# get constant names from UArchConstants.sol +# get constant names from EmulatorConstants.sol CONSTANTS=`cat $CONSTANTS_FILE | grep -E -o 'constant\s+[^ ]*' | $SED -E "s/constant//g; s/ //g" | tr '\n' '|' | sed "s/.$//"` cpp_src=`cat "$CPP_STEP_PATH"` @@ -54,8 +54,8 @@ cpp_src=`echo "${BASH_REMATCH[1]}" \ | $SED -E "s/UArchStepStatus uarch_step/static inline UArchStepStatus step/g" \ | $SED -E "s/static inline (\w+) ($INTERNAL_FN)\(([^\n]*)\) \{/function \2\(\3\) internal pure returns \(\1\)\{/g" \ | $SED -E "s/static inline (\w+) (\w+)\(([^\n]*)\) \{/function \2\(\3\) private pure returns \(\1\)\{/g" \ - | $SED -E "s/($COMPAT_FNS)/UArchCompat.\1/g" \ - | $SED -E "s/([^a-zA-Z])($CONSTANTS)([^a-zA-Z])/UArchConstants.\1\2\3/g" \ + | $SED -E "s/($COMPAT_FNS)/EmulatorCompat.\1/g" \ + | $SED -E "s/([^a-zA-Z])($CONSTANTS)([^a-zA-Z])/EmulatorConstants.\1\2\3/g" \ | $SED "s/ returns (void)//g"` # compose the solidity file from all components diff --git a/shasum-mock b/shasum-mock index 3a076d46..d9bd1340 100644 --- a/shasum-mock +++ b/shasum-mock @@ -2,7 +2,7 @@ c114d9e59014339c29374f0085a266fb820449f123007e7c89f2f9ec680e5de0 src/AccessLogs b0bb91ae378db1c938e73eccde20c539da01b8556165835839fd1794ca573404 src/Buffer.sol c2e9abd5557092fb2c7a3b6eb3d55933613c202b8ce54bba2e8cbd2d276278a1 src/Memory.sol 06df1c5a0a6094fdc3f55240a42b1991290eb672fae6833e9f2b4d4bfe2a5b88 src/MetaStep.sol -d858085617f1e8037e06420d9569e2196b72a8bd0dd217aefbb8bb738b44a8fd src/UArchCompat.sol -1152e2e0f1fdc8befe075251f5e69dcc55ec2666a287fc5002bfa021b2aaea98 src/UArchConstants.sol +d858085617f1e8037e06420d9569e2196b72a8bd0dd217aefbb8bb738b44a8fd src/EmulatorCompat.sol +1152e2e0f1fdc8befe075251f5e69dcc55ec2666a287fc5002bfa021b2aaea98 src/EmulatorConstants.sol c250ea17a7a471716148a60528b2cd01bd82dffd1c3c57aa0a7e99527fe44527 src/UArchReset.sol 40ab03ff44235b8ee5490314db112120e1ff99b347a5faf6a00f812e2497568d src/UArchStep.sol diff --git a/shasum-prod b/shasum-prod index f85b8209..21cd646f 100644 --- a/shasum-prod +++ b/shasum-prod @@ -2,7 +2,7 @@ b0bb91ae378db1c938e73eccde20c539da01b8556165835839fd1794ca573404 src/Buffer.sol d5de348b450c7cb5237a836d8e6e22cbfb4649f5892fac30f054efabdd7fc0a5 src/Memory.sol 06df1c5a0a6094fdc3f55240a42b1991290eb672fae6833e9f2b4d4bfe2a5b88 src/MetaStep.sol -0cdad8286752fbecf920db8095a764802ed88236efe7d179acdd88e018291b33 src/UArchCompat.sol -60ab17c719b0cb58047bfa5a83e390b30b32f5be00243890f2d321635bc5359a src/UArchConstants.sol +0cdad8286752fbecf920db8095a764802ed88236efe7d179acdd88e018291b33 src/EmulatorCompat.sol +60ab17c719b0cb58047bfa5a83e390b30b32f5be00243890f2d321635bc5359a src/EmulatorConstants.sol c250ea17a7a471716148a60528b2cd01bd82dffd1c3c57aa0a7e99527fe44527 src/UArchReset.sol 40ab03ff44235b8ee5490314db112120e1ff99b347a5faf6a00f812e2497568d src/UArchStep.sol diff --git a/src/AccessLogs.sol b/src/AccessLogs.sol index 131ab2c3..719c362a 100644 --- a/src/AccessLogs.sol +++ b/src/AccessLogs.sol @@ -19,7 +19,7 @@ pragma solidity ^0.8.0; import "./Buffer.sol"; -import "./UArchConstants.sol"; +import "./EmulatorConstants.sol"; library AccessLogs { using Buffer for Buffer.Context; diff --git a/src/UArchCompat.sol b/src/EmulatorCompat.sol similarity index 69% rename from src/UArchCompat.sol rename to src/EmulatorCompat.sol index 94697042..4063af03 100644 --- a/src/UArchCompat.sol +++ b/src/EmulatorCompat.sol @@ -15,10 +15,10 @@ // pragma solidity ^0.8.0; -import "./UArchConstants.sol"; +import "./EmulatorConstants.sol"; import "./AccessLogs.sol"; -library UArchCompat { +library EmulatorCompat { using AccessLogs for AccessLogs.Context; using Memory for uint64; @@ -27,7 +27,9 @@ library UArchCompat { pure returns (uint64) { - return a.readWord(UArchConstants.UCYCLE.toPhysicalAddress()); + return a.readWord( + EmulatorConstants.UARCH_CYCLE_ADDRESS.toPhysicalAddress() + ); } function readHaltFlag(AccessLogs.Context memory a) @@ -35,7 +37,11 @@ library UArchCompat { pure returns (bool) { - return (a.readWord(UArchConstants.UHALT.toPhysicalAddress()) != 0); + return ( + a.readWord( + EmulatorConstants.UARCH_HALT_FLAG_ADDRESS.toPhysicalAddress() + ) != 0 + ); } function readPc(AccessLogs.Context memory a) @@ -43,7 +49,8 @@ library UArchCompat { pure returns (uint64) { - return a.readWord(UArchConstants.UPC.toPhysicalAddress()); + return + a.readWord(EmulatorConstants.UARCH_PC_ADDRESS.toPhysicalAddress()); } function readWord(AccessLogs.Context memory a, uint64 paddr) @@ -61,7 +68,7 @@ library UArchCompat { { uint64 paddr; unchecked { - paddr = UArchConstants.UX0 + (index << 3); + paddr = EmulatorConstants.UARCH_X0_ADDRESS + (index << 3); } return a.readWord(paddr.toPhysicalAddress()); } @@ -70,15 +77,19 @@ library UArchCompat { internal pure { - a.writeWord(UArchConstants.UCYCLE.toPhysicalAddress(), val); + a.writeWord( + EmulatorConstants.UARCH_CYCLE_ADDRESS.toPhysicalAddress(), val + ); } function setHaltFlag(AccessLogs.Context memory a) internal pure { - a.writeWord(UArchConstants.UHALT.toPhysicalAddress(), 1); + a.writeWord( + EmulatorConstants.UARCH_HALT_FLAG_ADDRESS.toPhysicalAddress(), 1 + ); } function writePc(AccessLogs.Context memory a, uint64 val) internal pure { - a.writeWord(UArchConstants.UPC.toPhysicalAddress(), val); + a.writeWord(EmulatorConstants.UARCH_PC_ADDRESS.toPhysicalAddress(), val); } function writeWord(AccessLogs.Context memory a, uint64 paddr, uint64 val) @@ -94,7 +105,7 @@ library UArchCompat { { uint64 paddr; unchecked { - paddr = UArchConstants.UX0 + (index << 3); + paddr = EmulatorConstants.UARCH_X0_ADDRESS + (index << 3); } a.writeWord(paddr.toPhysicalAddress(), val); } @@ -102,12 +113,44 @@ library UArchCompat { function resetState(AccessLogs.Context memory a) internal pure { a.writeRegion( Memory.regionFromPhysicalAddress( - UArchConstants.RESET_POSITION.toPhysicalAddress(), + EmulatorConstants.UARCH_STATE_START_ADDRESS.toPhysicalAddress(), Memory.alignedSizeFromLog2( - UArchConstants.RESET_ALIGNED_SIZE - Memory.LOG2_LEAF + EmulatorConstants.UARCH_STATE_LOG2_SIZE - Memory.LOG2_LEAF ) ), - UArchConstants.PRESTINE_STATE + EmulatorConstants.UARCH_PRISTINE_STATE_HASH + ); + } + + function readIflagsY(AccessLogs.Context memory a) + internal + pure + returns (bool) + { + uint64 iflags = + a.readWord(EmulatorConstants.IFLAGS_ADDRESS.toPhysicalAddress()); + if (uint64ShiftRight(iflags, EmulatorConstants.IFLAGS_Y_SHIFT) & 1 == 0) + { + return false; + } + return true; + } + + function resetIflagsY(AccessLogs.Context memory a) internal pure { + uint64 iflags = + a.readWord(EmulatorConstants.IFLAGS_ADDRESS.toPhysicalAddress()); + iflags = iflags & ~uint64ShiftLeft(1, EmulatorConstants.IFLAGS_Y_SHIFT); + a.writeWord( + EmulatorConstants.IFLAGS_ADDRESS.toPhysicalAddress(), iflags + ); + } + + function writeHtifFromhost(AccessLogs.Context memory a, uint64 val) + internal + pure + { + a.writeWord( + EmulatorConstants.HTIF_FROMHOST_ADDRESS.toPhysicalAddress(), val ); } @@ -239,4 +282,14 @@ library UArchCompat { } function putChar(AccessLogs.Context memory a, uint8 c) internal pure {} + + function uint32Log2(uint32 value) external pure returns (uint32) { + require(value > 0, "EmulatorCompat: log2(0) is undefined"); + uint32 result = 0; + while (value > 1) { + value >>= 1; + result++; + } + return result; + } } diff --git a/src/UArchConstants.sol b/src/EmulatorConstants.sol similarity index 58% rename from src/UArchConstants.sol rename to src/EmulatorConstants.sol index a4393048..015dc4d5 100644 --- a/src/UArchConstants.sol +++ b/src/EmulatorConstants.sol @@ -14,31 +14,37 @@ // limitations under the License. // -/// @title UArchConstants -/// @notice Contains constants for micro-architecture +/// @title EmulatorConstants +/// @notice Contains constants from the Cartesi Machine emulator //:#include macro.pp -/// DEV_COMMENT(templates/UArchConstants.sol.template) +/// DEV_COMMENT(templates/EmulatorConstants.sol.template) pragma solidity ^0.8.0; -library UArchConstants { +library EmulatorConstants { // START OF AUTO-GENERATED CODE - uint64 constant UCYCLE = 0x400008; - uint64 constant UHALT = 0x400000; - uint64 constant UPC = 0x400010; - uint64 constant UX0 = 0x400018; + uint64 constant UARCH_CYCLE_ADDRESS = 0x400008; + uint64 constant UARCH_HALT_FLAG_ADDRESS = 0x400000; + uint64 constant UARCH_PC_ADDRESS = 0x400010; + uint64 constant UARCH_X0_ADDRESS = 0x400018; uint64 constant UARCH_SHADOW_START_ADDRESS = 0x400000; uint64 constant UARCH_SHADOW_LENGTH = 0x1000; uint64 constant UARCH_RAM_START_ADDRESS = 0x600000; uint64 constant UARCH_RAM_LENGTH = 0x200000; - uint64 constant RESET_POSITION = 0x400000; - uint8 constant RESET_ALIGNED_SIZE = 22; - bytes32 constant PRESTINE_STATE = + uint64 constant UARCH_STATE_START_ADDRESS = 0x400000; + uint8 constant UARCH_STATE_LOG2_SIZE = 22; + bytes32 constant UARCH_PRISTINE_STATE_HASH = 0x4de6115bdadc23724cf20c5580d718525ce81b294c8c149d3658020c380df109; uint64 constant UARCH_ECALL_FN_HALT = 1; uint64 constant UARCH_ECALL_FN_PUTCHAR = 2; + uint64 constant IFLAGS_ADDRESS = 0x2e8; + uint64 constant HTIF_FROMHOST_ADDRESS = 0x318; + uint32 constant TREE_LOG2_WORD_SIZE = 0x5; + uint32 constant TREE_WORD_SIZE = uint32(1) << TREE_LOG2_WORD_SIZE; + uint64 constant PMA_CMIO_RX_BUFFER_START = 0x60000000; // END OF AUTO-GENERATED CODE + uint32 constant IFLAGS_Y_SHIFT = 1; uint64 constant LOG2_CYCLES_TO_RESET = 10; } diff --git a/src/MetaStep.sol b/src/MetaStep.sol index a7aceef8..76039edd 100644 --- a/src/MetaStep.sol +++ b/src/MetaStep.sol @@ -36,10 +36,10 @@ library MetaStep { if ( counter - == (counter >> UArchConstants.LOG2_CYCLES_TO_RESET) - << UArchConstants.LOG2_CYCLES_TO_RESET + == (counter >> EmulatorConstants.LOG2_CYCLES_TO_RESET) + << EmulatorConstants.LOG2_CYCLES_TO_RESET ) { - // if counter is a multiple of (1 << UArchConstants.LOG2_CYCLES_TO_RESET), run uarch reset + // if counter is a multiple of (1 << EmulatorConstants.LOG2_CYCLES_TO_RESET), run uarch reset UArchReset.reset(accessLogs); machineState = accessLogs.currentRootHash; } diff --git a/src/SendCmioResponse.sol b/src/SendCmioResponse.sol new file mode 100644 index 00000000..9658ab73 --- /dev/null +++ b/src/SendCmioResponse.sol @@ -0,0 +1,80 @@ +// Copyright Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// @title SendCmioResponse +/// @notice Reset microarchitecture to pristine state +//:#include macro.pp +/// DEV_COMMENT(templates/UArchReset.sol.template) + +pragma solidity ^0.8.0; + +import "./EmulatorCompat.sol"; + +library SendCmioResponse { + using Memory for uint64; + using AccessLogs for AccessLogs.Context; + + // START OF AUTO-GENERATED CODE + + function sendCmioResponse( + AccessLogs.Context memory a, + uint16 reason, + bytes32 dataHash, + uint32 dataLength + ) internal pure { + if (!EmulatorCompat.readIflagsY(a)) { + EmulatorCompat.throwRuntimeError(a, "iflags.Y is not set"); + } + // A zero length data is a valid response. We just skip writing to the rx buffer. + if (dataLength > 0) { + // Find the write length: the smallest power of 2 that is >= dataLength and >= tree leaf size + uint32 writeLengthLog2Size = EmulatorCompat.uint32Log2(dataLength); + if (writeLengthLog2Size < EmulatorConstants.TREE_LOG2_WORD_SIZE) { + writeLengthLog2Size = EmulatorConstants.TREE_LOG2_WORD_SIZE; // minimum write size is the tree leaf size + } + if ( + EmulatorCompat.uint32ShiftLeft(1, writeLengthLog2Size) + < dataLength + ) { + writeLengthLog2Size += 1; + } + a.writeRegion( + Memory.regionFromPhysicalAddress( + EmulatorConstants.PMA_CMIO_RX_BUFFER_START.toPhysicalAddress( + ), + Memory.alignedSizeFromLog2( + uint8( + writeLengthLog2Size + - EmulatorConstants.TREE_LOG2_WORD_SIZE + ) + ) + ), + dataHash + ); + } + // Write data length and reason to fromhost + uint64 mask16 = EmulatorCompat.uint64ShiftLeft(1, 16) - 1; + uint64 mask32 = EmulatorCompat.uint64ShiftLeft(1, 32) - 1; + uint64 yieldData = EmulatorCompat.uint64ShiftLeft( + (uint64(reason) & mask16), 32 + ) | (uint64(dataLength) & mask32); + EmulatorCompat.writeHtifFromhost(a, yieldData); + // Reset iflags.Y + EmulatorCompat.resetIflagsY(a); + } + + // END OF AUTO-GENERATED CODE +} diff --git a/src/UArchReset.sol b/src/UArchReset.sol index a790a412..e6ab01c2 100644 --- a/src/UArchReset.sol +++ b/src/UArchReset.sol @@ -21,13 +21,13 @@ pragma solidity ^0.8.0; -import "./UArchCompat.sol"; +import "./EmulatorCompat.sol"; library UArchReset { // START OF AUTO-GENERATED CODE function reset(AccessLogs.Context memory a) internal pure { - UArchCompat.resetState(a); + EmulatorCompat.resetState(a); } // END OF AUTO-GENERATED CODE diff --git a/src/UArchStep.sol b/src/UArchStep.sol index 9c23c44a..c4ec1871 100644 --- a/src/UArchStep.sol +++ b/src/UArchStep.sol @@ -21,7 +21,7 @@ pragma solidity ^0.8.0; -import "./UArchCompat.sol"; +import "./EmulatorCompat.sol"; library UArchStep { // START OF AUTO-GENERATED CODE @@ -41,7 +41,7 @@ library UArchStep { returns (uint64) { require((paddr & 7) == 0, "misaligned readUint64 address"); - return UArchCompat.readWord(a, paddr); + return EmulatorCompat.readWord(a, paddr); } function readUint32(AccessLogs.Context memory a, uint64 paddr) @@ -52,9 +52,9 @@ library UArchStep { require((paddr & 3) == 0, "misaligned readUint32 address"); uint64 palign = paddr & ~uint64(7); uint32 bitoffset = - UArchCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); + EmulatorCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); uint64 val64 = readUint64(a, palign); - return uint32(UArchCompat.uint64ShiftRight(val64, bitoffset)); + return uint32(EmulatorCompat.uint64ShiftRight(val64, bitoffset)); } function readUint16(AccessLogs.Context memory a, uint64 paddr) @@ -65,9 +65,9 @@ library UArchStep { require((paddr & 1) == 0, "misaligned readUint16 address"); uint64 palign = paddr & ~uint64(7); uint32 bitoffset = - UArchCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); + EmulatorCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); uint64 val64 = readUint64(a, palign); - return uint16(UArchCompat.uint64ShiftRight(val64, bitoffset)); + return uint16(EmulatorCompat.uint64ShiftRight(val64, bitoffset)); } function readUint8(AccessLogs.Context memory a, uint64 paddr) @@ -77,9 +77,9 @@ library UArchStep { { uint64 palign = paddr & ~uint64(7); uint32 bitoffset = - UArchCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); + EmulatorCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); uint64 val64 = readUint64(a, palign); - return uint8(UArchCompat.uint64ShiftRight(val64, bitoffset)); + return uint8(EmulatorCompat.uint64ShiftRight(val64, bitoffset)); } function writeUint64(AccessLogs.Context memory a, uint64 paddr, uint64 val) @@ -87,7 +87,7 @@ library UArchStep { pure { require((paddr & 7) == 0, "misaligned writeUint64 address"); - UArchCompat.writeWord(a, paddr, val); + EmulatorCompat.writeWord(a, paddr, val); } /// \brief Copies bits from a uint64 word, starting at bit 0, to another uint64 word at the specified bit offset. @@ -102,9 +102,9 @@ library UArchStep { returns (uint64) { require(offset + count <= 64, "copyBits count exceeds limit of 64"); - uint64 eraseMask = UArchCompat.uint64ShiftLeft(1, count) - 1; - eraseMask = ~UArchCompat.uint64ShiftLeft(eraseMask, offset); - return UArchCompat.uint64ShiftLeft(from, offset) | (to & eraseMask); + uint64 eraseMask = EmulatorCompat.uint64ShiftLeft(1, count) - 1; + eraseMask = ~EmulatorCompat.uint64ShiftLeft(eraseMask, offset); + return EmulatorCompat.uint64ShiftLeft(from, offset) | (to & eraseMask); } function writeUint32(AccessLogs.Context memory a, uint64 paddr, uint32 val) @@ -115,7 +115,7 @@ library UArchStep { uint64 palign = paddr & ~uint64(7); uint32 bitoffset = - UArchCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); + EmulatorCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); uint64 oldval64 = readUint64(a, palign); uint64 newval64 = copyBits(val, 32, oldval64, bitoffset); writeUint64(a, palign, newval64); @@ -128,7 +128,7 @@ library UArchStep { require((paddr & 1) == 0, "misaligned writeUint16 address"); uint64 palign = paddr & ~uint64(7); uint32 bitoffset = - UArchCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); + EmulatorCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); uint64 oldval64 = readUint64(a, palign); uint64 newval64 = copyBits(val, 16, oldval64, bitoffset); writeUint64(a, palign, newval64); @@ -140,7 +140,7 @@ library UArchStep { { uint64 palign = paddr & ~uint64(7); uint32 bitoffset = - UArchCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); + EmulatorCompat.uint32ShiftLeft(uint32(paddr) & uint32(7), 3); uint64 oldval64 = readUint64(a, palign); uint64 newval64 = copyBits(val, 8, oldval64, bitoffset); writeUint64(a, palign, newval64); @@ -150,61 +150,61 @@ library UArchStep { function operandRd(uint32 insn) private pure returns (uint8) { return uint8( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 20), 27 + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 20), 27 ) ); } function operandRs1(uint32 insn) private pure returns (uint8) { return uint8( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 12), 27 + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 12), 27 ) ); } function operandRs2(uint32 insn) private pure returns (uint8) { return uint8( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 7), 27 + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 7), 27 ) ); } function operandImm12(uint32 insn) private pure returns (int32) { - return UArchCompat.int32ShiftRight(int32(insn), 20); + return EmulatorCompat.int32ShiftRight(int32(insn), 20); } function operandImm20(uint32 insn) private pure returns (int32) { return int32( - UArchCompat.uint32ShiftLeft( - UArchCompat.uint32ShiftRight(insn, 12), 12 + EmulatorCompat.uint32ShiftLeft( + EmulatorCompat.uint32ShiftRight(insn, 12), 12 ) ); } function operandJimm20(uint32 insn) private pure returns (int32) { int32 a = int32( - UArchCompat.uint32ShiftLeft( - uint32(UArchCompat.int32ShiftRight(int32(insn), 31)), 20 + EmulatorCompat.uint32ShiftLeft( + uint32(EmulatorCompat.int32ShiftRight(int32(insn), 31)), 20 ) ); - uint32 b = UArchCompat.uint32ShiftLeft( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 1), 22 + uint32 b = EmulatorCompat.uint32ShiftLeft( + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 1), 22 ), 1 ); - uint32 c = UArchCompat.uint32ShiftLeft( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 11), 31 + uint32 c = EmulatorCompat.uint32ShiftLeft( + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 11), 31 ), 11 ); - uint32 d = UArchCompat.uint32ShiftLeft( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 12), 24 + uint32 d = EmulatorCompat.uint32ShiftLeft( + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 12), 24 ), 12 ); @@ -213,41 +213,41 @@ library UArchStep { function operandShamt5(uint32 insn) private pure returns (int32) { return int32( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 7), 27 + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 7), 27 ) ); } function operandShamt6(uint32 insn) private pure returns (int32) { return int32( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 6), 26 + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 6), 26 ) ); } function operandSbimm12(uint32 insn) private pure returns (int32) { int32 a = int32( - UArchCompat.uint32ShiftLeft( - uint32(UArchCompat.int32ShiftRight(int32(insn), 31)), 12 + EmulatorCompat.uint32ShiftLeft( + uint32(EmulatorCompat.int32ShiftRight(int32(insn), 31)), 12 ) ); - uint32 b = UArchCompat.uint32ShiftLeft( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 1), 26 + uint32 b = EmulatorCompat.uint32ShiftLeft( + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 1), 26 ), 5 ); - uint32 c = UArchCompat.uint32ShiftLeft( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 20), 28 + uint32 c = EmulatorCompat.uint32ShiftLeft( + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 20), 28 ), 1 ); - uint32 d = UArchCompat.uint32ShiftLeft( - UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 24), 31 + uint32 d = EmulatorCompat.uint32ShiftLeft( + EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 24), 31 ), 11 ); @@ -256,11 +256,11 @@ library UArchStep { function operandSimm12(uint32 insn) private pure returns (int32) { return int32( - UArchCompat.uint32ShiftLeft( - uint32(UArchCompat.int32ShiftRight(int32(insn), 25)), 5 + EmulatorCompat.uint32ShiftLeft( + uint32(EmulatorCompat.int32ShiftRight(int32(insn), 25)), 5 ) - | UArchCompat.uint32ShiftRight( - UArchCompat.uint32ShiftLeft(insn, 20), 27 + | EmulatorCompat.uint32ShiftRight( + EmulatorCompat.uint32ShiftLeft(insn, 20), 27 ) ); } @@ -268,12 +268,12 @@ library UArchStep { // Execute instruction function advancePc(AccessLogs.Context memory a, uint64 pc) private pure { - uint64 newPc = UArchCompat.uint64AddUint64(pc, 4); - return UArchCompat.writePc(a, newPc); + uint64 newPc = EmulatorCompat.uint64AddUint64(pc, 4); + return EmulatorCompat.writePc(a, newPc); } function branch(AccessLogs.Context memory a, uint64 pc) private pure { - return UArchCompat.writePc(a, pc); + return EmulatorCompat.writePc(a, pc); } function executeLUI(AccessLogs.Context memory a, uint32 insn, uint64 pc) @@ -283,7 +283,7 @@ library UArchStep { uint8 rd = operandRd(insn); int32 imm = operandImm20(insn); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(imm)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(imm)); } return advancePc(a, pc); } @@ -295,7 +295,7 @@ library UArchStep { int32 imm = operandImm20(insn); uint8 rd = operandRd(insn); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.uint64AddInt32(pc, imm)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.uint64AddInt32(pc, imm)); } return advancePc(a, pc); } @@ -307,9 +307,9 @@ library UArchStep { int32 imm = operandJimm20(insn); uint8 rd = operandRd(insn); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.uint64AddUint64(pc, 4)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.uint64AddUint64(pc, 4)); } - return branch(a, UArchCompat.uint64AddInt32(pc, imm)); + return branch(a, EmulatorCompat.uint64AddInt32(pc, imm)); } function executeJALR(AccessLogs.Context memory a, uint32 insn, uint64 pc) @@ -319,11 +319,12 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); + uint64 rs1val = EmulatorCompat.readX(a, rs1); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.uint64AddUint64(pc, 4)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.uint64AddUint64(pc, 4)); } - return branch(a, UArchCompat.uint64AddInt32(rs1val, imm) & (~uint64(1))); + return + branch(a, EmulatorCompat.uint64AddInt32(rs1val, imm) & (~uint64(1))); } function executeBEQ(AccessLogs.Context memory a, uint32 insn, uint64 pc) @@ -333,10 +334,10 @@ library UArchStep { int32 imm = operandSbimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); if (rs1val == rs2val) { - return branch(a, UArchCompat.uint64AddInt32(pc, imm)); + return branch(a, EmulatorCompat.uint64AddInt32(pc, imm)); } return advancePc(a, pc); } @@ -348,10 +349,10 @@ library UArchStep { int32 imm = operandSbimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); if (rs1val != rs2val) { - return branch(a, UArchCompat.uint64AddInt32(pc, imm)); + return branch(a, EmulatorCompat.uint64AddInt32(pc, imm)); } return advancePc(a, pc); } @@ -363,10 +364,10 @@ library UArchStep { int32 imm = operandSbimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - int64 rs1val = int64(UArchCompat.readX(a, rs1)); - int64 rs2val = int64(UArchCompat.readX(a, rs2)); + int64 rs1val = int64(EmulatorCompat.readX(a, rs1)); + int64 rs2val = int64(EmulatorCompat.readX(a, rs2)); if (rs1val < rs2val) { - return branch(a, UArchCompat.uint64AddInt32(pc, imm)); + return branch(a, EmulatorCompat.uint64AddInt32(pc, imm)); } return advancePc(a, pc); } @@ -378,10 +379,10 @@ library UArchStep { int32 imm = operandSbimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - int64 rs1val = int64(UArchCompat.readX(a, rs1)); - int64 rs2val = int64(UArchCompat.readX(a, rs2)); + int64 rs1val = int64(EmulatorCompat.readX(a, rs1)); + int64 rs2val = int64(EmulatorCompat.readX(a, rs2)); if (rs1val >= rs2val) { - return branch(a, UArchCompat.uint64AddInt32(pc, imm)); + return branch(a, EmulatorCompat.uint64AddInt32(pc, imm)); } return advancePc(a, pc); } @@ -393,10 +394,10 @@ library UArchStep { int32 imm = operandSbimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); if (rs1val < rs2val) { - return branch(a, UArchCompat.uint64AddInt32(pc, imm)); + return branch(a, EmulatorCompat.uint64AddInt32(pc, imm)); } return advancePc(a, pc); } @@ -408,10 +409,10 @@ library UArchStep { int32 imm = operandSbimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); if (rs1val >= rs2val) { - return branch(a, UArchCompat.uint64AddInt32(pc, imm)); + return branch(a, EmulatorCompat.uint64AddInt32(pc, imm)); } return advancePc(a, pc); } @@ -423,10 +424,10 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - int8 i8 = int8(readUint8(a, UArchCompat.uint64AddInt32(rs1val, imm))); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + int8 i8 = int8(readUint8(a, EmulatorCompat.uint64AddInt32(rs1val, imm))); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.int8ToUint64(i8)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int8ToUint64(i8)); } return advancePc(a, pc); } @@ -438,10 +439,10 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint16 u16 = readUint16(a, UArchCompat.uint64AddInt32(rs1val, imm)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint16 u16 = readUint16(a, EmulatorCompat.uint64AddInt32(rs1val, imm)); if (rd != 0) { - UArchCompat.writeX(a, rd, u16); + EmulatorCompat.writeX(a, rd, u16); } return advancePc(a, pc); } @@ -453,11 +454,11 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); + uint64 rs1val = EmulatorCompat.readX(a, rs1); int16 i16 = - int16(readUint16(a, UArchCompat.uint64AddInt32(rs1val, imm))); + int16(readUint16(a, EmulatorCompat.uint64AddInt32(rs1val, imm))); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.int16ToUint64(i16)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int16ToUint64(i16)); } return advancePc(a, pc); } @@ -469,11 +470,11 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); + uint64 rs1val = EmulatorCompat.readX(a, rs1); int32 i32 = - int32(readUint32(a, UArchCompat.uint64AddInt32(rs1val, imm))); + int32(readUint32(a, EmulatorCompat.uint64AddInt32(rs1val, imm))); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(i32)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(i32)); } return advancePc(a, pc); } @@ -485,10 +486,10 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint8 u8 = readUint8(a, UArchCompat.uint64AddInt32(rs1val, imm)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint8 u8 = readUint8(a, EmulatorCompat.uint64AddInt32(rs1val, imm)); if (rd != 0) { - UArchCompat.writeX(a, rd, u8); + EmulatorCompat.writeX(a, rd, u8); } return advancePc(a, pc); } @@ -500,9 +501,9 @@ library UArchStep { int32 imm = operandSimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - writeUint8(a, UArchCompat.uint64AddInt32(rs1val, imm), uint8(rs2val)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + writeUint8(a, EmulatorCompat.uint64AddInt32(rs1val, imm), uint8(rs2val)); return advancePc(a, pc); } @@ -513,9 +514,11 @@ library UArchStep { int32 imm = operandSimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - writeUint16(a, UArchCompat.uint64AddInt32(rs1val, imm), uint16(rs2val)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + writeUint16( + a, EmulatorCompat.uint64AddInt32(rs1val, imm), uint16(rs2val) + ); return advancePc(a, pc); } @@ -526,9 +529,9 @@ library UArchStep { int32 imm = operandSimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint32 rs2val = uint32(UArchCompat.readX(a, rs2)); - writeUint32(a, UArchCompat.uint64AddInt32(rs1val, imm), rs2val); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint32 rs2val = uint32(EmulatorCompat.readX(a, rs2)); + writeUint32(a, EmulatorCompat.uint64AddInt32(rs1val, imm), rs2val); return advancePc(a, pc); } @@ -540,9 +543,9 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - int64 val = UArchCompat.int64AddInt64(int64(rs1val), int64(imm)); - UArchCompat.writeX(a, rd, uint64(val)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + int64 val = EmulatorCompat.int64AddInt64(int64(rs1val), int64(imm)); + EmulatorCompat.writeX(a, rd, uint64(val)); } return advancePc(a, pc); } @@ -554,10 +557,11 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - int32 rs1val = UArchCompat.uint64ToInt32(UArchCompat.readX(a, rs1)); + int32 rs1val = + EmulatorCompat.uint64ToInt32(EmulatorCompat.readX(a, rs1)); if (rd != 0) { - int32 val = UArchCompat.int32AddInt32(rs1val, imm); - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(val)); + int32 val = EmulatorCompat.int32AddInt32(rs1val, imm); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(val)); } return advancePc(a, pc); } @@ -570,11 +574,11 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); + uint64 rs1val = EmulatorCompat.readX(a, rs1); if (int64(rs1val) < imm) { - UArchCompat.writeX(a, rd, 1); + EmulatorCompat.writeX(a, rd, 1); } else { - UArchCompat.writeX(a, rd, 0); + EmulatorCompat.writeX(a, rd, 0); } } return advancePc(a, pc); @@ -588,11 +592,11 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - if (rs1val < UArchCompat.int32ToUint64(imm)) { - UArchCompat.writeX(a, rd, 1); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + if (rs1val < EmulatorCompat.int32ToUint64(imm)) { + EmulatorCompat.writeX(a, rd, 1); } else { - UArchCompat.writeX(a, rd, 0); + EmulatorCompat.writeX(a, rd, 0); } } return advancePc(a, pc); @@ -606,8 +610,10 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - UArchCompat.writeX(a, rd, rs1val ^ UArchCompat.int32ToUint64(imm)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + EmulatorCompat.writeX( + a, rd, rs1val ^ EmulatorCompat.int32ToUint64(imm) + ); } return advancePc(a, pc); } @@ -620,8 +626,10 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - UArchCompat.writeX(a, rd, rs1val | UArchCompat.int32ToUint64(imm)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + EmulatorCompat.writeX( + a, rd, rs1val | EmulatorCompat.int32ToUint64(imm) + ); } return advancePc(a, pc); } @@ -634,8 +642,10 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - UArchCompat.writeX(a, rd, rs1val & UArchCompat.int32ToUint64(imm)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + EmulatorCompat.writeX( + a, rd, rs1val & EmulatorCompat.int32ToUint64(imm) + ); } return advancePc(a, pc); } @@ -648,9 +658,9 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - UArchCompat.writeX( - a, rd, UArchCompat.uint64ShiftLeft(rs1val, uint32(imm)) + uint64 rs1val = EmulatorCompat.readX(a, rs1); + EmulatorCompat.writeX( + a, rd, EmulatorCompat.uint64ShiftLeft(rs1val, uint32(imm)) ); } return advancePc(a, pc); @@ -663,13 +673,13 @@ library UArchStep { int32 imm = operandShamt5(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint32 rs1val = uint32(UArchCompat.readX(a, rs1)); + uint32 rs1val = uint32(EmulatorCompat.readX(a, rs1)); if (rd != 0) { - UArchCompat.writeX( + EmulatorCompat.writeX( a, rd, - UArchCompat.int32ToUint64( - int32(UArchCompat.uint32ShiftLeft(rs1val, uint32(imm))) + EmulatorCompat.int32ToUint64( + int32(EmulatorCompat.uint32ShiftLeft(rs1val, uint32(imm))) ) ); } @@ -684,9 +694,9 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - UArchCompat.writeX( - a, rd, UArchCompat.uint64ShiftRight(rs1val, uint32(imm)) + uint64 rs1val = EmulatorCompat.readX(a, rs1); + EmulatorCompat.writeX( + a, rd, EmulatorCompat.uint64ShiftRight(rs1val, uint32(imm)) ); } return advancePc(a, pc); @@ -699,11 +709,11 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint32 rs1val = uint32(UArchCompat.readX(a, rs1)); - uint32 rs2val = uint32(UArchCompat.readX(a, rs2)); - int32 rdval = int32(UArchCompat.uint32ShiftRight(rs1val, rs2val)); + uint32 rs1val = uint32(EmulatorCompat.readX(a, rs1)); + uint32 rs2val = uint32(EmulatorCompat.readX(a, rs2)); + int32 rdval = int32(EmulatorCompat.uint32ShiftRight(rs1val, rs2val)); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(rdval)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(rdval)); } return advancePc(a, pc); } @@ -715,10 +725,11 @@ library UArchStep { int32 imm = operandShamt5(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint32 rs1val = uint32(UArchCompat.readX(a, rs1)); - int32 rdval = int32(UArchCompat.uint32ShiftRight(rs1val, uint32(imm))); + uint32 rs1val = uint32(EmulatorCompat.readX(a, rs1)); + int32 rdval = + int32(EmulatorCompat.uint32ShiftRight(rs1val, uint32(imm))); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(rdval)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(rdval)); } return advancePc(a, pc); } @@ -731,11 +742,13 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - UArchCompat.writeX( + uint64 rs1val = EmulatorCompat.readX(a, rs1); + EmulatorCompat.writeX( a, rd, - uint64(UArchCompat.int64ShiftRight(int64(rs1val), uint32(imm))) + uint64( + EmulatorCompat.int64ShiftRight(int64(rs1val), uint32(imm)) + ) ); } return advancePc(a, pc); @@ -748,13 +761,14 @@ library UArchStep { int32 imm = operandShamt5(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - int32 rs1val = UArchCompat.uint64ToInt32(UArchCompat.readX(a, rs1)); + int32 rs1val = + EmulatorCompat.uint64ToInt32(EmulatorCompat.readX(a, rs1)); if (rd != 0) { - UArchCompat.writeX( + EmulatorCompat.writeX( a, rd, - UArchCompat.int32ToUint64( - UArchCompat.int32ShiftRight(rs1val, uint32(imm)) + EmulatorCompat.int32ToUint64( + EmulatorCompat.int32ShiftRight(rs1val, uint32(imm)) ) ); } @@ -769,10 +783,10 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - UArchCompat.writeX( - a, rd, UArchCompat.uint64AddUint64(rs1val, rs2val) + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + EmulatorCompat.writeX( + a, rd, EmulatorCompat.uint64AddUint64(rs1val, rs2val) ); } return advancePc(a, pc); @@ -785,11 +799,13 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - int32 rs1val = UArchCompat.uint64ToInt32(UArchCompat.readX(a, rs1)); - int32 rs2val = UArchCompat.uint64ToInt32(UArchCompat.readX(a, rs2)); + int32 rs1val = + EmulatorCompat.uint64ToInt32(EmulatorCompat.readX(a, rs1)); + int32 rs2val = + EmulatorCompat.uint64ToInt32(EmulatorCompat.readX(a, rs2)); if (rd != 0) { - int32 val = UArchCompat.int32AddInt32(rs1val, rs2val); - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(val)); + int32 val = EmulatorCompat.int32AddInt32(rs1val, rs2val); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(val)); } return advancePc(a, pc); } @@ -802,10 +818,10 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - UArchCompat.writeX( - a, rd, UArchCompat.uint64SubUint64(rs1val, rs2val) + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + EmulatorCompat.writeX( + a, rd, EmulatorCompat.uint64SubUint64(rs1val, rs2val) ); } return advancePc(a, pc); @@ -818,11 +834,13 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - int32 rs1val = UArchCompat.uint64ToInt32(UArchCompat.readX(a, rs1)); - int32 rs2val = UArchCompat.uint64ToInt32(UArchCompat.readX(a, rs2)); + int32 rs1val = + EmulatorCompat.uint64ToInt32(EmulatorCompat.readX(a, rs1)); + int32 rs2val = + EmulatorCompat.uint64ToInt32(EmulatorCompat.readX(a, rs2)); if (rd != 0) { - int32 val = UArchCompat.int32SubInt32(rs1val, rs2val); - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(val)); + int32 val = EmulatorCompat.int32SubInt32(rs1val, rs2val); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(val)); } return advancePc(a, pc); } @@ -835,10 +853,10 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - uint32 rs2val = uint32(UArchCompat.readX(a, rs2)); - UArchCompat.writeX( - a, rd, UArchCompat.uint64ShiftLeft(rs1val, rs2val) + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint32 rs2val = uint32(EmulatorCompat.readX(a, rs2)); + EmulatorCompat.writeX( + a, rd, EmulatorCompat.uint64ShiftLeft(rs1val, rs2val) ); } return advancePc(a, pc); @@ -851,11 +869,12 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint32 rs1val = uint32(UArchCompat.readX(a, rs1)); - uint32 rs2val = uint32(UArchCompat.readX(a, rs2)); - int32 rdval = int32(UArchCompat.uint32ShiftLeft(uint32(rs1val), rs2val)); + uint32 rs1val = uint32(EmulatorCompat.readX(a, rs1)); + uint32 rs2val = uint32(EmulatorCompat.readX(a, rs2)); + int32 rdval = + int32(EmulatorCompat.uint32ShiftLeft(uint32(rs1val), rs2val)); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(rdval)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(rdval)); } return advancePc(a, pc); } @@ -868,13 +887,13 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - int64 rs1val = int64(UArchCompat.readX(a, rs1)); - int64 rs2val = int64(UArchCompat.readX(a, rs2)); + int64 rs1val = int64(EmulatorCompat.readX(a, rs1)); + int64 rs2val = int64(EmulatorCompat.readX(a, rs2)); uint64 rdval = 0; if (rs1val < rs2val) { rdval = 1; } - UArchCompat.writeX(a, rd, rdval); + EmulatorCompat.writeX(a, rd, rdval); } return advancePc(a, pc); } @@ -887,13 +906,13 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); uint64 rdval = 0; if (rs1val < rs2val) { rdval = 1; } - UArchCompat.writeX(a, rd, rdval); + EmulatorCompat.writeX(a, rd, rdval); } return advancePc(a, pc); } @@ -906,9 +925,9 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - UArchCompat.writeX(a, rd, rs1val ^ rs2val); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + EmulatorCompat.writeX(a, rd, rs1val ^ rs2val); } return advancePc(a, pc); } @@ -921,10 +940,10 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - UArchCompat.writeX( - a, rd, UArchCompat.uint64ShiftRight(rs1val, uint32(rs2val)) + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + EmulatorCompat.writeX( + a, rd, EmulatorCompat.uint64ShiftRight(rs1val, uint32(rs2val)) ); } return advancePc(a, pc); @@ -938,10 +957,10 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - int64 rs1val = int64(UArchCompat.readX(a, rs1)); - uint32 rs2val = uint32(UArchCompat.readX(a, rs2)); - UArchCompat.writeX( - a, rd, uint64(UArchCompat.int64ShiftRight(rs1val, rs2val)) + int64 rs1val = int64(EmulatorCompat.readX(a, rs1)); + uint32 rs2val = uint32(EmulatorCompat.readX(a, rs2)); + EmulatorCompat.writeX( + a, rd, uint64(EmulatorCompat.int64ShiftRight(rs1val, rs2val)) ); } return advancePc(a, pc); @@ -954,11 +973,12 @@ library UArchStep { uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - int32 rs1val = UArchCompat.uint64ToInt32(UArchCompat.readX(a, rs1)); - uint32 rs2val = uint32(UArchCompat.readX(a, rs2)); - int32 rdval = UArchCompat.int32ShiftRight(rs1val, rs2val); + int32 rs1val = + EmulatorCompat.uint64ToInt32(EmulatorCompat.readX(a, rs1)); + uint32 rs2val = uint32(EmulatorCompat.readX(a, rs2)); + int32 rdval = EmulatorCompat.int32ShiftRight(rs1val, rs2val); if (rd != 0) { - UArchCompat.writeX(a, rd, UArchCompat.int32ToUint64(rdval)); + EmulatorCompat.writeX(a, rd, EmulatorCompat.int32ToUint64(rdval)); } return advancePc(a, pc); } @@ -971,9 +991,9 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - UArchCompat.writeX(a, rd, rs1val | rs2val); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + EmulatorCompat.writeX(a, rd, rs1val | rs2val); } return advancePc(a, pc); } @@ -986,9 +1006,9 @@ library UArchStep { uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); if (rd != 0) { - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - UArchCompat.writeX(a, rd, rs1val & rs2val); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + EmulatorCompat.writeX(a, rd, rs1val & rs2val); } return advancePc(a, pc); } @@ -1007,10 +1027,10 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint32 u32 = readUint32(a, UArchCompat.uint64AddInt32(rs1val, imm)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint32 u32 = readUint32(a, EmulatorCompat.uint64AddInt32(rs1val, imm)); if (rd != 0) { - UArchCompat.writeX(a, rd, u32); + EmulatorCompat.writeX(a, rd, u32); } return advancePc(a, pc); } @@ -1022,10 +1042,10 @@ library UArchStep { int32 imm = operandImm12(insn); uint8 rd = operandRd(insn); uint8 rs1 = operandRs1(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 u64 = readUint64(a, UArchCompat.uint64AddInt32(rs1val, imm)); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 u64 = readUint64(a, EmulatorCompat.uint64AddInt32(rs1val, imm)); if (rd != 0) { - UArchCompat.writeX(a, rd, u64); + EmulatorCompat.writeX(a, rd, u64); } return advancePc(a, pc); } @@ -1037,9 +1057,9 @@ library UArchStep { int32 imm = operandSimm12(insn); uint8 rs1 = operandRs1(insn); uint8 rs2 = operandRs2(insn); - uint64 rs1val = UArchCompat.readX(a, rs1); - uint64 rs2val = UArchCompat.readX(a, rs2); - writeUint64(a, UArchCompat.uint64AddInt32(rs1val, imm), rs2val); + uint64 rs1val = EmulatorCompat.readX(a, rs1); + uint64 rs2val = EmulatorCompat.readX(a, rs2); + writeUint64(a, EmulatorCompat.uint64AddInt32(rs1val, imm), rs2val); return advancePc(a, pc); } @@ -1047,20 +1067,20 @@ library UArchStep { private pure { - uint64 fn = UArchCompat.readX(a, 17); // a7 contains the function number - if (fn == UArchConstants.UARCH_ECALL_FN_HALT) { - return UArchCompat.setHaltFlag(a); - } else if (fn == UArchConstants.UARCH_ECALL_FN_PUTCHAR) { - uint64 character = UArchCompat.readX(a, 16); // a6 contains the character to print - UArchCompat.putChar(a, uint8(character)); + uint64 fn = EmulatorCompat.readX(a, 17); // a7 contains the function number + if (fn == EmulatorConstants.UARCH_ECALL_FN_HALT) { + return EmulatorCompat.setHaltFlag(a); + } else if (fn == EmulatorConstants.UARCH_ECALL_FN_PUTCHAR) { + uint64 character = EmulatorCompat.readX(a, 16); // a6 contains the character to print + EmulatorCompat.putChar(a, uint8(character)); } else { - UArchCompat.throwRuntimeError(a, "unsupported ecall function"); + EmulatorCompat.throwRuntimeError(a, "unsupported ecall function"); } return advancePc(a, pc); } function executeEBREAK(AccessLogs.Context memory a) private pure { - UArchCompat.throwRuntimeError(a, "uarch aborted"); + EmulatorCompat.throwRuntimeError(a, "uarch aborted"); } /// \brief Returns true if the opcode field of an instruction matches the provided argument @@ -1079,8 +1099,8 @@ library UArchStep { returns (bool) { uint32 mask = (7 << 12) | 0x7f; - return - (insn & mask) == (UArchCompat.uint32ShiftLeft(funct3, 12) | opcode); + return (insn & mask) + == (EmulatorCompat.uint32ShiftLeft(funct3, 12) | opcode); } /// \brief Returns true if the opcode, funct3 and funct7 fields of an instruction match the provided arguments @@ -1093,8 +1113,8 @@ library UArchStep { uint32 mask = (0x7f << 25) | (7 << 12) | 0x7f; return ((insn & mask)) == ( - UArchCompat.uint32ShiftLeft(funct7, 25) - | UArchCompat.uint32ShiftLeft(funct3, 12) | opcode + EmulatorCompat.uint32ShiftLeft(funct7, 25) + | EmulatorCompat.uint32ShiftLeft(funct3, 12) | opcode ); } @@ -1109,8 +1129,8 @@ library UArchStep { uint32 mask = (0x3f << 26) | (7 << 12) | 0x7f; return ((insn & mask)) == ( - UArchCompat.uint32ShiftLeft(funct7Sr1, 26) - | UArchCompat.uint32ShiftLeft(funct3, 12) | opcode + EmulatorCompat.uint32ShiftLeft(funct7Sr1, 26) + | EmulatorCompat.uint32ShiftLeft(funct3, 12) | opcode ); } @@ -1224,7 +1244,7 @@ library UArchStep { } else if (insn == uint32(0x100073)) { return executeEBREAK(a); } - UArchCompat.throwRuntimeError(a, "illegal instruction"); + EmulatorCompat.throwRuntimeError(a, "illegal instruction"); } function step(AccessLogs.Context memory a) @@ -1233,21 +1253,21 @@ library UArchStep { returns (UArchStepStatus) { // This must be the first read in order to match the first log access in machine.verify_uarch_step_state_transition - uint64 cycle = UArchCompat.readCycle(a); + uint64 cycle = EmulatorCompat.readCycle(a); // do not advance if cycle will overflow if (cycle == type(uint64).max) { return UArchStepStatus.CycleOverflow; } // do not advance if machine is halted - if (UArchCompat.readHaltFlag(a)) { + if (EmulatorCompat.readHaltFlag(a)) { return UArchStepStatus.UArchHalted; } // execute next instruction - uint64 pc = UArchCompat.readPc(a); + uint64 pc = EmulatorCompat.readPc(a); uint32 insn = readUint32(a, pc); executeInsn(a, insn, pc); cycle = cycle + 1; - UArchCompat.writeCycle(a, cycle); + EmulatorCompat.writeCycle(a, cycle); return UArchStepStatus.Success; } diff --git a/templates/AccessLogs.sol.template b/templates/AccessLogs.sol.template index b25a9dc3..12473279 100644 --- a/templates/AccessLogs.sol.template +++ b/templates/AccessLogs.sol.template @@ -30,7 +30,7 @@ pragma solidity ^0.8.0; import "./Buffer.sol"; -import "./UArchConstants.sol"; +import "./EmulatorConstants.sol"; library AccessLogs { using Buffer for Buffer.Context; @@ -135,7 +135,7 @@ library AccessLogs { ) internal pure { bytes32 oldDrive = a.buffer.consumeBytes32(); (bytes32 rootHash,) = a.buffer.peekRoot(region, oldDrive); - + require( a.currentRootHash == rootHash, "Write region root doesn't match" ); @@ -255,12 +255,12 @@ library AccessLogs { uint64 index; uint64 position = Memory.PhysicalAddress.unwrap(paddr); if ( - position >= UArchConstants.UARCH_SHADOW_START_ADDRESS - && position <= UArchConstants.UARCH_SHADOW_START_ADDRESS + UArchConstants.UARCH_SHADOW_LENGTH + position >= EmulatorConstants.UARCH_SHADOW_START_ADDRESS + && position <= EmulatorConstants.UARCH_SHADOW_START_ADDRESS + EmulatorConstants.UARCH_SHADOW_LENGTH ) { - index = (position - UArchConstants.UARCH_SHADOW_START_ADDRESS); - } else if (position >= UArchConstants.UARCH_RAM_START_ADDRESS) { - index = (position - UArchConstants.UARCH_RAM_START_ADDRESS) + (35 << 3); + index = (position - EmulatorConstants.UARCH_SHADOW_START_ADDRESS); + } else if (position >= EmulatorConstants.UARCH_RAM_START_ADDRESS) { + index = (position - EmulatorConstants.UARCH_RAM_START_ADDRESS) + (35 << 3); } else { revert("invalid memory access"); } diff --git a/templates/UArchConstants.sol.template b/templates/EmulatorConstants.sol.template similarity index 84% rename from templates/UArchConstants.sol.template rename to templates/EmulatorConstants.sol.template index 8e2fa745..147faa89 100644 --- a/templates/UArchConstants.sol.template +++ b/templates/EmulatorConstants.sol.template @@ -14,16 +14,17 @@ // limitations under the License. // -/// @title UArchConstants +/// @title EmulatorConstants /// @notice Contains constants for micro-architecture //:#include macro.pp -/// DEV_COMMENT(templates/UArchConstants.sol.template) +/// DEV_COMMENT(templates/EmulatorConstants.sol.template) pragma solidity ^0.8.0; -library UArchConstants { +library EmulatorConstants { // START OF AUTO-GENERATED CODE // END OF AUTO-GENERATED CODE + uint32 constant IFLAGS_Y_SHIFT = 1; uint64 constant LOG2_CYCLES_TO_RESET = 10; } diff --git a/templates/SendCmioResponse.sol.template b/templates/SendCmioResponse.sol.template new file mode 100644 index 00000000..8bfeb6e7 --- /dev/null +++ b/templates/SendCmioResponse.sol.template @@ -0,0 +1,32 @@ +// Copyright Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +/// @title SendCmioResponse +/// @notice Reset microarchitecture to pristine state +//:#include macro.pp +/// DEV_COMMENT(templates/UArchReset.sol.template) + +pragma solidity ^0.8.0; + +import "./EmulatorCompat.sol"; + +library SendCmioResponse { + using Memory for uint64; + using AccessLogs for AccessLogs.Context; + + // START OF AUTO-GENERATED CODE + // END OF AUTO-GENERATED CODE +} diff --git a/templates/UArchReset.sol.template b/templates/UArchReset.sol.template index 9c6ef53b..268bc917 100644 --- a/templates/UArchReset.sol.template +++ b/templates/UArchReset.sol.template @@ -21,7 +21,7 @@ pragma solidity ^0.8.0; -import "./UArchCompat.sol"; +import "./EmulatorCompat.sol"; library UArchReset { // START OF AUTO-GENERATED CODE diff --git a/templates/UArchStep.sol.template b/templates/UArchStep.sol.template index 4459abbd..c56182f1 100644 --- a/templates/UArchStep.sol.template +++ b/templates/UArchStep.sol.template @@ -21,7 +21,7 @@ pragma solidity ^0.8.0; -import "./UArchCompat.sol"; +import "./EmulatorCompat.sol"; library UArchStep { // START OF AUTO-GENERATED CODE diff --git a/test/EmulatorCompat.t.sol b/test/EmulatorCompat.t.sol new file mode 100644 index 00000000..29342c5c --- /dev/null +++ b/test/EmulatorCompat.t.sol @@ -0,0 +1,161 @@ +// Copyright Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +import "forge-std/console.sol"; +import "forge-std/Test.sol"; +import "src/EmulatorCompat.sol"; + +pragma solidity ^0.8.0; + +contract EmulatorCompatTest is Test { + int16 constant INT16_MAX = type(int16).max; + int32 constant INT32_MAX = type(int32).max; + int64 constant INT64_MAX = type(int64).max; + int16 constant INT16_MIN = type(int16).min; + int32 constant INT32_MIN = type(int32).min; + int64 constant INT64_MIN = type(int64).min; + uint16 constant UINT16_MAX = type(uint16).max; + uint32 constant UINT32_MAX = type(uint32).max; + uint64 constant UINT64_MAX = type(uint64).max; + + function testSanity() public { + assertEq(UINT16_MAX, 65535); + assertEq(UINT32_MAX, 4294967295); + assertEq(UINT64_MAX, 18446744073709551615); + assertEq(INT16_MAX, 32767); + assertEq(INT32_MAX, 2147483647); + assertEq(INT64_MAX, 9223372036854775807); + assertEq(INT16_MIN, -32768); + assertEq(INT32_MIN, -INT32_MAX - 1); + assertEq(INT64_MIN, -INT64_MAX - 1); + } + + function testCompat() public { + assertEq(EmulatorCompat.uint64ToInt32(1), 1); + assertEq(EmulatorCompat.uint64ToInt32(0xffffffff), -1); + assertEq(EmulatorCompat.uint64ToInt32(0xffffffff << 31), INT32_MIN); + assertEq(EmulatorCompat.uint64ToInt32(0xffffffff << 32), 0); + + assertEq(EmulatorCompat.uint64AddInt32(2, -1), 1); + assertEq(EmulatorCompat.uint64AddInt32(0, -1), UINT64_MAX); + assertEq(EmulatorCompat.uint64AddInt32(UINT64_MAX, 1), 0); + + assertEq(EmulatorCompat.uint64SubUint64(1, 1), 0); + assertEq(EmulatorCompat.uint64SubUint64(0, 1), UINT64_MAX); + + assertEq(EmulatorCompat.uint64AddUint64(0, 1), 1); + assertEq(EmulatorCompat.uint64AddUint64(UINT64_MAX, 1), 0); + + assertEq(EmulatorCompat.uint64ShiftRight(0, 0), 0); + assertEq(EmulatorCompat.uint64ShiftRight(0, 1), 0); + assertEq(EmulatorCompat.uint64ShiftRight(4, 1), 2); + assertEq(EmulatorCompat.uint64ShiftRight(4, 2), 1); + assertEq(EmulatorCompat.uint64ShiftRight(4, 3), 0); + assertEq(EmulatorCompat.uint64ShiftRight(UINT64_MAX, 63), 1); + + assertEq(EmulatorCompat.uint64ShiftLeft(0, 0), 0); + assertEq(EmulatorCompat.uint64ShiftLeft(0, 1), 0); + assertEq(EmulatorCompat.uint64ShiftLeft(4, 1), 8); + assertEq(EmulatorCompat.uint64ShiftLeft(4, 2), 16); + assertEq(EmulatorCompat.uint64ShiftLeft(UINT64_MAX, 63), 1 << 63); + + assertEq(EmulatorCompat.int64ShiftRight(0, 0), 0); + assertEq(EmulatorCompat.int64ShiftRight(0, 1), 0); + assertEq(EmulatorCompat.int64ShiftRight(4, 1), 2); + assertEq(EmulatorCompat.int64ShiftRight(4, 2), 1); + assertEq(EmulatorCompat.int64ShiftRight(4, 3), 0); + assertEq(EmulatorCompat.int64ShiftRight(INT64_MAX, 62), 1); + assertEq(EmulatorCompat.int64ShiftRight(INT64_MAX, 63), 0); + assertEq(EmulatorCompat.int64ShiftRight(-1, 1), -1); + assertEq(EmulatorCompat.int64ShiftRight(-4, 1), -2); + assertEq(EmulatorCompat.int64ShiftRight(INT64_MIN, 62), -2); + assertEq(EmulatorCompat.int64ShiftRight(INT64_MIN, 63), -1); + + assertEq(EmulatorCompat.int64AddInt64(0, 0), 0); + assertEq(EmulatorCompat.int64AddInt64(0, 1), 1); + assertEq(EmulatorCompat.int64AddInt64(0, -1), -1); + assertEq(EmulatorCompat.int64AddInt64(-1, 0), -1); + assertEq(EmulatorCompat.int64AddInt64(INT64_MAX, 1), INT64_MIN); + assertEq(EmulatorCompat.int64AddInt64(INT64_MAX, INT64_MAX), -2); + + assertEq(EmulatorCompat.uint32ShiftRight(0, 0), 0); + assertEq(EmulatorCompat.uint32ShiftRight(0, 1), 0); + assertEq(EmulatorCompat.uint32ShiftRight(4, 1), 2); + assertEq(EmulatorCompat.uint32ShiftRight(4, 2), 1); + assertEq(EmulatorCompat.uint32ShiftRight(4, 3), 0); + assertEq(EmulatorCompat.uint32ShiftRight(UINT32_MAX, 31), 1); + + assertEq(EmulatorCompat.uint32ShiftLeft(0, 0), 0); + assertEq(EmulatorCompat.uint32ShiftLeft(0, 1), 0); + assertEq(EmulatorCompat.uint32ShiftLeft(4, 1), 8); + assertEq(EmulatorCompat.uint32ShiftLeft(4, 2), 16); + assertEq(EmulatorCompat.uint32ShiftLeft(4, 3), 32); + assertEq(EmulatorCompat.uint32ShiftLeft(UINT32_MAX, 31), 0x80000000); + + assertEq(EmulatorCompat.int32ToUint64(1), 1); + assertEq(EmulatorCompat.int32ToUint64(INT32_MAX), 2147483647); + assertEq(EmulatorCompat.int32ToUint64(INT32_MIN), 0xffffffff80000000); + + assertEq(EmulatorCompat.int32ShiftRight(0, 0), 0); + assertEq(EmulatorCompat.int32ShiftRight(0, 1), 0); + assertEq(EmulatorCompat.int32ShiftRight(4, 1), 2); + assertEq(EmulatorCompat.int32ShiftRight(4, 2), 1); + assertEq(EmulatorCompat.int32ShiftRight(4, 3), 0); + assertEq(EmulatorCompat.int32ShiftRight(INT32_MAX, 30), 1); + assertEq(EmulatorCompat.int32ShiftRight(INT32_MAX, 31), 0); + assertEq(EmulatorCompat.int32ShiftRight(-1, 1), -1); + assertEq(EmulatorCompat.int32ShiftRight(-4, 1), -2); + assertEq(EmulatorCompat.int32ShiftRight(INT32_MIN, 30), -2); + assertEq(EmulatorCompat.int32ShiftRight(INT32_MIN, 31), -1); + + assertEq(EmulatorCompat.int32AddInt32(0, 0), 0); + assertEq(EmulatorCompat.int32AddInt32(0, 1), 1); + assertEq(EmulatorCompat.int32AddInt32(0, -1), -1); + assertEq(EmulatorCompat.int32AddInt32(-1, 0), -1); + assertEq(EmulatorCompat.int32AddInt32(INT32_MAX, 1), INT32_MIN); + assertEq(EmulatorCompat.int32AddInt32(INT32_MAX, INT32_MAX), -2); + + assertEq(EmulatorCompat.int32SubInt32(1, 1), 0); + assertEq(EmulatorCompat.int32SubInt32(1, 0), 1); + assertEq(EmulatorCompat.int32SubInt32(0, 1), -1); + assertEq(EmulatorCompat.int32SubInt32(-1, -1), 0); + assertEq(EmulatorCompat.int32SubInt32(INT32_MIN, INT32_MAX), 1); + assertEq(EmulatorCompat.int32SubInt32(INT32_MAX, INT32_MIN), -1); + + assertEq(EmulatorCompat.int16ToUint64(1), 1); + assertEq(EmulatorCompat.int16ToUint64(INT16_MAX), 32767); + assertEq(EmulatorCompat.int16ToUint64(INT16_MIN), 0xffffffffffff8000); + + assertEq(EmulatorCompat.int8ToUint64(int8(1)), 1); + assertEq(EmulatorCompat.int8ToUint64(int8(127)), 127); + assertEq(EmulatorCompat.int8ToUint64(int8(-128)), 0xffffffffffffff80); + } + + function testUint32Log2() public { + assertEq(EmulatorCompat.uint32Log2(1), 0); + assertEq(EmulatorCompat.uint32Log2(2), 1); + assertEq(EmulatorCompat.uint32Log2(3), 1); + assertEq(EmulatorCompat.uint32Log2(4), 2); + assertEq(EmulatorCompat.uint32Log2(5), 2); + assertEq(EmulatorCompat.uint32Log2(0x7fffffff), 30); + assertEq(EmulatorCompat.uint32Log2(0x80000000), 31); + assertEq(EmulatorCompat.uint32Log2(0xffffffff), 31); + } + + function testUint32Log2Of0() public { + vm.expectRevert("EmulatorCompat: log2(0) is undefined"); + EmulatorCompat.uint32Log2(0); + } +} diff --git a/test/SendCmioResponse.t.sol b/test/SendCmioResponse.t.sol new file mode 100644 index 00000000..61217bb6 --- /dev/null +++ b/test/SendCmioResponse.t.sol @@ -0,0 +1,177 @@ +// THIS IS AUTO GENERATED, ONLY EDIT THE TEMPLATE + +// Copyright Cartesi and individual authors (see AUTHORS) +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +pragma solidity ^0.8.0; + +import "forge-std/StdJson.sol"; +import "forge-std/console.sol"; +import "forge-std/Test.sol"; + +import "src/EmulatorConstants.sol"; +import "src/SendCmioResponse.sol"; +import "./BufferAux.sol"; + +contract SendCmioResponse_Test is Test { + using Buffer for Buffer.Context; + using BufferAux for Buffer.Context; + using stdJson for string; + + // configure the tests + string constant JSON_PATH = "./test/uarch-log/"; + string constant CATALOG_PATH = "catalog.json"; + string constant SEND_CMIO_RESPONSE_PATH = "send-cmio-response-steps.json"; + + uint256 constant siblingsLength = 59; + + struct Entry { + string binaryFilename; + string finalRootHash; + string initialRootHash; + string logFilename; + bool proof; + uint256 proofsFrequency; + uint256 steps; + } + + struct RawAccess { + uint256 addressAccess; + uint256 log2_size; + string read_hash; + string read_value; + string[] sibling_hashes; + string typeAccess; + string written_hash; + } + + function testSendCmioResponse() public { + Entry[] memory catalog = + loadCatalog(string.concat(JSON_PATH, CATALOG_PATH)); + string memory resetLog = + string.concat(JSON_PATH, SEND_CMIO_RESPONSE_PATH); + + // all tests combined can easily run out of gas, stop metering + // also raise memory_limit in foundry.toml per https://github.com/foundry-rs/foundry/issues/3971 + vm.pauseGasMetering(); + // create a large buffer and reuse it + bytes memory buffer = new bytes(100 * (siblingsLength + 1) * 32); + + for (uint256 i = 0; i < catalog.length; i++) { + if ( + keccak256(abi.encodePacked(catalog[i].logFilename)) + != keccak256(abi.encodePacked("send-cmio-response-steps.json")) + ) { + continue; + } + console.log("Replaying log file %s ...", catalog[i].logFilename); + require( + catalog[i].proofsFrequency == 1, "require proof in every step" + ); + + string memory rj = loadJsonLog(resetLog); + + bytes32 initialRootHash = + vm.parseBytes32(string.concat("0x", catalog[i].initialRootHash)); + bytes32 finalRootHash = + vm.parseBytes32(string.concat("0x", catalog[i].finalRootHash)); + + loadBufferFromRawJson(buffer, rj); + + AccessLogs.Context memory accessLogs = + AccessLogs.Context(initialRootHash, Buffer.Context(buffer, 0)); + + // Prepare arguments for sendCmioResponse + // These values are hard-coded in order to match the values used when generating the test log file + uint16 reason = 1; + bytes memory response = bytes("This is a test cmio response"); + require( + response.length == 28, + "The response data must match the hard-coded value in the test log file" + ); + bytes memory paddedResponse = new bytes(32); + for (uint256 j = 0; j < response.length; j++) { + paddedResponse[j] = response[j]; + } + bytes32 paddedResponseHash = keccak256(paddedResponse); + // call sendCmioResponse + SendCmioResponse.sendCmioResponse( + accessLogs, reason, paddedResponseHash, uint32(response.length) + ); + // ensure that the final root hash matches the expected value + assertEq( + accessLogs.currentRootHash, + finalRootHash, + "final root hash must match" + ); + } + } + + function loadCatalog(string memory path) + private + view + returns (Entry[] memory) + { + string memory json = vm.readFile(path); + bytes memory raw = json.parseRaw(""); + Entry[] memory catalog = abi.decode(raw, (Entry[])); + + return catalog; + } + + function loadJsonLog(string memory path) + private + view + returns (string memory) + { + return vm.readFile(path); + } + + function loadBufferFromRawJson(bytes memory data, string memory rawJson) + private + pure + { + string memory key = ".accesses"; + bytes memory raw = rawJson.parseRaw(key); + RawAccess[] memory rawAccesses = abi.decode(raw, (RawAccess[])); + uint256 arrayLength = rawAccesses.length; + + Buffer.Context memory buffer = Buffer.Context(data, 0); + + for (uint256 i = 0; i < arrayLength; i++) { + if (rawAccesses[i].log2_size == 3) { + buffer.writeBytes32( + vm.parseBytes32( + string.concat("0x", rawAccesses[i].read_value) + ) + ); + } else { + buffer.writeBytes32( + vm.parseBytes32( + string.concat("0x", rawAccesses[i].read_hash) + ) + ); + } + + for (uint256 j = 0; j < rawAccesses[i].sibling_hashes.length; j++) { + buffer.writeBytes32( + vm.parseBytes32( + string.concat("0x", rawAccesses[i].sibling_hashes[j]) + ) + ); + } + } + } +} diff --git a/test/UArchCompat.t.sol b/test/UArchCompat.t.sol deleted file mode 100644 index 102edce0..00000000 --- a/test/UArchCompat.t.sol +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright Cartesi and individual authors (see AUTHORS) -// SPDX-License-Identifier: Apache-2.0 -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -import "forge-std/console.sol"; -import "forge-std/Test.sol"; -import "src/UArchCompat.sol"; - -pragma solidity ^0.8.0; - -contract UArchCompatTest is Test { - int16 constant INT16_MAX = type(int16).max; - int32 constant INT32_MAX = type(int32).max; - int64 constant INT64_MAX = type(int64).max; - int16 constant INT16_MIN = type(int16).min; - int32 constant INT32_MIN = type(int32).min; - int64 constant INT64_MIN = type(int64).min; - uint16 constant UINT16_MAX = type(uint16).max; - uint32 constant UINT32_MAX = type(uint32).max; - uint64 constant UINT64_MAX = type(uint64).max; - - function testSanity() public { - assertEq(UINT16_MAX, 65535); - assertEq(UINT32_MAX, 4294967295); - assertEq(UINT64_MAX, 18446744073709551615); - assertEq(INT16_MAX, 32767); - assertEq(INT32_MAX, 2147483647); - assertEq(INT64_MAX, 9223372036854775807); - assertEq(INT16_MIN, -32768); - assertEq(INT32_MIN, -INT32_MAX - 1); - assertEq(INT64_MIN, -INT64_MAX - 1); - } - - function testCompat() public { - assertEq(UArchCompat.uint64ToInt32(1), 1); - assertEq(UArchCompat.uint64ToInt32(0xffffffff), -1); - assertEq(UArchCompat.uint64ToInt32(0xffffffff << 31), INT32_MIN); - assertEq(UArchCompat.uint64ToInt32(0xffffffff << 32), 0); - - assertEq(UArchCompat.uint64AddInt32(2, -1), 1); - assertEq(UArchCompat.uint64AddInt32(0, -1), UINT64_MAX); - assertEq(UArchCompat.uint64AddInt32(UINT64_MAX, 1), 0); - - assertEq(UArchCompat.uint64SubUint64(1, 1), 0); - assertEq(UArchCompat.uint64SubUint64(0, 1), UINT64_MAX); - - assertEq(UArchCompat.uint64AddUint64(0, 1), 1); - assertEq(UArchCompat.uint64AddUint64(UINT64_MAX, 1), 0); - - assertEq(UArchCompat.uint64ShiftRight(0, 0), 0); - assertEq(UArchCompat.uint64ShiftRight(0, 1), 0); - assertEq(UArchCompat.uint64ShiftRight(4, 1), 2); - assertEq(UArchCompat.uint64ShiftRight(4, 2), 1); - assertEq(UArchCompat.uint64ShiftRight(4, 3), 0); - assertEq(UArchCompat.uint64ShiftRight(UINT64_MAX, 63), 1); - - assertEq(UArchCompat.uint64ShiftLeft(0, 0), 0); - assertEq(UArchCompat.uint64ShiftLeft(0, 1), 0); - assertEq(UArchCompat.uint64ShiftLeft(4, 1), 8); - assertEq(UArchCompat.uint64ShiftLeft(4, 2), 16); - assertEq(UArchCompat.uint64ShiftLeft(UINT64_MAX, 63), 1 << 63); - - assertEq(UArchCompat.int64ShiftRight(0, 0), 0); - assertEq(UArchCompat.int64ShiftRight(0, 1), 0); - assertEq(UArchCompat.int64ShiftRight(4, 1), 2); - assertEq(UArchCompat.int64ShiftRight(4, 2), 1); - assertEq(UArchCompat.int64ShiftRight(4, 3), 0); - assertEq(UArchCompat.int64ShiftRight(INT64_MAX, 62), 1); - assertEq(UArchCompat.int64ShiftRight(INT64_MAX, 63), 0); - assertEq(UArchCompat.int64ShiftRight(-1, 1), -1); - assertEq(UArchCompat.int64ShiftRight(-4, 1), -2); - assertEq(UArchCompat.int64ShiftRight(INT64_MIN, 62), -2); - assertEq(UArchCompat.int64ShiftRight(INT64_MIN, 63), -1); - - assertEq(UArchCompat.int64AddInt64(0, 0), 0); - assertEq(UArchCompat.int64AddInt64(0, 1), 1); - assertEq(UArchCompat.int64AddInt64(0, -1), -1); - assertEq(UArchCompat.int64AddInt64(-1, 0), -1); - assertEq(UArchCompat.int64AddInt64(INT64_MAX, 1), INT64_MIN); - assertEq(UArchCompat.int64AddInt64(INT64_MAX, INT64_MAX), -2); - - assertEq(UArchCompat.uint32ShiftRight(0, 0), 0); - assertEq(UArchCompat.uint32ShiftRight(0, 1), 0); - assertEq(UArchCompat.uint32ShiftRight(4, 1), 2); - assertEq(UArchCompat.uint32ShiftRight(4, 2), 1); - assertEq(UArchCompat.uint32ShiftRight(4, 3), 0); - assertEq(UArchCompat.uint32ShiftRight(UINT32_MAX, 31), 1); - - assertEq(UArchCompat.uint32ShiftLeft(0, 0), 0); - assertEq(UArchCompat.uint32ShiftLeft(0, 1), 0); - assertEq(UArchCompat.uint32ShiftLeft(4, 1), 8); - assertEq(UArchCompat.uint32ShiftLeft(4, 2), 16); - assertEq(UArchCompat.uint32ShiftLeft(4, 3), 32); - assertEq(UArchCompat.uint32ShiftLeft(UINT32_MAX, 31), 0x80000000); - - assertEq(UArchCompat.int32ToUint64(1), 1); - assertEq(UArchCompat.int32ToUint64(INT32_MAX), 2147483647); - assertEq(UArchCompat.int32ToUint64(INT32_MIN), 0xffffffff80000000); - - assertEq(UArchCompat.int32ShiftRight(0, 0), 0); - assertEq(UArchCompat.int32ShiftRight(0, 1), 0); - assertEq(UArchCompat.int32ShiftRight(4, 1), 2); - assertEq(UArchCompat.int32ShiftRight(4, 2), 1); - assertEq(UArchCompat.int32ShiftRight(4, 3), 0); - assertEq(UArchCompat.int32ShiftRight(INT32_MAX, 30), 1); - assertEq(UArchCompat.int32ShiftRight(INT32_MAX, 31), 0); - assertEq(UArchCompat.int32ShiftRight(-1, 1), -1); - assertEq(UArchCompat.int32ShiftRight(-4, 1), -2); - assertEq(UArchCompat.int32ShiftRight(INT32_MIN, 30), -2); - assertEq(UArchCompat.int32ShiftRight(INT32_MIN, 31), -1); - - assertEq(UArchCompat.int32AddInt32(0, 0), 0); - assertEq(UArchCompat.int32AddInt32(0, 1), 1); - assertEq(UArchCompat.int32AddInt32(0, -1), -1); - assertEq(UArchCompat.int32AddInt32(-1, 0), -1); - assertEq(UArchCompat.int32AddInt32(INT32_MAX, 1), INT32_MIN); - assertEq(UArchCompat.int32AddInt32(INT32_MAX, INT32_MAX), -2); - - assertEq(UArchCompat.int32SubInt32(1, 1), 0); - assertEq(UArchCompat.int32SubInt32(1, 0), 1); - assertEq(UArchCompat.int32SubInt32(0, 1), -1); - assertEq(UArchCompat.int32SubInt32(-1, -1), 0); - assertEq(UArchCompat.int32SubInt32(INT32_MIN, INT32_MAX), 1); - assertEq(UArchCompat.int32SubInt32(INT32_MAX, INT32_MIN), -1); - - assertEq(UArchCompat.int16ToUint64(1), 1); - assertEq(UArchCompat.int16ToUint64(INT16_MAX), 32767); - assertEq(UArchCompat.int16ToUint64(INT16_MIN), 0xffffffffffff8000); - - assertEq(UArchCompat.int8ToUint64(int8(1)), 1); - assertEq(UArchCompat.int8ToUint64(int8(127)), 127); - assertEq(UArchCompat.int8ToUint64(int8(-128)), 0xffffffffffffff80); - } -} diff --git a/test/UArchInterpret.t.sol b/test/UArchInterpret.t.sol index fbd063ba..7571f8d7 100644 --- a/test/UArchInterpret.t.sol +++ b/test/UArchInterpret.t.sol @@ -18,7 +18,7 @@ import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; import "./UArchInterpret.sol"; -import "src/UArchConstants.sol"; +import "src/EmulatorConstants.sol"; pragma solidity ^0.8.0; @@ -66,23 +66,23 @@ contract UArchInterpretTest is Test { string.concat(BINARIES_PATH, catalog[i].binaryFilename) ); // init pc to ram start - UArchCompat.writePc(a, UArchConstants.UARCH_RAM_START_ADDRESS); + EmulatorCompat.writePc(a, EmulatorConstants.UARCH_RAM_START_ADDRESS); // init cycle to 0 - UArchCompat.writeCycle(a, 0); + EmulatorCompat.writeCycle(a, 0); UArchInterpret.interpret(a); - uint64 x = UArchCompat.readX(a, TEST_STATUS_X); + uint64 x = EmulatorCompat.readX(a, TEST_STATUS_X); assertEq( // read test result from the register x, uint64(TEST_SUCEEDED) ); - bool halt = UArchCompat.readHaltFlag(a); + bool halt = EmulatorCompat.readHaltFlag(a); assertTrue(halt, "machine should halt"); - uint64 cycle = UArchCompat.readCycle(a); + uint64 cycle = EmulatorCompat.readCycle(a); assertEq(cycle, catalog[i].steps, "cycle values should match"); } } @@ -91,9 +91,9 @@ contract UArchInterpretTest is Test { AccessLogs.Context memory a = newAccessLogsContext(); // init pc to ram start - UArchCompat.writePc(a, UArchConstants.UARCH_RAM_START_ADDRESS); + EmulatorCompat.writePc(a, EmulatorConstants.UARCH_RAM_START_ADDRESS); // init cycle to uint64.max - UArchCompat.writeCycle(a, type(uint64).max); + EmulatorCompat.writeCycle(a, type(uint64).max); UArchStep.UArchStepStatus status = UArchInterpret.interpret(a); @@ -102,7 +102,7 @@ contract UArchInterpretTest is Test { "machine should be cycle overflow" ); - uint64 cycle = UArchCompat.readCycle(a); + uint64 cycle = EmulatorCompat.readCycle(a); assertEq( cycle, type(uint64).max, @@ -110,9 +110,9 @@ contract UArchInterpretTest is Test { ); // reset cycle to 0 - UArchCompat.writeCycle(a, 0); + EmulatorCompat.writeCycle(a, 0); // set machine to halt - UArchCompat.setHaltFlag(a); + EmulatorCompat.setHaltFlag(a); status = UArchInterpret.interpret(a); @@ -126,9 +126,9 @@ contract UArchInterpretTest is Test { AccessLogs.Context memory a = newAccessLogsContext(); // init pc to ram start - UArchCompat.writePc(a, UArchConstants.UARCH_RAM_START_ADDRESS); + EmulatorCompat.writePc(a, EmulatorConstants.UARCH_RAM_START_ADDRESS); // init cycle to 0 - UArchCompat.writeCycle(a, 0); + EmulatorCompat.writeCycle(a, 0); vm.expectRevert("illegal instruction"); UArchInterpret.interpret(a); diff --git a/test/UArchReset.t.sol b/test/UArchReset.t.sol index 1e792f15..693a8e26 100644 --- a/test/UArchReset.t.sol +++ b/test/UArchReset.t.sol @@ -21,7 +21,7 @@ import "forge-std/StdJson.sol"; import "forge-std/console.sol"; import "forge-std/Test.sol"; -import "src/UArchConstants.sol"; +import "src/EmulatorConstants.sol"; import "src/UArchReset.sol"; import "./BufferAux.sol"; @@ -145,12 +145,12 @@ contract UArchReset_Test is Test { } assertEq( rawAccesses[0].addressAccess, - UArchConstants.RESET_POSITION, + EmulatorConstants.UARCH_STATE_START_ADDRESS, "position should be (0x400000)" ); assertEq( rawAccesses[0].log2_size, - UArchConstants.RESET_ALIGNED_SIZE, + EmulatorConstants.UARCH_STATE_LOG2_SIZE, "log2Size should be 22" );