diff --git a/.ci/gdbstub-test.sh b/.ci/gdbstub-test.sh index 6bba5668..6128ddf8 100755 --- a/.ci/gdbstub-test.sh +++ b/.ci/gdbstub-test.sh @@ -2,12 +2,12 @@ set -e -u -o pipefail -export PATH=`pwd`/toolchain/riscv/bin:$PATH +export PATH=`pwd`/toolchain/bin:$PATH GDB= -prefixes=("${CROSS_COMPILE}" "riscv32-unknown-elf" "riscv-none-elf") +prefixes=("${CROSS_COMPILE}" "riscv32-unknown-elf-" "riscv-none-elf-") for prefix in "${prefixes[@]}"; do - utility=${prefix}-gdb + utility=${prefix}gdb set +e # temporarily disable exit on error command -v "${utility}" &> /dev/null if [[ $? == 0 ]]; then @@ -21,7 +21,7 @@ if [ -z ${GDB} ]; then exit 1 fi -build/rv32emu -g build/puzzle.elf & +build/rv32emu -g build/riscv32/puzzle & PID=$! # Before starting GDB, we should ensure rv32emu is still running. @@ -31,9 +31,9 @@ fi OPTS= tmpfile=/tmp/rv32emu-gdbstub.$PID -breakpoints=(0x10700 0x10800 0x10900) +breakpoints=(0x10500 0x10600 0x10700) bkpt_count=${#breakpoints[@]} -OPTS+="-ex 'file build/puzzle.elf' " +OPTS+="-ex 'file build/riscv32/puzzle' " OPTS+="-ex 'target remote :1234' " for t in ${breakpoints[@]}; do OPTS+="-ex 'break *$t' " diff --git a/.ci/riscv-tests.sh b/.ci/riscv-tests.sh index ad11fda7..8d5b5d72 100755 --- a/.ci/riscv-tests.sh +++ b/.ci/riscv-tests.sh @@ -7,7 +7,7 @@ pip3 install git+https://github.com/riscv/riscof.git@d38859f85fe407bcacddd2efcd3 set -x -export PATH=`pwd`/toolchain/riscv/bin:$PATH +export PATH=`pwd`/toolchain/bin:$PATH make clean make arch-test RISCV_DEVICE=IMAFCZicsrZifencei || exit 1 diff --git a/.ci/riscv-toolchain-install.sh b/.ci/riscv-toolchain-install.sh index 23f8edf6..d9eadae0 100755 --- a/.ci/riscv-toolchain-install.sh +++ b/.ci/riscv-toolchain-install.sh @@ -8,10 +8,15 @@ check_platform mkdir -p toolchain -# GNU Toolchain for RISC-V -GCC_VER=2024.04.12 -TOOLCHAIN_REPO=https://github.com/riscv-collab/riscv-gnu-toolchain/releases +if [[ "$#" == "0" ]] || [[ "$1" != "riscv-collab" ]]; then + GCC_VER=14.2.0-1 + TOOLCHAIN_REPO=https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack + TOOLCHAIN_URL=${TOOLCHAIN_REPO}/releases/download/v${GCC_VER}/xpack-riscv-none-elf-gcc-${GCC_VER}-linux-x64.tar.gz +else + UBUNTU_VER=`lsb_release -r | cut -f2` + GCC_VER=2024.04.12 + TOOLCHAIN_REPO=https://github.com/riscv-collab/riscv-gnu-toolchain + TOOLCHAIN_URL=${TOOLCHAIN_REPO}/releases/download/${GCC_VER}/riscv32-elf-ubuntu-${UBUNTU_VER}-gcc-nightly-${GCC_VER}-nightly.tar.gz +fi -wget -q \ - ${TOOLCHAIN_REPO}/download/${GCC_VER}/riscv32-elf-ubuntu-22.04-gcc-nightly-${GCC_VER}-nightly.tar.gz -O- \ -| tar -C toolchain -xz +wget -q ${TOOLCHAIN_URL} -O- | tar -C toolchain --strip-components=1 -xz diff --git a/.github/workflows/build-artifact.yml b/.github/workflows/build-artifact.yml new file mode 100644 index 00000000..fc5b84bc --- /dev/null +++ b/.github/workflows/build-artifact.yml @@ -0,0 +1,87 @@ +name: Build artifact + +on: + push: + branches: + - master + workflow_dispatch: + +jobs: + detect-file-change: + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Test file change + id: test-file-change + uses: tj-actions/changed-files@v45 + with: + fetch_additional_submodule_history: 'true' + files: | + tests/ansibench/* + tests/rv8-bench/* + tests/*.c + - name: Set alias + id: has_changed_files + run: | + if [[ ${{ steps.test-file-change.outputs.any_modified }} == true ]]; then + echo "has_changed_files=true" >> $GITHUB_OUTPUT + else + echo "has_changed_files=false" >> $GITHUB_OUTPUT + fi + outputs: + has_changed_files: ${{ steps.has_changed_files.outputs.has_changed_files }} + + build-artifact: + needs: [detect-file-change] + if: ${{ needs.detect-file-change.outputs.has_changed_files == 'true' || github.event_name == 'workflow_dispatch' }} + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: 'true' + - name: Install dependencies + run: | + sudo apt-get update -q -y + sudo apt-get upgrade -q -y + sudo apt-get install -q -y gcc-multilib g++-multilib + sudo apt-get install -q -y opam build-essential libgmp-dev z3 pkg-config zlib1g-dev + .ci/riscv-toolchain-install.sh + echo "$PWD/toolchain/bin" >> $GITHUB_PATH + - name: Build binaries + run: | + make artifact ENABLE_PREBUILT=0 + mkdir -p /tmp/rv32emu-prebuilt + mv build/linux-x86-softfp build/riscv32 /tmp/rv32emu-prebuilt + - name: Build Sail model + run: | + cd /tmp + opam init -y --disable-sandboxing + opam switch create ocaml-base-compiler.4.06.1 + opam install sail -y + eval $(opam config env) + git clone https://github.com/riscv/sail-riscv.git + cd sail-riscv + git checkout 9547a30bf84572c458476591b569a95f5232c1c7 + ARCH=RV32 make -j + mkdir -p /tmp/rv32emu-prebuilt/sail_cSim + mv c_emulator/riscv_sim_RV32 /tmp/rv32emu-prebuilt/sail_cSim + - name: Create tarball + run: | + cd /tmp + tar -zcvf rv32emu-prebuilt.tar.gz rv32emu-prebuilt + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.RV32EMU_PREBUILT_TOKEN }} + run: | + RELEASE_TAG=$(date +'%Y.%m.%d') + cd /tmp + gh release create $RELEASE_TAG \ + --repo sysprog21/rv32emu-prebuilt \ + --title "$RELEASE_TAG""-nightly" + gh release upload $RELEASE_TAG \ + rv32emu-prebuilt.tar.gz \ + --repo sysprog21/rv32emu-prebuilt diff --git a/.gitignore b/.gitignore index 86dd5647..60dad509 100644 --- a/.gitignore +++ b/.gitignore @@ -16,9 +16,14 @@ build/softfloat build/cache/ build/map/ build/path/ +build/linux-x86-softfp/ +build/riscv32/ +build/sail_cSim/ +*.a *.o *.o.d tests/**/*.elf tests/arch-test-target/config.ini +tests/arch-test-target/sail_cSim/riscv_sim_RV32 __pycache__/ src/rv32_jit.c diff --git a/.gitmodules b/.gitmodules index 8540dbfc..b9b99ffa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -11,3 +11,15 @@ url = https://github.com/sysprog21/berkeley-softfloat-3 branch = rv32emu shallow = true +[submodule "tests/ansibench"] + path = tests/ansibench + url = https://github.com/sysprog21/ansibench + shallow = true +[submodule "tests/rv8-bench"] + path = tests/rv8-bench + url = https://github.com/sysprog21/rv8-bench + shallow = true +[submodule "src/ieeelib"] + path = src/ieeelib + url = https://github.com/sysprog21/ieeelib + shallow = true diff --git a/Makefile b/Makefile index d8359110..3c21b459 100644 --- a/Makefile +++ b/Makefile @@ -182,7 +182,7 @@ $(OUT)/emulate.o: CFLAGS += -foptimize-sibling-calls -fomit-frame-pointer -fno-s .DEFAULT_GOAL := all include mk/external.mk - +include mk/artifact.mk include mk/wasm.mk all: config $(BIN) @@ -229,13 +229,13 @@ tool: $(TOOLS_BIN) include mk/riscv-arch-test.mk include mk/tests.mk -CHECK_ELF_FILES := \ - hello \ - puzzle \ - fcalc +# the prebuilt executables are built for "rv32im" +CHECK_ELF_FILES := ifeq ($(call has, EXT_M), 1) CHECK_ELF_FILES += \ + puzzle \ + fcalc \ pi endif @@ -244,10 +244,19 @@ EXPECTED_puzzle = success in 2005 trials EXPECTED_fcalc = Performed 12 tests, 0 failures, 100% success rate. EXPECTED_pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086 -check: $(BIN) +check-hello: $(BIN) + $(Q)$(PRINTF) "Running hello.elf ..."; \ + if [ "$(shell $(BIN) $(OUT)/hello.elf | uniq)" = "$(strip $(EXPECTED_hello)) inferior exit code 0" ]; then \ + $(call notice, [OK]); \ + else \ + $(PRINTF) "Failed.\n"; \ + exit 1; \ + fi; + +check: $(BIN) check-hello artifact $(Q)$(foreach e,$(CHECK_ELF_FILES),\ - $(PRINTF) "Running $(e).elf ... "; \ - if [ "$(shell $(BIN) $(OUT)/$(e).elf | uniq)" = "$(strip $(EXPECTED_$(e))) inferior exit code 0" ]; then \ + $(PRINTF) "Running $(e) ... "; \ + if [ "$(shell $(BIN) $(OUT)/riscv32/$(e) | uniq)" = "$(strip $(EXPECTED_$(e))) inferior exit code 0" ]; then \ $(call notice, [OK]); \ else \ $(PRINTF) "Failed.\n"; \ @@ -256,9 +265,9 @@ check: $(BIN) ) EXPECTED_aes_sha1 = 1242a6757c8aef23e50b5264f5941a2f4b4a347e - -misalign: $(BIN) - $(Q)$(PRINTF) "Running aes.elf ... "; - $(Q)if [ "$(shell $(BIN) -m $(OUT)/aes.elf | $(SHA1SUM))" = "$(EXPECTED_aes_sha1)" ]; then \ +misalign: $(BIN) artifact + $(Q)$(PRINTF) "Running uaes ... "; + $(Q)if [ "$(shell $(BIN) -m $(OUT)/riscv32/uaes | $(SHA1SUM))" = "$(EXPECTED_aes_sha1)" ]; then \ $(call notice, [OK]); \ else \ $(PRINTF) "Failed.\n"; \ diff --git a/README.md b/README.md index d5a926c2..808483cb 100644 --- a/README.md +++ b/README.md @@ -327,46 +327,8 @@ Use of this source code is governed by a MIT license that can be found in the [L ## External sources -In `rv32emu` repository, there are some prebuilt ELF files for testing purpose. -* `aes.elf` : See [tests/aes.c](tests/aes.c) -* `captcha.elf` : See [tests/captcha.c](tests/captcha.c) -* `cc.elf` : See [tests/cc](tests/cc) -* `chacha20.elf` : See [tests/chacha20](tests/chacha20) -* `coremark.elf` : See [eembc/coremark](https://github.com/eembc/coremark) [RV32M] -* `dhrystone.elf` : See [rv8-bench](https://github.com/michaeljclark/rv8-bench) -* `donut.elf` : See [donut.c](tests/donut.c) -* `doom.elf` : See [sysprog21/doom_riscv](https://github.com/sysprog21/doom_riscv) [RV32M] -* `fcalc.elf` : See [fcalc.c](tests/fcalc.c) -* `hamilton.elf` : See [hamilton.c](tests/hamilton.c) -* `ieee754.elf` : See [tests/ieee754.c](tests/ieee754.c) [RV32F] -* `jit-bf.elf` : See [ezaki-k/xkon_beta](https://github.com/ezaki-k/xkon_beta) -* `lena.elf`: See [tests/lena.c](tests/lena.c) -* `line.elf` : See [tests/line.c](tests/line.c) [RV32M] -* `maj2random.elf` : See [tests/maj2random.c](tests/maj2random.c) [RV32F] -* `mandelbrot.elf` : See [tests/mandelbrot.c](tests/mandelbrot.c) -* `nqueens.elf` : See [tests/nqueens.c](tests/nqueens.c) -* `nyancat.elf` : See [tests/nyancat.c](tests/nyancat.c) -* `pi.elf` : See [tests/pi.c](tests/pi.c) [RV32M] -* `qrcode.elf` : See [tests/qrcode.c](tests/qrcode.c) -* `quake.elf` : See [sysprog21/quake-embedded](https://github.com/sysprog21/quake-embedded) [RV32F] -* `readelf.elf` : See [tests/readelf](tests/readelf) -* `richards.elf` : See [tests/richards.c](tests/richards.c) -* `rvsim.elf` : See [tests/rvsim.c](tests/rvsim.c) -* `scimark2.elf` : See [tests/scimark2](tests/scimark2) [RV32MF] -* `smolnes.elf` : See [tests/smolnes](tests/smolnes.c) [RV32M] -* `spirograph.elf` : See [tests/spirograph.c](tests/spirograph.c) -* `stream.elf` : See [tests/stream](tests/stream.c) [RV32MF] -* `qsort.elf` : See [rv8-bench](https://github.com/michaeljclark/rv8-bench) -* `miniz.elf` : See [rv8-bench](https://github.com/michaeljclark/rv8-bench) -* `primes.elf` : See [rv8-bench](https://github.com/michaeljclark/rv8-bench) -* `sha512.elf` : See [rv8-bench](https://github.com/michaeljclark/rv8-bench) -* `numeric_sort.elf` : See [nbench](https://github.com/nfinit/ansibench/tree/master/nbench) -* `FP_emulation.elf` : See [nbench](https://github.com/nfinit/ansibench/tree/master/nbench) -* `bitfield.elf` : See [nbench](https://github.com/nfinit/ansibench/tree/master/nbench) -* `idea.elf` : See [nbench](https://github.com/nfinit/ansibench/tree/master/nbench) -* `assignment.elf` : See [nbench](https://github.com/nfinit/ansibench/tree/master/nbench) -* `string_sort.elf` : See [nbench](https://github.com/nfinit/ansibench/tree/master/nbench) -* `huffman.elf` : See [nbench](https://github.com/nfinit/ansibench/tree/master/nbench) +See [docs/prebuilt.md](docs/prebuilt.md). + ## Reference * [Writing a simple RISC-V emulator in plain C](https://fmash16.github.io/content/posts/riscv-emulator-in-c.html) diff --git a/build/FP_emulation.elf b/build/FP_emulation.elf deleted file mode 100644 index 8fd5e4aa..00000000 Binary files a/build/FP_emulation.elf and /dev/null differ diff --git a/build/aes.elf b/build/aes.elf deleted file mode 100644 index 7cbcd20f..00000000 Binary files a/build/aes.elf and /dev/null differ diff --git a/build/assignment.elf b/build/assignment.elf deleted file mode 100644 index a633e73d..00000000 Binary files a/build/assignment.elf and /dev/null differ diff --git a/build/bitfield.elf b/build/bitfield.elf deleted file mode 100644 index 456d691e..00000000 Binary files a/build/bitfield.elf and /dev/null differ diff --git a/build/captcha.elf b/build/captcha.elf deleted file mode 100644 index cad474b7..00000000 Binary files a/build/captcha.elf and /dev/null differ diff --git a/build/coremark.elf b/build/coremark.elf deleted file mode 100644 index 1da8631a..00000000 Binary files a/build/coremark.elf and /dev/null differ diff --git a/build/dhrystone.elf b/build/dhrystone.elf deleted file mode 100755 index 356ff0eb..00000000 Binary files a/build/dhrystone.elf and /dev/null differ diff --git a/build/donut.elf b/build/donut.elf deleted file mode 100644 index 71c54de7..00000000 Binary files a/build/donut.elf and /dev/null differ diff --git a/build/fcalc.elf b/build/fcalc.elf deleted file mode 100644 index a6e57552..00000000 Binary files a/build/fcalc.elf and /dev/null differ diff --git a/build/hamilton.elf b/build/hamilton.elf deleted file mode 100644 index 5f67e081..00000000 Binary files a/build/hamilton.elf and /dev/null differ diff --git a/build/huffman.elf b/build/huffman.elf deleted file mode 100644 index 483e937c..00000000 Binary files a/build/huffman.elf and /dev/null differ diff --git a/build/idea.elf b/build/idea.elf deleted file mode 100644 index 7609a5a5..00000000 Binary files a/build/idea.elf and /dev/null differ diff --git a/build/lena.elf b/build/lena.elf deleted file mode 100644 index e41e506e..00000000 Binary files a/build/lena.elf and /dev/null differ diff --git a/build/line.elf b/build/line.elf deleted file mode 100644 index 851b1376..00000000 Binary files a/build/line.elf and /dev/null differ diff --git a/build/maj2random.elf b/build/maj2random.elf deleted file mode 100644 index fae6c1aa..00000000 Binary files a/build/maj2random.elf and /dev/null differ diff --git a/build/mandelbrot.elf b/build/mandelbrot.elf deleted file mode 100644 index 6a847286..00000000 Binary files a/build/mandelbrot.elf and /dev/null differ diff --git a/build/miniz.elf b/build/miniz.elf deleted file mode 100644 index 2cc3e8df..00000000 Binary files a/build/miniz.elf and /dev/null differ diff --git a/build/nqueens.elf b/build/nqueens.elf deleted file mode 100644 index fdbfc31d..00000000 Binary files a/build/nqueens.elf and /dev/null differ diff --git a/build/numeric_sort.elf b/build/numeric_sort.elf deleted file mode 100644 index e6fda6ac..00000000 Binary files a/build/numeric_sort.elf and /dev/null differ diff --git a/build/nyancat.elf b/build/nyancat.elf deleted file mode 100644 index 5e4e346d..00000000 Binary files a/build/nyancat.elf and /dev/null differ diff --git a/build/pi.elf b/build/pi.elf deleted file mode 100644 index f1f29f7f..00000000 Binary files a/build/pi.elf and /dev/null differ diff --git a/build/primes.elf b/build/primes.elf deleted file mode 100644 index e474b49d..00000000 Binary files a/build/primes.elf and /dev/null differ diff --git a/build/puzzle.elf b/build/puzzle.elf deleted file mode 100644 index 1111f7a7..00000000 Binary files a/build/puzzle.elf and /dev/null differ diff --git a/build/qrcode.elf b/build/qrcode.elf deleted file mode 100644 index 4f80e504..00000000 Binary files a/build/qrcode.elf and /dev/null differ diff --git a/build/qsort.elf b/build/qsort.elf deleted file mode 100644 index 9432d445..00000000 Binary files a/build/qsort.elf and /dev/null differ diff --git a/build/richards.elf b/build/richards.elf deleted file mode 100644 index 3cdf4594..00000000 Binary files a/build/richards.elf and /dev/null differ diff --git a/build/rvsim.elf b/build/rvsim.elf deleted file mode 100644 index d2d0b837..00000000 Binary files a/build/rvsim.elf and /dev/null differ diff --git a/build/sha512.elf b/build/sha512.elf deleted file mode 100644 index a999f5ef..00000000 Binary files a/build/sha512.elf and /dev/null differ diff --git a/build/spirograph.elf b/build/spirograph.elf deleted file mode 100644 index 8dd7c915..00000000 Binary files a/build/spirograph.elf and /dev/null differ diff --git a/build/stream.elf b/build/stream.elf deleted file mode 100644 index a5915854..00000000 Binary files a/build/stream.elf and /dev/null differ diff --git a/build/string_sort.elf b/build/string_sort.elf deleted file mode 100644 index 6d551769..00000000 Binary files a/build/string_sort.elf and /dev/null differ diff --git a/docs/prebuilt.md b/docs/prebuilt.md new file mode 100644 index 00000000..f06e28ad --- /dev/null +++ b/docs/prebuilt.md @@ -0,0 +1,67 @@ +# Prebuilt Binaries + +The prebuilt binaries for [rv32emu](https://github.com/sysprog21/rv32emu) are prepared primarily because the [RISC-V Sail Model](https://github.com/riscv/sail-riscv) executable is required for the [RISC-V Architecture Test](https://github.com/riscv-non-isa/riscv-arch-test), and selected RISC-V ELF files are useful for ISA simulation validation and testing. +Some of these prebuilt binaries are stored in [rv32emu-prebuilt](https://github.com/sysprog21/rv32emu-prebuilt). +During testing or benchmarking, these binaries are automatically downloaded into the `build/linux-x86-softfp/` and `build/riscv32/` directories by default. +The RISC-V binaries are compiled using the [xPack RISC-V GCC toolchain](https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack) with the options `-march=rv32im -mabi=ilp32`. +The x86 binaries are compiled by GCC with `-m32 -mno-sse -mno-sse2 -msoft-float` options and use [ieeelib](https://github.com/sysprog21/ieeelib) as the soft-fp library. + +To fetch the prebuilt binaries manually, run: + +```shell +$ make artifact +``` + +Or build the binaries from scratch (the RISC-V cross-compiler is required): + +```shell +$ make artifact ENABLE_PREBUILT=0 [CROSS_COMPILE=] +``` + +The compiler prefix varies according to the used toolchain, such as `riscv-none-elf-`, `riscv32-unknown-elf-`, etc. + +The prebuilt binaries in `rv32emu-prebuilt` are built from the following repositories and resources: + +- [ansibench](https://github.com/sysprog21/ansibench) + - coremark + - stream + - nbench +- [rv8-bench](https://github.com/sysprog21/rv8-bench) + - aes + - dhrystone + - miniz + - norx + - primes + - qsort + - sha512 +- `captcha` : See [tests/captcha.c](/tests/captcha.c) +- `donut` : See [tests/donut.c](/tests/donut.c) +- `fcalc` : See [tests/fcalc.c](/tests/fcalc.c) +- `hamilton` : See [tests/hamilton.c](/tests/hamilton.c) +- `jit` : See [tests/jit.c](/tests/jit.c) +- `lena`: See [tests/lena.c](/tests/lena.c) +- `line` : See [tests/line.c](/tests/line.c) +- `maj2random` : See [tests/maj2random.c](/tests/maj2random.c) +- `mandelbrot` : See [tests/mandelbrot.c](/tests/mandelbrot.c) +- `nqueens` : See [tests/nqueens.c](/tests/nqueens.c) +- `nyancat` : See [tests/nyancat.c](/tests/nyancat.c) +- `pi` : See [tests/pi.c](/tests/pi.c) +- `puzzle` : See [tests/puzzle.c](/tests/puzzle.c) +- `qrcode` : See [tests/qrcode.c](/tests/qrcode.c) +- `richards` : See [tests/richards.c](/tests/richards.c) +- `rvsim` : See [tests/rvsim.c](/tests/rvsim.c) +- `spirograph` : See [tests/spirograph.c](/tests/spirograph.c) +- `uaes` : See [tests/uaes.c](/tests/uaes.c) + +There are still some prebuilt standalone RISC-V binaries under `build/` directory only for testing purpose: + +- `hello.elf` : See [tests/asm-hello](/tests/asm-hello) +- `cc.elf` : See [tests/cc](/tests/cc) +- `chacha20.elf` : See [tests/chacha20](/tests/chacha20) +- `doom.elf` : See [sysprog21/doom_riscv](https://github.com/sysprog21/doom_riscv) [RV32M] +- `ieee754.elf` : See [tests/ieee754.c](/tests/ieee754.c) [RV32F] +- `jit-bf.elf` : See [ezaki-k/xkon_beta](https://github.com/ezaki-k/xkon_beta) +- `quake.elf` : See [sysprog21/quake-embedded](https://github.com/sysprog21/quake-embedded) [RV32F] +- `readelf.elf` : See [tests/readelf](/tests/readelf) +- `scimark2.elf` : See [tests/scimark2](/tests/scimark2) [RV32MF] +- `smolnes.elf` : See [tests/smolnes](/tests/smolnes.c) [RV32M] diff --git a/mk/artifact.mk b/mk/artifact.mk new file mode 100644 index 00000000..543955af --- /dev/null +++ b/mk/artifact.mk @@ -0,0 +1,70 @@ +ENABLE_PREBUILT ?= 1 + +CC ?= gcc +CROSS_COMPILE ?= riscv-none-elf- + +BIN_DIR := $(abspath $(OUT)) + +TEST_SUITES += \ + ansibench \ + rv8-bench + +# "ieee754" needs F extension +# "smolnes", "ticks" have inline assembly and only work in riscv +TEST_BENCHES += \ + captcha \ + donut \ + fcalc \ + hamilton \ + jit \ + lena \ + line \ + maj2random \ + mandelbrot \ + nqueens \ + nyancat \ + pi \ + puzzle \ + qrcode \ + richards \ + rvsim \ + spirograph \ + uaes + +SHELL_HACK := $(shell mkdir -p $(BIN_DIR)/linux-x86-softfp $(BIN_DIR)/riscv32) + +ifeq ($(call has, PREBUILT), 1) + LATEST_RELEASE := $(shell wget -q https://api.github.com/repos/sysprog21/rv32emu-prebuilt/releases/latest -O- | grep '"tag_name"' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/') +else + # Since rv32emu only supports the dynamic binary translation of integer instruction in tiered compilation currently, + # we disable the hardware floating-point and the related SIMD operation of x86. + CFLAGS := -m32 -mno-sse -mno-sse2 -msoft-float -O2 -L$(BIN_DIR) + LDFLAGS := -lsoft-fp -lm + + CFLAGS_CROSS := -march=rv32im -mabi=ilp32 -O2 + LDFLAGS_CROSS := -lm -lsemihost +endif + +.PHONY: artifact + +artifact: +ifeq ($(call has, PREBUILT), 1) + $(Q)$(PRINTF) "Fetching prebuilt executables from \"rv32emu-prebuilt\" ...\n" + $(Q)wget -q --show-progress https://github.com/sysprog21/rv32emu-prebuilt/releases/download/$(LATEST_RELEASE)/rv32emu-prebuilt.tar.gz -O- | tar -C build --strip-components=1 -xz +else + git submodule update --init ./src/ieeelib $(addprefix ./tests/,$(foreach tb,$(TEST_SUITES),$(tb))) + $(Q)$(MAKE) -C ./src/ieeelib CC=$(CC) CFLAGS="$(CFLAGS)" BINDIR=$(BIN_DIR) + $(Q)for tb in $(TEST_SUITES); do \ + CC=$(CC) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" BINDIR=$(BIN_DIR)/linux-x86-softfp $(MAKE) -C ./tests/$$tb; \ + done + $(Q)for tb in $(TEST_SUITES); do \ + CC=$(CROSS_COMPILE)gcc CFLAGS="$(CFLAGS_CROSS)" LDFLAGS="$(LDFLAGS_CROSS)" BINDIR=$(BIN_DIR)/riscv32 $(MAKE) -C ./tests/$$tb; \ + done + $(Q)$(PRINTF) "Building standalone testbenches ...\n" + $(Q)for tb in $(TEST_BENCHES); do \ + $(CC) $(CFLAGS) -Wno-unused-result -o $(BIN_DIR)/linux-x86-softfp/$$tb ./tests/$$tb.c $(LDFLAGS); \ + done + $(Q)for tb in $(TEST_BENCHES); do \ + $(CROSS_COMPILE)gcc $(CFLAGS_CROSS) -o $(BIN_DIR)/riscv32/$$tb ./tests/$$tb.c $(LDFLAGS_CROSS); \ + done +endif diff --git a/mk/external.mk b/mk/external.mk index 704bbfda..202c2589 100644 --- a/mk/external.mk +++ b/mk/external.mk @@ -22,7 +22,7 @@ endef # $(1): compressed source URL define download - $(eval _ := $(shell curl --progress-bar -O -L -C - "$(strip $(1))")) + $(eval _ := $(shell wget -q --show-progress --continue "$(strip $(1))")) endef # $(1): compressed source(.zip or.gz) diff --git a/mk/riscv-arch-test.mk b/mk/riscv-arch-test.mk index ae00765e..bd117c2f 100644 --- a/mk/riscv-arch-test.mk +++ b/mk/riscv-arch-test.mk @@ -9,11 +9,12 @@ ifeq ($(RISCV_DEVICE),FCZicsr) ARCH_TEST_SUITE := tests/rv32fc-test-suite endif -arch-test: $(BIN) +arch-test: $(BIN) artifact ifeq ($(CROSS_COMPILE),) $(error GNU Toolchain for RISC-V is required to build architecture tests. Please check package installation) endif git submodule update --init $(dir $(ARCH_TEST_DIR)) + $(Q)cp $(OUT)/sail_cSim/riscv_sim_RV32 tests/arch-test-target/sail_cSim/riscv_sim_RV32 $(Q)python3 -B $(RISCV_TARGET)/setup.py --riscv_device=$(RISCV_DEVICE) $(Q)riscof run --work-dir=$(WORK) \ --config=$(RISCV_TARGET)/config.ini \ diff --git a/src/ieeelib b/src/ieeelib new file mode 160000 index 00000000..8bd30447 --- /dev/null +++ b/src/ieeelib @@ -0,0 +1 @@ +Subproject commit 8bd3044791e12d196c2af6639312cfbf8b49677c diff --git a/tests/ansibench b/tests/ansibench new file mode 160000 index 00000000..676e97d4 --- /dev/null +++ b/tests/ansibench @@ -0,0 +1 @@ +Subproject commit 676e97d4e14ab1a390f32443691d789a80e48b79 diff --git a/tests/arch-test-target/sail_cSim/riscv_sim_RV32 b/tests/arch-test-target/sail_cSim/riscv_sim_RV32 deleted file mode 100755 index 0b9241ab..00000000 Binary files a/tests/arch-test-target/sail_cSim/riscv_sim_RV32 and /dev/null differ diff --git a/tests/rv8-bench b/tests/rv8-bench new file mode 160000 index 00000000..5bf50214 --- /dev/null +++ b/tests/rv8-bench @@ -0,0 +1 @@ +Subproject commit 5bf5021431f3946b3f8da89aad9635490c3078a0 diff --git a/tests/spirograph.c b/tests/spirograph.c index e11d9cdd..2e409020 100644 --- a/tests/spirograph.c +++ b/tests/spirograph.c @@ -9,6 +9,7 @@ #include #include #include +#include #ifndef GL_FPS #define GL_FPS 30 diff --git a/tests/stream.c b/tests/stream.c deleted file mode 100644 index 54a28990..00000000 --- a/tests/stream.c +++ /dev/null @@ -1,488 +0,0 @@ -/* Program: STREAM */ -/* */ -/* This program measures memory transfer rates in MB/s for simple */ -/* computational kernels coded in C. */ -/*-----------------------------------------------------------------------*/ -/* Copyright 1991-2013: John D. McCalpin */ -/*-----------------------------------------------------------------------*/ -/* License: */ -/* 1. You are free to use this program and/or to redistribute */ -/* this program. */ -/* 2. You are free to modify this program for your own use, */ -/* including commercial use, subject to the publication */ -/* restrictions in item 3. */ -/* 3. You are free to publish results obtained from running this */ -/* program, or from works that you derive from this program, */ -/* with the following limitations: */ -/* 3a. In order to be referred to as "STREAM benchmark results", */ -/* published results must be in conformance to the STREAM */ -/* Run Rules, (briefly reviewed below) published at */ -/* https://www.cs.virginia.edu/stream/ref.html */ -/* and incorporated herein by reference. */ -/* As the copyright holder, John McCalpin retains the */ -/* right to determine conformity with the Run Rules. */ -/* 3b. Results based on modified source code or on runs not in */ -/* accordance with the STREAM Run Rules must be clearly */ -/* labelled whenever they are published. Examples of */ -/* proper labelling include: */ -/* "tuned STREAM benchmark results" */ -/* "based on a variant of the STREAM benchmark code" */ -/* Other comparable, clear, and reasonable labelling is */ -/* acceptable. */ -/* 3c. Submission of results to the STREAM benchmark web site */ -/* is encouraged, but not required. */ -/* 4. Use of this program or creation of derived works based on this */ -/* program constitutes acceptance of these licensing restrictions. */ -/* 5. Absolutely no warranty is expressed or implied. */ -/*-----------------------------------------------------------------------*/ - -#include -#include -#include -#include -#include -#include - -/*----------------------------------------------------------------------- - * INSTRUCTIONS: - * - * 1) STREAM requires different amounts of memory to run on different - * systems, depending on both the system cache size(s) and the - * granularity of the system timer. - * You should adjust the value of 'STREAM_ARRAY_SIZE' (below) - * to meet *both* of the following criteria: - * (a) Each array must be at least 4 times the size of the - * available cache memory. I don't worry about the difference - * between 10^6 and 2^20, so in practice the minimum array size - * is about 3.8 times the cache size. - * Example: One Xeon E3 with 8 MB L3 cache - * STREAM_ARRAY_SIZE should be >= 4 million, giving - * an array size of 30.5 MB and a total memory requirement - * of 91.5 MB. - * (b) The size should be large enough so that the 'timing calibration' - * output by the program is at least 20 clock-ticks. - * Example: most versions of Windows have a 10 millisecond timer - * granularity. 20 "ticks" at 10 ms/tic is 200 milliseconds. - * If the chip is capable of 10 GB/s, it moves 2 GB in 200 msec. - * This means the each array must be at least 1 GB, or 128M - *elements. - * - * Version 5.10 increases the default array size from 2 million - * elements to 10 million elements in response to the increasing - * size of L3 caches. The new default size is large enough for caches - * up to 20 MB. - * Version 5.10 changes the loop index variables from "register int" - * to "ssize_t", which allows array indices >2^32 (4 billion) - * on properly configured 64-bit systems. Additional compiler options - * (such as "-mcmodel=medium") may be required for large memory runs. - * - * Array size can be set at compile time without modifying the source - * code for the (many) compilers that support preprocessor definitions - * on the compile line. E.g., - * gcc -O -DSTREAM_ARRAY_SIZE=100000000 stream.c -o stream.100M - * will override the default size of 10M with a new size of 100M - *elements per array. - */ -#define STREAM_ARRAY_SIZE 10000000 - -/* 2) STREAM runs each kernel "NTIMES" times and reports the *best* result - * for any iteration after the first, therefore the minimum value - * for NTIMES is 2. - * There are no rules on maximum allowable values for NTIMES, but - * values larger than the default are unlikely to noticeably - * increase the reported performance. - * NTIMES can also be set on the compile line without changing the source - * code using, for example, "-DNTIMES=7". - */ -#if defined(NTIMES) && NTIMES <= 1 -#undef NTIMES -#endif -#ifndef NTIMES -#define NTIMES 7 -#endif - -/* Users are allowed to modify the "OFFSET" variable, which *may* change the - * relative alignment of the arrays (though compilers may change the - * effective offset by making the arrays non-contiguous on some - * systems). Use of non-zero values for OFFSET can be especially helpful if the - * STREAM_ARRAY_SIZE is set to a value close to a large power of 2. - * OFFSET can also be set on the compile line without changing the source - * code using, for example, "-DOFFSET=56". - */ -#ifndef OFFSET -#define OFFSET 0 -#endif - -/* - * 3) Compile the code with optimization. Many compilers generate - * unreasonably bad code before the optimizer tightens things up. - * If the results are unreasonably good, on the other hand, the - * optimizer might be too smart for me! - * - * For a simple single-core version, try compiling with: - * cc -O stream.c -o stream - * This is known to work on many, many systems.... - * - * To run with single-precision variables and arithmetic, simply add - * -DSTREAM_TYPE=float - * to the compile line. - * Note that this changes the minimum array sizes required --- see (1) - *above. - * - * 4) Optional: Mail the results to mccalpin@cs.virginia.edu - * Be sure to include info that will help me understand: - * a) the computer hardware configuration (e.g., processor model, memory - *type) b) the compiler name/version and compilation flags c) any run-time - *information (such as OMP_NUM_THREADS) d) all of the output from the test case. - */ - -#define HLINE "-------------------------------------------------------------\n" - -#ifndef MIN -#define MIN(x, y) ((x) < (y) ? (x) : (y)) -#endif -#ifndef MAX -#define MAX(x, y) ((x) > (y) ? (x) : (y)) -#endif - -#ifndef STREAM_TYPE -#define STREAM_TYPE double -#endif -#define ALIGNED_STREAM __attribute__((aligned(32))) - -static STREAM_TYPE a[STREAM_ARRAY_SIZE + OFFSET] ALIGNED_STREAM, - b[STREAM_ARRAY_SIZE + OFFSET] ALIGNED_STREAM, - c[STREAM_ARRAY_SIZE + OFFSET] ALIGNED_STREAM; - -static double avgtime[4] = {0}, maxtime[4] = {0}, - mintime[4] = {FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX}; - -static char *label[4] = { - "Copy: ", "Scale: ", "Add: ", "Triad: "}; - -static double bytes[4] = {2 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE, - 2 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE, - 3 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE, - 3 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE}; - -static double mysecond(); -static void checkSTREAMresults(); - -int main() -{ - int quantum, checktick(); - int BytesPerWord; - int k; - ssize_t j; - STREAM_TYPE scalar; - double t, times[4][NTIMES]; - - /* --- SETUP --- determine precision and check timing --- */ - - printf(HLINE); - printf("STREAM version $Revision: 5.10 $\n"); - printf(HLINE); - BytesPerWord = sizeof(STREAM_TYPE); - printf("This system uses %d bytes per array element.\n", BytesPerWord); - - printf(HLINE); -#ifdef N - printf("***** WARNING: ******\n"); - printf( - " It appears that you set the preprocessor variable N when " - "compiling this code.\n"); - printf( - " This version of the code uses the preprocesor variable " - "STREAM_ARRAY_SIZE to control the array size\n"); - printf(" Reverting to default value of STREAM_ARRAY_SIZE=%llu\n", - (unsigned long long) STREAM_ARRAY_SIZE); - printf("***** WARNING: ******\n"); -#endif - - printf("Array size = %llu (elements), Offset = %d (elements)\n", - (unsigned long long) STREAM_ARRAY_SIZE, OFFSET); - printf( - "Memory per array = %.1f MiB (= %.1f GiB).\n", - BytesPerWord * ((double) STREAM_ARRAY_SIZE / 1024.0 / 1024.0), - BytesPerWord * ((double) STREAM_ARRAY_SIZE / 1024.0 / 1024.0 / 1024.0)); - printf("Total memory required = %.1f MiB (= %.1f GiB).\n", - (3.0 * BytesPerWord) * ((double) STREAM_ARRAY_SIZE / 1024.0 / 1024.), - (3.0 * BytesPerWord) * - ((double) STREAM_ARRAY_SIZE / 1024.0 / 1024. / 1024.)); - printf("Each kernel will be executed %d times.\n", NTIMES); - printf( - " The *best* time for each kernel (excluding the first iteration)\n"); - printf(" will be used to compute the reported bandwidth.\n"); - - /* Get initial value for system clock. */ - for (j = 0; j < STREAM_ARRAY_SIZE; j++) { - a[j] = 1.0; - b[j] = 2.0; - c[j] = 0.0; - } - - printf(HLINE); - - if ((quantum = checktick()) >= 1) - printf( - "Your clock granularity/precision appears to be " - "%d microseconds.\n", - quantum); - else { - printf( - "Your clock granularity appears to be " - "less than one microsecond.\n"); - quantum = 1; - } - - t = mysecond(); - for (j = 0; j < STREAM_ARRAY_SIZE; j++) - a[j] = 2.0E0 * a[j]; - t = 1.0E6 * (mysecond() - t); - - printf( - "Each test below will take on the order" - " of %d microseconds.\n", - (int) t); - printf(" (= %d clock ticks)\n", (int) (t / quantum)); - printf("Increase the size of the arrays if this shows that\n"); - printf("you are not getting at least 20 clock ticks per test.\n"); - - printf(HLINE); - - printf("WARNING -- The above is only a rough guideline.\n"); - printf("For best results, please be sure you know the\n"); - printf("precision of your system timer.\n"); - printf(HLINE); - - /* --- MAIN LOOP --- repeat test cases NTIMES times --- */ - - scalar = 3.0; - for (k = 0; k < NTIMES; k++) { - times[0][k] = mysecond(); - for (j = 0; j < STREAM_ARRAY_SIZE; j++) - c[j] = a[j]; - times[0][k] = mysecond() - times[0][k]; - - times[1][k] = mysecond(); - for (j = 0; j < STREAM_ARRAY_SIZE; j++) - b[j] = scalar * c[j]; - times[1][k] = mysecond() - times[1][k]; - - times[2][k] = mysecond(); - for (j = 0; j < STREAM_ARRAY_SIZE; j++) - c[j] = a[j] + b[j]; - times[2][k] = mysecond() - times[2][k]; - - times[3][k] = mysecond(); - for (j = 0; j < STREAM_ARRAY_SIZE; j++) - a[j] = b[j] + scalar * c[j]; - times[3][k] = mysecond() - times[3][k]; - } - - /* --- SUMMARY --- */ - - for (k = 1; k < NTIMES; k++) /* note -- skip first iteration */ - { - for (j = 0; j < 4; j++) { - avgtime[j] = avgtime[j] + times[j][k]; - mintime[j] = MIN(mintime[j], times[j][k]); - maxtime[j] = MAX(maxtime[j], times[j][k]); - } - } - - printf("Function Best Rate MB/s Avg time Min time Max time\n"); - for (j = 0; j < 4; j++) { - avgtime[j] = avgtime[j] / (double) (NTIMES - 1); - - printf("%s%12.1f %11.6f %11.6f %11.6f\n", label[j], - 1.0E-06 * bytes[j] / mintime[j], avgtime[j], mintime[j], - maxtime[j]); - } - printf(HLINE); - - /* --- Check Results --- */ - checkSTREAMresults(); - printf(HLINE); - - return 0; -} - -#define M 20 - -int checktick() -{ - int i, minDelta, Delta; - double t1, t2, timesfound[M]; - - /* Collect a sequence of M unique time values from the system. */ - - for (i = 0; i < M; i++) { - t1 = mysecond(); - while (((t2 = mysecond()) - t1) < 1.0E-6) - ; - timesfound[i] = t1 = t2; - } - - /* - * Determine the minimum difference between these M values. - * This result will be our estimate (in microseconds) for the - * clock granularity. - */ - - minDelta = 1000000; - for (i = 1; i < M; i++) { - Delta = (int) (1.0E6 * (timesfound[i] - timesfound[i - 1])); - minDelta = MIN(minDelta, MAX(Delta, 0)); - } - - return (minDelta); -} - -/* A gettimeofday routine to give access to the wall clock timer on most - * UNIX-like systems. - */ -#include - -static double mysecond() -{ - struct timeval tp; - struct timezone tzp; - - (void) gettimeofday(&tp, &tzp); - return ((double) tp.tv_sec + (double) tp.tv_usec * 1.e-6); -} - -#ifndef abs -#define abs(a) ((a) >= 0 ? (a) : -(a)) -#endif -static void checkSTREAMresults() -{ - STREAM_TYPE aj, bj, cj, scalar; - STREAM_TYPE aSumErr, bSumErr, cSumErr; - STREAM_TYPE aAvgErr, bAvgErr, cAvgErr; - double epsilon; - ssize_t j; - int k, ierr, err; - - /* reproduce initialization */ - aj = 1.0; - bj = 2.0; - cj = 0.0; - /* a[] is modified during timing check */ - aj = 2.0E0 * aj; - /* now execute timing loop */ - scalar = 3.0; - for (k = 0; k < NTIMES; k++) { - cj = aj; - bj = scalar * cj; - cj = aj + bj; - aj = bj + scalar * cj; - } - - /* accumulate deltas between observed and expected results */ - aSumErr = 0.0; - bSumErr = 0.0; - cSumErr = 0.0; - for (j = 0; j < STREAM_ARRAY_SIZE; j++) { - aSumErr += abs(a[j] - aj); - bSumErr += abs(b[j] - bj); - cSumErr += abs(c[j] - cj); - // if (j == 417) printf("Index 417: c[j]: %f, cj: %f\n",c[j],cj); // - // MCCALPIN - } - aAvgErr = aSumErr / (STREAM_TYPE) STREAM_ARRAY_SIZE; - bAvgErr = bSumErr / (STREAM_TYPE) STREAM_ARRAY_SIZE; - cAvgErr = cSumErr / (STREAM_TYPE) STREAM_ARRAY_SIZE; - - if (sizeof(STREAM_TYPE) == 4) { - epsilon = 1.e-6; - } else if (sizeof(STREAM_TYPE) == 8) { - epsilon = 1.e-13; - } else { - printf("WEIRD: sizeof(STREAM_TYPE) = %u\n", sizeof(STREAM_TYPE)); - epsilon = 1.e-6; - } - - err = 0; - if (abs(aAvgErr / aj) > epsilon) { - err++; - printf("Failed Validation on array a[], AvgRelAbsErr > epsilon (%e)\n", - epsilon); - printf(" Expected Value: %e, AvgAbsErr: %e, AvgRelAbsErr: %e\n", aj, - aAvgErr, abs(aAvgErr) / aj); - ierr = 0; - for (j = 0; j < STREAM_ARRAY_SIZE; j++) { - if (abs(a[j] / aj - 1.0) > epsilon) { - ierr++; -#ifdef VERBOSE - if (ierr < 10) { - printf( - " array a: index: %ld, expected: %e, observed: " - "%e, relative error: %e\n", - j, aj, a[j], abs((aj - a[j]) / aAvgErr)); - } -#endif - } - } - printf(" For array a[], %d errors were found.\n", ierr); - } - if (abs(bAvgErr / bj) > epsilon) { - err++; - printf("Failed Validation on array b[], AvgRelAbsErr > epsilon (%e)\n", - epsilon); - printf(" Expected Value: %e, AvgAbsErr: %e, AvgRelAbsErr: %e\n", bj, - bAvgErr, abs(bAvgErr) / bj); - printf(" AvgRelAbsErr > Epsilon (%e)\n", epsilon); - ierr = 0; - for (j = 0; j < STREAM_ARRAY_SIZE; j++) { - if (abs(b[j] / bj - 1.0) > epsilon) { - ierr++; -#ifdef VERBOSE - if (ierr < 10) { - printf( - " array b: index: %ld, expected: %e, observed: " - "%e, relative error: %e\n", - j, bj, b[j], abs((bj - b[j]) / bAvgErr)); - } -#endif - } - } - printf(" For array b[], %d errors were found.\n", ierr); - } - if (abs(cAvgErr / cj) > epsilon) { - err++; - printf("Failed Validation on array c[], AvgRelAbsErr > epsilon (%e)\n", - epsilon); - printf(" Expected Value: %e, AvgAbsErr: %e, AvgRelAbsErr: %e\n", cj, - cAvgErr, abs(cAvgErr) / cj); - printf(" AvgRelAbsErr > Epsilon (%e)\n", epsilon); - ierr = 0; - for (j = 0; j < STREAM_ARRAY_SIZE; j++) { - if (abs(c[j] / cj - 1.0) > epsilon) { - ierr++; -#ifdef VERBOSE - if (ierr < 10) { - printf( - " array c: index: %ld, expected: %e, observed: " - "%e, relative error: %e\n", - j, cj, c[j], abs((cj - c[j]) / cAvgErr)); - } -#endif - } - } - printf(" For array c[], %d errors were found.\n", ierr); - } - if (err == 0) { - printf( - "Solution Validates: avg error less than %e on all three arrays\n", - epsilon); - } -#ifdef VERBOSE - printf("Results Validation Verbose Results: \n"); - printf(" Expected a(1), b(1), c(1): %f %f %f \n", aj, bj, cj); - printf(" Observed a(1), b(1), c(1): %f %f %f \n", a[1], b[1], c[1]); - printf(" Rel Errors on a, b, c: %e %e %e \n", abs(aAvgErr / aj), - abs(bAvgErr / bj), abs(cAvgErr / cj)); -#endif -} diff --git a/tests/aes.c b/tests/uaes.c similarity index 100% rename from tests/aes.c rename to tests/uaes.c