Skip to content

Commit

Permalink
feat!: Add support to ECALL and EBREAK
Browse files Browse the repository at this point in the history
  • Loading branch information
mpernambuco committed Apr 23, 2024
1 parent 7d304ea commit 28ff4b0
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 88 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-7545c7a2857a873fa1909ec4174032c4e4702116
version: nightly-008922d5165c764859bc540d7298045eebf5bc60

- run: forge build
- run: forge fmt --check src test
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly-7545c7a2857a873fa1909ec4174032c4e4702116
version: nightly-008922d5165c764859bc540d7298045eebf5bc60

- name: Run all tests
run: make test-all
77 changes: 37 additions & 40 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ TEST_DIR := test
DOWNLOADDIR := downloads
SRC_DIR := src

EMULATOR_VERSION ?= v0.16.1
EMULATOR_VERSION ?= v0.17.0

TESTS_DATA_FILE ?= cartesi-machine-tests-data-$(EMULATOR_VERSION).deb
TESTS_DATA_DOWNLOAD_URL := https://github.com/cartesi/machine-emulator/releases/download/$(EMULATOR_VERSION)/$(TESTS_DATA_FILE)
Expand All @@ -17,6 +17,7 @@ LOG_TEST_DIR := $(TEST_DIR)/uarch-log

DOWNLOADFILES := $(TESTS_DATA_DOWNLOAD_FILEPATH) $(LOG_DOWNLOAD_FILEPATH)
GENERATEDFILES := $(SRC_DIR)/*.sol
DEPDIRS = $(TESTS_DATA_DIR) $(LOG_TEST_DIR)

help:
@echo 'Cleaning targets:'
Expand All @@ -36,72 +37,42 @@ help:
@echo ' test-prod - test production code'
@echo ' test-replay - test log files'

$(TESTS_DATA_DOWNLOAD_FILEPATH):
@mkdir -p $(DOWNLOADDIR)
@wget -nc $(TESTS_DATA_DOWNLOAD_URL) -P $(DOWNLOADDIR)

$(LOG_DOWNLOAD_FILEPATH):
@mkdir -p $(DOWNLOADDIR)
@wget -nc $(LOG_DOWNLOAD_URL) -P $(DOWNLOADDIR)

all: build test-all

build: generate-step generate-reset generate-constants
forge build --use 0.8.21
build: generate-step generate-reset generate-constants generate-prod
forge build --use 0.8.21

clean:
rm -rf src/AccessLogs.sol test/UArchReplay_*.t.sol
rm -rf $(TESTS_DATA_DIR) $(LOG_TEST_DIR) $(DOWNLOADDIR)
rm -rf test/UArchReplay_*.t.sol
rm -rf $(DEPDIRS) $(DOWNLOADDIR)
forge clean

shasum-download: $(DOWNLOADFILES)
shasum -a 256 $^ > $@

shasum-generated: $(GENERATEDFILES)
shasum -a 256 $^ > $@

checksum-download: $(DOWNLOADFILES)
@shasum -ca 256 shasum-download

checksum-mock:
@shasum -ca 256 shasum-mock

checksum-prod:
@shasum -ca 256 shasum-prod

pretest: checksum-download
mkdir -p $(TESTS_DATA_DIR) $(LOG_TEST_DIR)
ar p $(TESTS_DATA_DOWNLOAD_FILEPATH) data.tar.xz | tar -xJf - --strip-components=7 -C $(TESTS_DATA_DIR) ./usr/share/cartesi-machine/tests/data/uarch
tar -xzf $(LOG_DOWNLOAD_FILEPATH) --strip-components=1 -C $(LOG_TEST_DIR)
rm -f $(TESTS_DATA_DIR)/*.dump $(TESTS_DATA_DIR)/*.elf

test-all:
$(MAKE) test-mock
$(MAKE) test-prod
$(MAKE) test-replay
$(MAKE) test-prod

test-mock: pretest
test-mock: dep
$(MAKE) generate-mock
forge test --use 0.8.21 -vv --match-contract UArchInterpret

test-prod: pretest
test-prod: dep
$(MAKE) generate-prod
forge test --use 0.8.21 -vv --no-match-contract "UArchInterpret|UArchReplay|UArchReset"

test-replay: pretest
test-replay: dep
$(MAKE) generate-prod
$(MAKE) generate-replay
forge test --use 0.8.21 -vv --match-contract "UArchReplay|UArchReset"

generate-mock:
./helper_scripts/generate_AccessLogs.sh mock
$(MAKE) fmt
$(MAKE) checksum-mock

generate-prod:
./helper_scripts/generate_AccessLogs.sh prod
$(MAKE) fmt
$(MAKE) checksum-prod

generate-replay:
./helper_scripts/generate_ReplayTests.sh
Expand All @@ -119,7 +90,33 @@ generate-reset: $(EMULATOR_DIR)/src/uarch-reset-state.cpp
fmt:
forge fmt src test


download: $(DOWNLOADDIR)

dep: $(DEPDIRS)

$(DOWNLOADDIR):
@mkdir -p $(DOWNLOADDIR)
@wget -nc $(TESTS_DATA_DOWNLOAD_URL) -P $(DOWNLOADDIR)
@wget -nc $(LOG_DOWNLOAD_URL) -P $(DOWNLOADDIR)
$(MAKE) checksum-download

shasum-download:
shasum -a 256 $(DOWNLOADFILES) > shasum-download

checksum-download:
@shasum -ca 256 shasum-download

$(TESTS_DATA_DIR): | download
@mkdir -p $(TESTS_DATA_DIR)
@ar p $(TESTS_DATA_DOWNLOAD_FILEPATH) data.tar.xz | tar -xJf - --strip-components=7 -C $(TESTS_DATA_DIR) ./usr/share/cartesi-machine/tests/data/uarch
@rm -f $(TESTS_DATA_DIR)/*.dump $(TESTS_DATA_DIR)/*.elf

$(LOG_TEST_DIR): | download
@mkdir -p $(LOG_TEST_DIR)
@tar -xzf $(LOG_DOWNLOAD_FILEPATH) --strip-components=1 -C $(LOG_TEST_DIR)

submodules:
git submodule update --init --recursive

.PHONY: help all build clean checksum-download checksum-mock checksum-prod 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
2 changes: 2 additions & 0 deletions helper_scripts/generate_UArchConstants.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ out:write(' uint64 constant UARCH_RAM_LENGTH = 0x' .. hex(cartesi.UARCH_RAM_L
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()
13 changes: 7 additions & 6 deletions helper_scripts/generate_UArchStep.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ 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"
KEYWORD_START="START OF AUTO-GENERATED CODE"
KEYWORD_END="END OF AUTO-GENERATED CODE"

# function with to be internal
INTERNAL_FN="step"
# function with unused variable, to silence warning
UNUSED_INSN_FN="executeFENCE"

# grab head and tail of the template
start=`cat "$TEMPLATE_FILE" | grep "$KEYWORD_START" -n | grep -Eo "[0-9]*"`
Expand All @@ -37,24 +36,26 @@ h_src=`echo "enum ${BASH_REMATCH[1]} {${BASH_REMATCH[2]}}"`
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
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"`
pattern="namespace cartesi \{(.*)\}"
[[ $cpp_src =~ $pattern ]]
# replace cpp specific syntaxes with solidity ones
cpp_src=`echo "${BASH_REMATCH[1]}" \
| $SED "/template/d" \
| $SED "/dumpInsn/d" \
| $SED "/note/d" \
| $SED "/note = a.make_scoped_note/d" \
| $SED "/(void) note/d" \
| $SED "s/constexpr//g" \
| $SED "s/UarchState &a/AccessLogs.Context memory a/g" \
| $SED "s/throw std::runtime_error/revert/g" \
| $SED "s/::/./g" \
| $SED "s/UINT64_MAX/type(uint64).max/g" \
| $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/([^\n]*) $UNUSED_INSN_FN([^\n]*) uint32 insn,([^\n]*)/\1 $UNUSED_INSN_FN\2 uint32,\3/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 "s/ returns (void)//g"`

# compose the solidity file from all components
Expand Down
4 changes: 2 additions & 2 deletions shasum-download
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
583595858e749c5704d02fca312470a65077a0365ddbc62340b4d0205a81c8ef downloads/cartesi-machine-tests-data-v0.16.1.deb
4c845a39cc9186af33b99554aacae8cc4777f5de14851a8919280cdf9b2245b6 downloads/uarch-riscv-tests-json-logs-v0.16.1.tar.gz
d3b254f274fd6c32e6688365886fbe6b86f91aab733a83cdb73e2461ed7a0d96 downloads/cartesi-machine-tests-data-v0.17.0.deb
8f0cd797b78466b62184257b3276d6c029c5ea5a53672036ad507cbf417d0211 downloads/uarch-riscv-tests-json-logs-v0.17.0.tar.gz
9 changes: 9 additions & 0 deletions src/UArchCompat.sol
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,13 @@ library UArchCompat {
{
return v >> (count & 0x1f);
}

function throwRuntimeError(
AccessLogs.Context memory, /* a */
string memory text
) internal pure {
revert(text);
}

function putChar(AccessLogs.Context memory a, uint8 c) internal pure {}
}
4 changes: 3 additions & 1 deletion src/UArchConstants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ library UArchConstants {
uint64 constant RESET_POSITION = 0x400000;
uint8 constant RESET_ALIGNED_SIZE = 22;
bytes32 constant PRESTINE_STATE =
0x0ceeb27295050183aff6fbead83d1033b469737d9aef99e1a6e5cb6e2bf2af8a;
0xc2b9cf2658f233f44c403aba6e9f9aa6709e00617b349c0190113517f03d13de;
uint64 constant UARCH_ECALL_FN_HALT = 1;
uint64 constant UARCH_ECALL_FN_PUTCHAR = 2;
// END OF AUTO-GENERATED CODE

uint64 constant LOG2_CYCLES_TO_RESET = 10;
Expand Down
36 changes: 30 additions & 6 deletions src/UArchStep.sol
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,7 @@ library UArchStep {
return advancePc(a, pc);
}

function executeFENCE(AccessLogs.Context memory a, uint32, uint64 pc)
function executeFENCE(AccessLogs.Context memory a, uint64 pc)
private
pure
{
Expand Down Expand Up @@ -1043,6 +1043,26 @@ library UArchStep {
return advancePc(a, pc);
}

function executeECALL(AccessLogs.Context memory a, uint64 pc)
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));
} else {
UArchCompat.throwRuntimeError(a, "unsupported ecall function");
}
return advancePc(a, pc);
}

function executeEBREAK(AccessLogs.Context memory a) private pure {
UArchCompat.throwRuntimeError(a, "uarch aborted");
}

/// \brief Returns true if the opcode field of an instruction matches the provided argument
function insnMatchOpcode(uint32 insn, uint32 opcode)
private
Expand Down Expand Up @@ -1198,9 +1218,13 @@ library UArchStep {
} else if (insnMatchOpcodeFunct3(insn, 0x13, 0x2)) {
return executeSLTI(a, insn, pc);
} else if (insnMatchOpcodeFunct3(insn, 0xf, 0x0)) {
return executeFENCE(a, insn, pc);
return executeFENCE(a, pc);
} else if (insn == uint32(0x73)) {
return executeECALL(a, pc);
} else if (insn == uint32(0x100073)) {
return executeEBREAK(a);
}
revert("illegal instruction");
UArchCompat.throwRuntimeError(a, "illegal instruction");
}

function step(AccessLogs.Context memory a)
Expand All @@ -1227,11 +1251,11 @@ library UArchStep {
return UArchStepStatus.Success;
}

// Explicit instantiation for uarch_step_state_access
// Explicit instantiation for uarch_state_access

// Explicit instantiation for uarch_record_step_state_access
// Explicit instantiation for uarch_record_state_access

// Explicit instantiation for uarch_replay_step_state_access
// Explicit instantiation for uarch_replay_state_access

// END OF AUTO-GENERATED CODE
}
10 changes: 10 additions & 0 deletions templates/AccessLogs.sol.template
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
// limitations under the License.
//

//:#ifdef test
// ***********************************************************
// WARNING: DO NOT COMMIT THIS FILE!
// This is the mock version of AccessLogs.
// It is intended solely for running the test binary programs.
// To generate production AccessLogs, run:
// make generate-prod
// ***********************************************************
//:#endif

//:#include macro.pp
/// DEV_COMMENT(templates/AccessLogs.sol.template)

Expand Down
29 changes: 15 additions & 14 deletions templates/UArchReplay.t.sol.template
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,23 @@ contract UArchReplay_@X@_Test is Test {
uint256 constant siblingsLength = 61;

struct Entry {
string binaryFilename;
string finalRootHash;
string initialRootHash;
string path;
string logFilename;
bool proof;
uint256 proofsFrequency;
uint256 steps;
}

struct RawAccess {
uint256 position;
uint256 addressAccess;
string hash;
uint256 log2Size;
string readHash;
string[] rawSiblings;
string accessType;
string val;
uint256 log2_size;
string read_hash;
string[] sibling_hashes;
string typeAccess;
string value;
}

function testReplay_@X@() public {
Expand All @@ -66,18 +67,18 @@ contract UArchReplay_@X@_Test is Test {

for (uint256 i = 0; i < catalog.length; i++) {
if (
keccak256(abi.encodePacked(catalog[i].path))
keccak256(abi.encodePacked(catalog[i].logFilename))
!= keccak256(abi.encodePacked("@PATH@"))
) {
continue;
}
console.log("Replaying file %s ...", catalog[i].path);
console.log("Replaying log file %s ...", catalog[i].logFilename);
require(
catalog[i].proofsFrequency == 1, "require proof in every step"
);

string memory rj =
loadJsonLog(string.concat(JSON_PATH, catalog[i].path));
loadJsonLog(string.concat(JSON_PATH, catalog[i].logFilename));

bytes32 initialRootHash =
vm.parseBytes32(string.concat("0x", catalog[i].initialRootHash));
Expand Down Expand Up @@ -140,23 +141,23 @@ contract UArchReplay_@X@_Test is Test {

for (uint256 i = 0; i < arrayLength; i++) {
if (
keccak256(abi.encodePacked(rawAccesses[i].accessType))
keccak256(abi.encodePacked(rawAccesses[i].typeAccess))
== keccak256(abi.encodePacked("read"))
) {
bytes8 word = bytes8(
vm.parseBytes(string.concat("0x", rawAccesses[i].val))
vm.parseBytes(string.concat("0x", rawAccesses[i].value))
);
buffer.writeBytes8(word);
}

buffer.writeBytes32(
vm.parseBytes32(string.concat("0x", rawAccesses[i].readHash))
vm.parseBytes32(string.concat("0x", rawAccesses[i].read_hash))
);

for (uint256 j = 0; j < siblingsLength; j++) {
buffer.writeBytes32(
vm.parseBytes32(
string.concat("0x", rawAccesses[i].rawSiblings[j])
string.concat("0x", rawAccesses[i].sibling_hashes[j])
)
);
}
Expand Down
Loading

0 comments on commit 28ff4b0

Please sign in to comment.