├── examples ├── build-rust │ ├── .gitignore │ ├── README.md │ ├── Makefile │ └── test.rs ├── build-c │ ├── test.c │ ├── .gitignore │ ├── README.md │ └── Makefile ├── test-code-c │ ├── README.md │ ├── Makefile │ ├── .devcontainer │ │ └── devcontainer.json │ ├── CMakePresets.json │ ├── timer.h │ ├── CMakeLists.txt │ ├── main.c │ ├── timer.c │ ├── riscv-interrupts.h │ ├── startup.c │ ├── riscv.cmake │ └── linker.lds ├── build-run-sim │ ├── README.md │ ├── test-decode.sh │ ├── test.gtkw │ └── Makefile ├── Makefile └── README.md ├── docker ├── riscv-spike-debug-sim │ ├── .gitignore │ ├── Makefile │ ├── riscv_spike.cfg │ ├── Makefile.vcd_spike │ ├── Dockerfile │ ├── README.md │ ├── sim_helpers.sh │ └── sim_entrypoint.sh ├── riscv-spike-debug-gdb │ ├── .gitignore │ ├── Makefile │ ├── Makefile.vcd_spike │ ├── README.md │ ├── Dockerfile │ └── entrypoint_gdb.sh ├── riscv-tool-build │ ├── Makefile │ ├── README.md │ └── Dockerfile ├── riscv-rust │ ├── Makefile │ ├── README.md │ └── Dockerfile ├── riscv-openocd │ ├── Makefile │ ├── riscv_spike.cfg │ ├── compose.yaml │ ├── README.md │ └── Dockerfile ├── riscv-spike │ ├── Makefile │ ├── Makefile.vcd_spike │ ├── README.md │ └── Dockerfile ├── riscv-gnu-toolchain │ ├── Makefile │ ├── README.md │ └── Dockerfile ├── riscv-xpack-gcc │ ├── Makefile │ ├── README.md │ └── Dockerfile ├── Makefile ├── riscv-gtkwave │ ├── Makefile │ ├── README.md │ └── Dockerfile ├── README.md ├── riscv-gnu-toolchain-2 │ ├── README.md │ ├── compose.yaml │ ├── docker_build │ │ └── Dockerfile │ └── Makefile ├── common.mak └── targets.mak ├── .gitmodules ├── .gitignore ├── LICENSE └── README.md /examples/build-rust/.gitignore: -------------------------------------------------------------------------------- 1 | test.elf 2 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-sim/.gitignore: -------------------------------------------------------------------------------- 1 | riscv_spike.cfg 2 | -------------------------------------------------------------------------------- /examples/build-c/test.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } 4 | -------------------------------------------------------------------------------- /examples/build-c/.gitignore: -------------------------------------------------------------------------------- 1 | host_out 2 | riscv-none-embed_out 3 | -------------------------------------------------------------------------------- /examples/test-code-c/README.md: -------------------------------------------------------------------------------- 1 | Example code for ../build-run-sim. 2 | -------------------------------------------------------------------------------- /examples/test-code-c/Makefile: -------------------------------------------------------------------------------- 1 | all : 2 | 3 | clean : 4 | rm -rf build 5 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-gdb/.gitignore: -------------------------------------------------------------------------------- 1 | riscv_spike.cfg 2 | sim_helpers.sh 3 | 4 | -------------------------------------------------------------------------------- /examples/build-run-sim/README.md: -------------------------------------------------------------------------------- 1 | Build a complete program and ensure it can run in spike. 2 | -------------------------------------------------------------------------------- /examples/build-rust/README.md: -------------------------------------------------------------------------------- 1 | Build a baremetal rust program for riscv32imac using fiveembeddev/riscv_rustup_dev_env docker container. 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "_export/build-and-verify"] 2 | path = _export/build-and-verify 3 | url = git@github.com:five-embeddev/build-and-verify.git 4 | -------------------------------------------------------------------------------- /docker/riscv-tool-build/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | IMAGE_NAME=build_env 3 | 4 | all : docker-build-build_env 5 | 6 | include ../targets.mak 7 | 8 | -------------------------------------------------------------------------------- /examples/build-c/README.md: -------------------------------------------------------------------------------- 1 | Examples on building for the host and target via docker. 2 | 3 | Depends on the docker images build in the 4 | ../../docker directory. Those should be built first. 5 | -------------------------------------------------------------------------------- /docker/riscv-rust/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | 3 | IMAGE_NAME=riscv_rustup_dev_env 4 | COMPOSE_TARGET=build_env 5 | RELEASE_TAG:=${RELEASE_TAG} 6 | 7 | all : docker-build-${IMAGE_NAME} 8 | 9 | include ../targets.mak 10 | -------------------------------------------------------------------------------- /examples/test-code-c/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "RISC-V Dev", 3 | "image": "fiveembeddev/riscv_xpack_gcc_dev_env:latest", 4 | "customizations": { 5 | "vscode": { 6 | "extensions": ["cmake"] 7 | } 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | DIRS=\ 2 | build-c \ 3 | build-rust \ 4 | test-code-c \ 5 | build-run-sim 6 | 7 | build : ${DIRS:%=build.%} 8 | echo ${DIRS} 9 | 10 | build.% : 11 | ${MAKE} -C ${*} all 12 | 13 | clean : ${DIRS:%=clean.%} 14 | echo ${DIRS} 15 | 16 | clean.% : 17 | ${MAKE} -C ${*} clean 18 | -------------------------------------------------------------------------------- /examples/build-run-sim/test-decode.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "DECODE_ELF=${DECODE_ELF}" 4 | grep 0x build/main.map | \ 5 | perl -p -e 's/^.*(0x[0-9A-Fa-f]{8,16}).*$/$1/' | \ 6 | cut -f1 -d' ' | \ 7 | sort -u > test.addr 8 | cat test.addr 9 | /opt/riscv-gtkwave/bin/decode_addr < test.addr 10 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-sim/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | 3 | IMAGE_NAME=riscv_spike_debug_sim 4 | RELEASE_TAG:=${RELEASE_TAG}_spike_${SPIKE_TAG} 5 | 6 | all : docker-build-${IMAGE_NAME} 7 | 8 | docker-build-${IMAGE_NAME} : riscv-spike riscv-openocd riscv_spike.cfg 9 | 10 | include ../targets.mak 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/test-code-c/CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurePresets": [ 3 | { 4 | "name": "RISC-V Build", 5 | "displayName": "RISC-V Build Preset", 6 | "binaryDir": "${sourceDir}/build/default", 7 | "generator": "Makefile", 8 | "toolchainFile": "riscv.cmake" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /examples/build-rust/Makefile: -------------------------------------------------------------------------------- 1 | all : test.elf 2 | 3 | test.elf : test.rs 4 | docker run \ 5 | --rm \ 6 | -v .:/project \ 7 | fiveembeddev/riscv_rustup_dev_env:latest \ 8 | rustc \ 9 | --target riscv32imac-unknown-none-elf \ 10 | /project/test.rs \ 11 | -o test.elf 12 | 13 | 14 | clean : 15 | rm -f test.elf 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docker/riscv-gnu-toolchain-2/docker_build/install_dir/ 2 | examples/build-run-sim/build/ 3 | CMakeLists.txt.user 4 | CMakeCache.txt 5 | CMakeFiles 6 | CMakeScripts 7 | Testing 8 | cmake_install.cmake 9 | install_manifest.txt 10 | compile_commands.json 11 | CTestTestfile.cmake 12 | _deps 13 | 14 | *~ 15 | 16 | **/build/* 17 | *.log 18 | *# 19 | .#* 20 | -------------------------------------------------------------------------------- /docker/riscv-openocd/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | 3 | IMAGE_NAME=riscv_openocd_base 4 | 5 | # Override to choose spike fork 6 | RELEASE_TAG:=${RELEASE_TAG}_openocd_${OPENOCD_TAG} 7 | 8 | DOCKER_BUILD_ARGS += \ 9 | OPENOCD_TAG=${OPENOCD_TAG} \ 10 | 11 | all : docker-build-${IMAGE_NAME} 12 | 13 | docker-build-${IMAGE_NAME} : riscv-tool-build 14 | 15 | include ../targets.mak 16 | -------------------------------------------------------------------------------- /docker/riscv-openocd/riscv_spike.cfg: -------------------------------------------------------------------------------- 1 | adapter driver remote_bitbang 2 | remote_bitbang host localhost 3 | remote_bitbang port 9824 4 | 5 | set _CHIPNAME riscv 6 | jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 7 | 8 | set _TARGETNAME $_CHIPNAME.cpu 9 | target create $_TARGETNAME riscv -chain-position $_TARGETNAME 10 | 11 | gdb_report_data_abort enable 12 | 13 | bindto 0.0.0.0 14 | 15 | init 16 | halt 17 | 18 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-gdb/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | 3 | IMAGE_NAME=riscv_spike_debug_gdb 4 | RELEASE_TAG:=${RELEASE_TAG}_spike_${SPIKE_TAG} 5 | 6 | all : docker-build-${IMAGE_NAME} 7 | 8 | .PHONY: docker-build-${IMAGE_NAME} 9 | docker-build-${IMAGE_NAME} : \ 10 | riscv_spike.cfg \ 11 | sim_helpers.sh \ 12 | riscv-spike \ 13 | riscv-openocd \ 14 | riscv-xpack-gcc 15 | 16 | include ../targets.mak 17 | 18 | 19 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-sim/riscv_spike.cfg: -------------------------------------------------------------------------------- 1 | adapter driver remote_bitbang 2 | remote_bitbang host localhost 3 | remote_bitbang port 9824 4 | 5 | set _CHIPNAME riscv 6 | jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 7 | 8 | set _TARGETNAME $_CHIPNAME.cpu 9 | target create $_TARGETNAME riscv -chain-position $_TARGETNAME 10 | 11 | gdb_report_data_abort enable 12 | 13 | bindto 0.0.0.0 14 | 15 | init 16 | halt 17 | 18 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples of using docker 2 | 3 | | Example | Description | 4 | |-----------------------|-------------| 5 | | build-c/ | Build a simple C test program for host and target | 6 | | build-rust/ | Build a small rust program | 7 | | build-run-sim/ | Build a full baremetal example and simulate with Spike, debug with GDB | 8 | | test-code-c/ | Small example program | 9 | 10 | -------------------------------------------------------------------------------- /docker/riscv-spike/Makefile: -------------------------------------------------------------------------------- 1 | # -*- Makefile -*- 2 | include ../common.mak 3 | 4 | IMAGE_NAME=riscv_spike_dev_env 5 | COMPOSE_TARGET=riscv_spike 6 | 7 | # Override to choose spike fork 8 | RELEASE_TAG:=${RELEASE_TAG}_spike_${SPIKE_TAG} 9 | 10 | DOCKER_BUILD_ARGS += \ 11 | SPIKE_TAG=${SPIKE_TAG} \ 12 | SPIKE_URL=${SPIKE_URL} 13 | 14 | all : docker-build-${IMAGE_NAME} 15 | 16 | docker-build-${IMAGE_NAME} : riscv-tool-build 17 | 18 | include ../targets.mak 19 | 20 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-sim/Makefile.vcd_spike: -------------------------------------------------------------------------------- 1 | # -*- Makefile -*- 2 | include ../common.mak 3 | 4 | SPIKE_IMAGE_NAME=forked_riscv_spike_dev_env 5 | IMAGE_NAME=forked_riscv_spike_debug_sim 6 | RELEASE_TAG:=${RELEASE_TAG}_spike_${SPIKE_TAG} 7 | 8 | DOCKER_BUILD_ARGS += \ 9 | SPIKE_IMAGE_NAME=${SPIKE_IMAGE_NAME} 10 | 11 | all : docker-build-${IMAGE_NAME} 12 | 13 | docker-build-${IMAGE_NAME} : riscv-spike-vcd riscv-openocd riscv_spike.cfg 14 | 15 | include ../targets.mak 16 | 17 | 18 | -------------------------------------------------------------------------------- /docker/riscv-gnu-toolchain/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | 3 | IMAGE_NAME=riscv_gnu_toolchain_dev_env 4 | 5 | # Override to choose spike fork 6 | RELEASE_TAG:=${RELEASE_TAG}_gcc_${GCC_TAG} 7 | 8 | DOCKER_BUILD_ARGS += \ 9 | GNU_TOOLCHAIN_TAG=${GNU_TOOLCHAIN_TAG} \ 10 | GCC_TAG=${GCC_TAG} \ 11 | RISCV_MARCH=${RISCV_MARCH} \ 12 | RISCV_ABI=${RISCV_ABI} 13 | 14 | all : docker-build-${IMAGE_NAME} 15 | 16 | docker-build-${IMAGE_NAME} : riscv-tool-build 17 | 18 | include ../targets.mak 19 | -------------------------------------------------------------------------------- /docker/riscv-openocd/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | riscv_openocd: 3 | build: 4 | context : . 5 | target: riscv_openocd_base 6 | image: fiveembeddev/riscv_openocd 7 | ports: 8 | - "9824:9824" 9 | - "4000:4000" 10 | - "6000:6000" 11 | - "3000:3000" 12 | command: ["openocd", "--version"] 13 | 14 | riscv_openocd_shell: 15 | image: fiveembeddev/riscv_openocd 16 | command: bash 17 | tty: true 18 | stdin_open: true 19 | -------------------------------------------------------------------------------- /docker/riscv-xpack-gcc/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | 3 | IMAGE_NAME=riscv_xpack_gcc_dev_env 4 | COMPOSE_TARGET=build_env 5 | 6 | #XPACK_GCC_VERSION=10.1.0-1.1.1 7 | XPACK_GCC_VERSION=12.2.0-3.1 8 | NODE_VERSION=16.16.0 9 | NVM_VERSION=v0.38.0 10 | 11 | RELEASE_TAG:=${RELEASE_TAG}_gcc_${XPACK_GCC_VERSION} 12 | 13 | DOCKER_BUILD_ARGS += \ 14 | XPACK_GCC_VERSION=${XPACK_GCC_VERSION} \ 15 | NODE_VERSION=${NODE_VERSION} \ 16 | NVM_VERSION=${NVM_VERSION} 17 | 18 | all : docker-build-${IMAGE_NAME} 19 | 20 | include ../targets.mak 21 | -------------------------------------------------------------------------------- /examples/build-rust/test.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use core::panic::PanicInfo; 5 | 6 | //fn main() { 7 | // // Statements here are executed when the compiled binary is called 8 | // 9 | // // Print text to the console 10 | // // println!("Hello World!"); 11 | //} 12 | 13 | // error: `#[panic_handler]` function required, but not found 14 | #[panic_handler] 15 | fn panic(_info: &PanicInfo) -> ! { 16 | 17 | loop {} 18 | } 19 | 20 | #[no_mangle] 21 | pub extern "C" fn _start() -> ! { 22 | loop {} 23 | } 24 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-gdb/Makefile.vcd_spike: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | 3 | SPIKE_IMAGE_NAME=forked_riscv_spike_dev_env 4 | IMAGE_NAME=forked_riscv_spike_debug_gdb 5 | RELEASE_TAG:=${RELEASE_TAG}_spike_${SPIKE_TAG} 6 | 7 | DOCKER_BUILD_ARGS += \ 8 | SPIKE_IMAGE_NAME=${SPIKE_IMAGE_NAME} 9 | 10 | all : docker-build-${IMAGE_NAME} 11 | 12 | .PHONY: docker-build-${IMAGE_NAME} 13 | docker-build-${IMAGE_NAME} : \ 14 | riscv_spike.cfg \ 15 | sim_helpers.sh \ 16 | riscv-spike-vcd \ 17 | riscv-openocd \ 18 | riscv-xpack-gcc 19 | 20 | include ../targets.mak 21 | 22 | 23 | -------------------------------------------------------------------------------- /docker/riscv-spike/Makefile.vcd_spike: -------------------------------------------------------------------------------- 1 | # -*- Makefile -*- 2 | include ../common.mak 3 | 4 | IMAGE_NAME=forked_riscv_spike_dev_env 5 | COMPOSE_TARGET=riscv_spike 6 | 7 | # Override to choose spike fork 8 | SPIKE_TAG=vcd_trace_20241109 9 | SPIKE_URL=https://github.com/five-embeddev/riscv-isa-sim.git 10 | RELEASE_TAG:=${RELEASE_TAG}_spike_${SPIKE_TAG} 11 | 12 | DOCKER_BUILD_ARGS += \ 13 | SPIKE_TAG=${SPIKE_TAG} \ 14 | SPIKE_URL=${SPIKE_URL} 15 | 16 | all : docker-build-${IMAGE_NAME} 17 | 18 | docker-build-${IMAGE_NAME} : riscv-tool-build 19 | 20 | include ../targets.mak 21 | 22 | -------------------------------------------------------------------------------- /docker/Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: build push 3 | build push : 4 | ${MAKE} -C riscv-tool-build/ $@ 5 | ${MAKE} -C riscv-spike/ $@ 6 | ${MAKE} -C riscv-spike/ -f Makefile.vcd_spike $@ 7 | ${MAKE} -C riscv-openocd/ $@ 8 | ${MAKE} -C riscv-xpack-gcc/ $@ 9 | ${MAKE} -C riscv-spike-debug-sim/ $@ 10 | ${MAKE} -C riscv-spike-debug-sim/ -f Makefile.vcd_spike $@ 11 | ${MAKE} -C riscv-spike-debug-gdb/ $@ 12 | ${MAKE} -C riscv-spike-debug-gdb/ -f Makefile.vcd_spike $@ 13 | ${MAKE} -C riscv-rust/ $@ 14 | 15 | .PHONY: login 16 | login : 17 | docker login \ 18 | -u fiveembeddev 19 | 20 | 21 | -------------------------------------------------------------------------------- /docker/riscv-gtkwave/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mak 2 | 3 | IMAGE_NAME=riscv_gtkwave_base 4 | 5 | RISCV_GTKWAVE_TAG=docker_build_9da3e8c8a6 6 | RISCV_GTKWAVE_URL=https://github.com/five-embeddev/riscv-gtkwave.git 7 | 8 | # Override to choose spike fork 9 | RELEASE_TAG:=${RELEASE_TAG}_decoders_${RISCV_GTKWAVE_TAG} 10 | 11 | DOCKER_BUILD_ARGS += \ 12 | RISCV_GTKWAVE_TAG=${RISCV_GTKWAVE_TAG} \ 13 | RISCV_GTKWAVE_URL=${RISCV_GTKWAVE_URL} 14 | 15 | DOCKER_RUN_ARGS += \ 16 | -v /tmp/.X11-unix:/tmp/.X11-unix \ 17 | -e DISPLAY=${DISPLAY} 18 | 19 | DOCKER_RUN_SHELL=gtkwave 20 | 21 | all : docker-build-${IMAGE_NAME} 22 | 23 | docker-build-${IMAGE_NAME} : riscv-tool-build 24 | 25 | include ../targets.mak 26 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-sim/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG SPIKE_IMAGE_NAME=riscv_spike_dev_env 2 | FROM fiveembeddev/${SPIKE_IMAGE_NAME}:latest AS riscv_spike_debug_sim 3 | 4 | WORKDIR /project/ 5 | 6 | # Merge in openocd 7 | COPY --from=fiveembeddev/riscv_openocd_base:latest \ 8 | /opt/riscv-openocd/ \ 9 | /opt/riscv-openocd/ 10 | 11 | RUN sudo apt-get update -qq && sudo apt-get install -y ncat 12 | ENV PATH=/opt/riscv-openocd/bin:/opt/riscv-isa-sim/bin:/bin:/usr/bin:/usr/local/bin 13 | 14 | COPY riscv_spike.cfg /opt/ 15 | COPY sim_helpers.sh /opt/ 16 | COPY sim_entrypoint.sh /opt/ 17 | RUN sudo chmod +x /opt/sim_entrypoint.sh 18 | 19 | ENV RISCV_ISA=rv32imac 20 | ENV RISCV_PRIV=m 21 | ENV BOARD_MEM=0x8000000:0x2000,0x80000000:0x4000,0x20010000:0x6a120 22 | ENV START_PC=0x20010000 23 | 24 | ENTRYPOINT ["/opt/sim_entrypoint.sh"] 25 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Docker for emebdded RISC-V development. 2 | 3 | | Target | Description | 4 | |-----------------------|-------------| 5 | | riscv-tool-build | Base image for compiling tools| 6 | | riscv-spike | RISC-V ISA Simulator. | 7 | | riscv-openocd | OpenOCD JTAG debugger interface| 8 | | riscv-xpack-gcc | X-PACK packaged GCC | 9 | | riscv-spike-debug-sim | RISC-V Spike ISA configured to run with OpenOCD| 10 | | riscv-spike-debug-gdb | RISC-V Spike ISA configured to run with OpenOCD & GDB| 11 | | riscv-rust | Rust for RISC-V | 12 | | riscv-gnu-toolchain | Build GCC for RISC-V | 13 | | riscv-gnu-toolchain-2 | Build GCC for RISC-V (using docker compose to conserve resources) | 14 | 15 | Each Docker environment is configured to run with a `docker_user` account and user `/project/` as the working directory. 16 | 17 | 18 | -------------------------------------------------------------------------------- /docker/riscv-gnu-toolchain-2/README.md: -------------------------------------------------------------------------------- 1 | # GNU Toolchain compiled from source 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/riscv_gnu_toolchain_dev_env2:latest`| 6 | |*User* | `docker_user`| 7 | |*Home Dir*| `/home/docker_user`| 8 | |*Workdir*| `/project`| 9 | |*Tool Path*| `/opt/riscv-toolchain/`| 10 | 11 | 12 | Clone the https://github.com/riscv-collab/riscv-gnu-toolchain repo and 13 | build the toolchain in this folder. The build files will be copied 14 | into a docker container. 15 | 16 | NOTE - The Makefile in this directory is not for convinence, it must 17 | be used to build the image. 18 | 19 | The final `fiveembeddev/riscv_gnu_toolchain_dev_env2` image will have 20 | the `riscv32-unknown-elf-` toolchain on the path. 21 | 22 | NOTE - The tool build requires 5GB+ of disk space. 23 | 24 | -------------------------------------------------------------------------------- /docker/riscv-gnu-toolchain-2/compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | 4 | build_env: 5 | build: 6 | context: ../riscv-tool-build/ 7 | dockerfile: Dockerfile 8 | target: riscv_tools_build_env 9 | image: fiveembeddev/build_env 10 | volumes: 11 | - ./build_dir:/project/build_dir 12 | - ./docker_build/install_dir:/opt/riscv-gnu-toolchain 13 | 14 | dev_env: 15 | build: 16 | context: docker_build/ 17 | dockerfile: Dockerfile 18 | target: riscv_gnu_toolchain_dev_env2 19 | args: 20 | DOCKER_USER_UID: 1000 21 | image: fiveembeddev/riscv_gnu_toolchain_dev_env2 22 | command: ["riscv32-unknown-elf-gcc", "--version"] 23 | 24 | shell: 25 | image: fiveembeddev/riscv_gnu_toolchain_dev_env2 26 | stdin_open: true # docker run -i 27 | tty: true # docker run -t 28 | command: ["bash"] 29 | 30 | -------------------------------------------------------------------------------- /examples/build-c/Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_CMD= docker run \ 2 | --rm \ 3 | -v .:/project \ 4 | 5 | 6 | all : host_out riscv-none-embed_out riscv32-unknown-elf_out 7 | 8 | host : host_out 9 | 10 | gnu_toolchain : riscv32-unknown-elf_out 11 | 12 | xpack : riscv-none-embed_out 13 | 14 | host_out : test.c 15 | ${DOCKER_CMD} \ 16 | fiveembeddev/build_env \ 17 | gcc test.c -o host_out \ 18 | 19 | riscv-none-embed_out : test.c 20 | ${DOCKER_CMD} \ 21 | fiveembeddev/riscv_xpack_gcc_dev_env:latest \ 22 | riscv-none-elf-gcc \ 23 | test.c \ 24 | -nostartfiles \ 25 | -o riscv-none-embed_out 26 | 27 | 28 | riscv32-unknown-elf_out : test.c 29 | ${DOCKER_CMD} \ 30 | fiveembeddev/riscv_gnu_toolchain_dev_env2:latest \ 31 | riscv32-unknown-elf-gcc \ 32 | test.c \ 33 | -o riscv32-unknown-elf_out 34 | 35 | clean : 36 | rm -f riscv32-unknown-elf_out riscv-none-embed_out 37 | -------------------------------------------------------------------------------- /docker/riscv-rust/README.md: -------------------------------------------------------------------------------- 1 | # Docker environment for running Rust for cross compilation for RISC-V. 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/riscv_rustup_dev_env:latest`| 6 | |*User*| `docker_user`| 7 | |*Home Dir*| `/home/docker_user`| 8 | |*Workdir*| `/project`| 9 | |*Tool Path*| `/home/docker_user/.cargo`| 10 | 11 | 12 | The compile is installed using rustup 13 | 14 | RISC-V was a tier-2 platform when this was `Dockerfile` developed. () 15 | 16 | More info about rust for embedded targets . 17 | 18 | ```bash 19 | docker run \ 20 | --tty \ 21 | --interactive \ 22 | --rm \ 23 | -v .:/project \ 24 | fiveembeddev/riscv_rustup_dev_env:latest \ 25 | rustc --version 26 | ``` 27 | -------------------------------------------------------------------------------- /docker/common.mak: -------------------------------------------------------------------------------- 1 | DOCKER=docker 2 | DOCKER_COMPOSE=${DOCKER} compose 3 | DOCKER_USER_UID:=$(shell id -u) 4 | DOCKER_USER_GID:=$(shell id -g) 5 | 6 | BASE_IMAGE=ubuntu:jammy 7 | 8 | DOCKER_REPO= 9 | DOCKER_USER=fiveembeddev 10 | 11 | RELEASE_VERSION=0.2.0 12 | RELEASE_LABEL=env_${RELEASE_VERSION} 13 | BUILD_TAG=${DOCKER_USER}/${IMAGE_NAME}:latest 14 | RELEASE_TAG=${DOCKER_USER}/${IMAGE_NAME}:${RELEASE_LABEL} 15 | 16 | DOCKER_BUILD_ARGS=\ 17 | DOCKER_USER_UID=${DOCKER_USER_UID} \ 18 | BASE_IMAGE=${BASE_IMAGE} 19 | 20 | #NO_CACHE=--no-cache 21 | NO_CACHE= 22 | # Show cache 23 | #export DOCKER_BUILDKIT=0 24 | 25 | # Versions 26 | SPIKE_TAG=v1.1.0 27 | SPIKE_URL=https://github.com/riscv-software-src/riscv-isa-sim.git 28 | #GNU_TOOLCHAIN_TAG=2022.03.09 29 | GNU_TOOLCHAIN_TAG=2025.05.30 30 | GCC_TAG=riscv-gcc-10.2.0 31 | 32 | # Default arch 33 | RISCV_MARCH=rv32imac 34 | RISCV_ABI=ilp32 35 | 36 | OPENOCD_TAG=riscv 37 | 38 | DOCKER_RUN_SHELL=/bin/bash 39 | -------------------------------------------------------------------------------- /docker/riscv-gnu-toolchain-2/docker_build/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG DOCKER_USER_UID=1000 2 | 3 | # ------------------------------------------------------------------------ 4 | # Lightwieght container with only tools, no source 5 | ARG BASE_IMAGE=ubuntu:jammy 6 | FROM ${BASE_IMAGE} AS riscv_gnu_toolchain_dev_env2 7 | 8 | ARG DOCKER_USER_UID 9 | ARG TZ 10 | 11 | ENV INSTALL_PATH=/opt/riscv-toolchain/ 12 | 13 | # Basic OS update 14 | RUN apt-get update -qq 15 | RUN apt-get install -y sudo 16 | 17 | # Setup user 18 | RUN useradd \ 19 | -u ${DOCKER_USER_UID} \ 20 | -m \ 21 | -r \ 22 | -G sudo -s /sbin/nologin \ 23 | -c "Docker image user" \ 24 | docker_user 25 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 26 | USER docker_user 27 | 28 | COPY install_dir ${INSTALL_PATH} 29 | 30 | RUN sudo apt-get install -y libmpc3 31 | 32 | ENV PATH=${INSTALL_PATH}bin:/bin:/usr/bin:/usr/local/bin 33 | 34 | RUN sudo mkdir /project && sudo chown docker_user /project 35 | WORKDIR /project 36 | -------------------------------------------------------------------------------- /examples/build-run-sim/test.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Sat Jun 15 14:41:00 2024 4 | [*] 5 | [dumpfile] "/project/test.vcd" 6 | [dumpfile_mtime] "Sat Jun 15 14:22:49 2024" 7 | [dumpfile_size] 6360 8 | [savefile] "/project/test.gtkw" 9 | [timestart] 1023 10 | [size] 1182 591 11 | [pos] -1 -1 12 | *0.000000 2 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] riscv_isa_sim. 14 | [treeopen] riscv_isa_sim.core0. 15 | [sst_width] 214 16 | [signals_width] 134 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 149 19 | @4022 20 | ^>1 /opt/riscv-gtkwave/bin/decode_inst 21 | riscv_isa_sim.core0.processor.insn[63:0] 22 | @22 23 | riscv_isa_sim.core0.processor.jump_pc[63:0] 24 | riscv_isa_sim.core0.processor.pc[63:0] 25 | @4022 26 | ^>2 /opt/riscv-gtkwave/bin/decode_addr 27 | riscv_isa_sim.core0.processor.jump_pc[63:0] 28 | @4023 29 | ^>2 /opt/riscv-gtkwave/bin/decode_addr 30 | riscv_isa_sim.core0.processor.pc[63:0] 31 | [pattern_trace] 1 32 | [pattern_trace] 0 33 | -------------------------------------------------------------------------------- /docker/riscv-xpack-gcc/README.md: -------------------------------------------------------------------------------- 1 | # XPack RISC-V GCC package 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/riscv_xpack_gcc_dev_env:latest`| 6 | |*User* | `docker_user`| 7 | |*Home Dir*| `/home/docker_user`| 8 | |*Workdir*| `/project`| 9 | |*Tool Path*| `/home/docker_user/.xpack/repos/@xpack-dev-tools/`| 10 | |*Tool Path*| `/opt/riscv-none-embed` | 11 | 12 | Docker environment for running the xpack riscv-none-elf-gcc release. 13 | 14 | https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases 15 | 16 | ```bash 17 | docker run \ 18 | --tty \ 19 | --interactive \ 20 | --rm \ 21 | -v .:/project \ 22 | fiveembeddev/riscv_xpack_gcc_dev_env:latest \ 23 | riscv-none-elf-gcc --version 24 | ``` 25 | 26 | ``` 27 | riscv-none-elf-gcc (xPack GNU RISC-V Embedded GCC x86_64) 12.2.0 28 | Copyright (C) 2022 Free Software Foundation, Inc. 29 | This is free software; see the source for copying conditions. There is NO 30 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 31 | ``` 32 | -------------------------------------------------------------------------------- /docker/riscv-gnu-toolchain/README.md: -------------------------------------------------------------------------------- 1 | # GNU Toolchain compiled from source 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/riscv_gnu_toolchain_dev_env:latest`| 6 | |*User* | `docker_user`| 7 | |*Home Dir*| `/home/docker_user`| 8 | |*Workdir*| `/project`| 9 | |*Tool Path*| `/opt/riscv-toolchain/`| 10 | 11 | 12 | Clone the https://github.com/riscv-collab/riscv-gnu-toolchain repo and 13 | build the toolchain within Docker. A multistage docker file is used to 14 | reduce the size of the final image. 15 | 16 | The final `fiveembeddev/riscv_gnu_toolchain_dev_env` image will have 17 | the `riscv32-unknown-elf-` toolchain on the path. 18 | 19 | 20 | *NOTE*: The tool build requires 5GB+ of disk space, and building within 21 | docker requires a lot of system resources. An alternate build is in 22 | `../riscv-gnu-toolchain-2/`. 23 | 24 | ```bash 25 | docker run \ 26 | --tty \ 27 | --interactive \ 28 | --rm \ 29 | -v .:/project \ 30 | fiveembeddev/riscv_gnu_toolchain_dev_env:latest \ 31 | riscv32-unknown-elf-gcc --version 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /docker/riscv-openocd/README.md: -------------------------------------------------------------------------------- 1 | # OpenOCD for RISC-V 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/riscv_openocd_base:latest`| 6 | |*User*| `docker_user`| 7 | |*Home Dir*| `/home/docker_user`| 8 | |*Workdir*| `/project`| 9 | |*Tool Path*| `/opt/riscv-openocd/`| 10 | 11 | 12 | Clone and build the RISC-V port of openocd from 13 | https://github.com/riscv-collab/riscv-openocd. The tools will be built inside 14 | of the docker image. A multistage docker file is used so the source is 15 | not included in the final image. 16 | 17 | An example configuration file is copied into the docker image for 18 | running with the spike ISA simulator. 19 | 20 | ```bash 21 | docker run \ 22 | --tty \ 23 | --interactive \ 24 | --rm \ 25 | -v .:/project \ 26 | -p "9824:9824" \ 27 | -p "4000:4000" \ 28 | -p "6000:6000" \ 29 | -p "3000:3000" \ 30 | fiveembeddev/riscv_openocd_base:latest \ 31 | /opt/riscv-openocd/bin/openocd \ 32 | -f /opt/riscv-openocd/riscv_spike.cfg 33 | ``` 34 | 35 | (Note: command requires a target to connect to on 9824, such as riscv-spike) 36 | -------------------------------------------------------------------------------- /examples/test-code-c/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | Simple machine mode timer driver for RISC-V standard timer. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | (https://five-embeddev.com/) 6 | 7 | */ 8 | 9 | #ifndef TIMER_H 10 | #define TIMER_H 11 | 12 | #include 13 | 14 | #define RISCV_MTIMECMP_ADDR (0x2000000 + 0x4000) 15 | #define RISCV_MTIME_ADDR (0x2000000 + 0xBFF8) 16 | 17 | #define MTIME_FREQ_HZ 32768 18 | 19 | #define MTIMER_SECONDS_TO_CLOCKS(SEC) \ 20 | ((uint64_t)(((SEC)*(MTIME_FREQ_HZ)))) 21 | 22 | /** Set the raw time compare point in system timer clocks. 23 | * @param clock_offset Time relative to current mtime when 24 | * @note The time range of the 64 bit timer is large enough not to consider a wrap around of mtime. 25 | * An interrupt will be generated at mtime + clock_offset. 26 | * See http://five-embeddev.com/riscv-isa-manual/latest/machine.html#machine-timer-registers-mtime-and-mtimecmp 27 | */ 28 | void mtimer_set_raw_time_cmp(uint64_t clock_offset); 29 | 30 | /** Read the raw time of the system timer in system timer clocks 31 | */ 32 | uint64_t mtimer_get_raw_time(void); 33 | 34 | 35 | #endif // #ifdef TIMER_H 36 | 37 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-sim/README.md: -------------------------------------------------------------------------------- 1 | # Debug Server With RISC-V Spike 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/riscv_spike_debug_sim:latest`| 6 | |*Image*|`fiveembeddev/forked_riscv_spike_debug_sim:latest`| 7 | |*User*| `docker_user`| 8 | |*Home Dir*| `/home/docker_user`| 9 | |*Workdir*| `/project`| 10 | |*Tool Path*| `/opt/riscv-isa-sim/`| 11 | |*Tool Path*| `/opt/riscv-openocd/`| 12 | |*GDB Port*| 3333 | 13 | |*OpenOCD TCL Port*| 6666 | 14 | |*OpenOCD CMD Port*| 4444 | 15 | 16 | Docker environment for running spike with openocd for exposing a GDB 17 | port for debugging RISC-V applications. 18 | 19 | ## Standard Version 20 | 21 | Expose a server for GDB. 22 | 23 | ~~~ 24 | docker run \ 25 | -it \ 26 | -p 3333:3333 27 | --rm \ 28 | -v .:/project \ 29 | fiveembeddev/riscv_spike_debug_sim:latest \ 30 | build_target/src/main.elf 31 | ~~~ 32 | 33 | 34 | ## VCD Version 35 | 36 | VCD Trace can saved to inspect a run. 37 | 38 | ~~~ 39 | docker run \ 40 | -it \ 41 | --rm \ 42 | -v .:/project \ 43 | fiveembeddev/forked_riscv_spike_debug_sim:latest \ 44 | --vcd-log=test.vcd \ 45 | --max-cycles=10000 \ 46 | build_target/src/main.elf 47 | ~~~ 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Docker and docker-compose files for building and simulating RISC-V target code. 2 | 3 | See for more info. 4 | 5 | ## Dockerfiles 6 | 7 | Each directory in `docker/` folder includes at least `Dockerfile` and `Makefile`. The docker `Dockerfile` will build an 8 | image, either from source or using the OS package and tools 9 | manager. The `Makefile` is used to define the image 10 | tags and run some commands or open a shell to check the build. The 11 | `Makefile` is generally for convinience, the build steps are in the 12 | `Dockerfile` and `targets.mak` file. NOTE - `riscv-gnu-toolchain-2` 13 | relies on the `compose.yaml` to build the image, as the build files are stored 14 | outside of docker. 15 | 16 | The docker images are designed to run tools using a user account with 17 | user ID, `DOCKER_USER_UID`. The `Makefile` will set that to the uid of 18 | the user building the docker images. 19 | 20 | The docker images set the workdir to `/project`. The input and output 21 | files can be mounted to this volume. 22 | 23 | ## Examples 24 | 25 | The directories in `example/` will compile or simulate some target code. 26 | 27 | The `Makefile` files generally include the commands, the 28 | `compose.yaml` are provided for convinience if needed. These all 29 | assume the required images in `docker/` have been built. 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-sim/sim_helpers.sh: -------------------------------------------------------------------------------- 1 | BITBANG_PORT=9824 2 | GDB_PORT=3333 3 | TCL_PORT=6666 4 | CMD_PORT=4444 5 | 6 | SPIKE_PID=-1 7 | OPENOCD_PID=-1 8 | 9 | LOG_DIR=/project 10 | PID_DIR=/tmp 11 | 12 | ELF_FILE= 13 | 14 | # ------------------------------------------ 15 | # Functions 16 | 17 | print_log(){ 18 | if [ -f $2 ]; then 19 | echo "$1: BEGIN" 20 | cat $2 21 | echo "$1: END" 22 | else 23 | echo "$1 LOG: NOT FOUND..." 24 | fi 25 | } 26 | 27 | clean_up_pid() { 28 | if [ $2 > 0 ] ; then 29 | if ps -p $2 > /dev/null 2>&1 ; then 30 | echo "$1 EXIT: KILL ($2)" 31 | kill $2; 32 | else 33 | echo "$1 EXIT: ALREADY DEAD" 34 | fi 35 | fi 36 | } 37 | 38 | clean_up() { 39 | print_log "SPIKE" ${LOG_DIR}/spike.log 40 | print_log "OPENOCD" ${LOG_DIR}/openocd.log 41 | clean_up_pid "SPIKE" $SPIKE_PID 42 | clean_up_pid "OPENOCD" $OPENOCD_PID 43 | exit $1 44 | } 45 | 46 | test_alive() { 47 | if ! ps -p $2 > /dev/null 2>&1 ; then 48 | echo "$1: PROCESS DIED" 49 | clean_up 1 50 | fi 51 | } 52 | 53 | waitport() { 54 | while ! nc -z localhost $3 ; do 55 | sleep 0.1 ; 56 | test_alive $1 $2 57 | done 58 | } 59 | 60 | 61 | 62 | find_elf_args() { 63 | for arg in $@; do 64 | if [[ "$arg" != "-"* ]] ; then 65 | if [ -f $arg ] ; then 66 | echo "$arg" 67 | fi 68 | fi 69 | done 70 | } 71 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-gdb/README.md: -------------------------------------------------------------------------------- 1 | # Debug Server With RISC-V Spike 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/riscv_spike_debug_gdb:latest`| 6 | |*User*| `docker_user`| 7 | |*Home Dir*| `/home/docker_user`| 8 | |*Workdir*| `/project`| 9 | |*Tool Path*| `/opt/riscv-isa-sim/`| 10 | |*Tool Path*| `/opt/riscv-openocd/`| 11 | |*Tool Path*| `/opt/riscv-none-embed/`| 12 | 13 | Docker environment for running spike with openocd & GDB to allow direct debugging RISC-V applications. 14 | 15 | ~~~ 16 | docker run \ 17 | -it \ 18 | --rm \ 19 | -v .:/project \ 20 | fiveembeddev/riscv_spike_debug_gdb:latest \ 21 | build/main.elf 22 | ~~~ 23 | 24 | output: 25 | 26 | ~~~ 27 | SPIKE: STARTING with ARGS: build/main.elf 28 | FOUND ELF: build/main.elf 29 | SPIKE: WAIT FOR PORT 9824 30 | SPIKE: READY 31 | OPENOCD: STARTING 32 | OPENOCD: READY 33 | GDB: LOAD: build/main.elf 34 | GNU gdb (xPack GNU RISC-V Embedded GCC x86_64) 12.1 35 | 36 | For help, type "help". 37 | Type "apropos word" to search for commands related to "word"... 38 | Reading symbols from build/main.elf... 39 | Remote debugging using 127.0.0.1:3333 40 | 0x00001000 in ?? () 41 | (gdb) tui enable 42 | Detaching from program: /project/build/main.elf, Remote target 43 | Ending remote debugging. 44 | [Inferior 1 (Remote target) detached] 45 | ~~~ 46 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-gdb/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG SPIKE_IMAGE_NAME=riscv_spike_dev_env 2 | FROM fiveembeddev/${SPIKE_IMAGE_NAME}:latest AS riscv_spike_debug_gdb 3 | 4 | WORKDIR /project/ 5 | 6 | # Merge in openocd 7 | COPY --from=fiveembeddev/riscv_openocd_base:latest \ 8 | /opt/riscv-openocd/ \ 9 | /opt/riscv-openocd/ 10 | 11 | RUN sudo mkdir -p /opt/riscv-none-embed/bin 12 | 13 | COPY --from=fiveembeddev/riscv_xpack_gcc_dev_env:latest \ 14 | /opt/riscv-none-embed/bin/riscv-none-elf-gdb \ 15 | /opt/riscv-none-embed/bin/ 16 | COPY --from=fiveembeddev/riscv_xpack_gcc_dev_env:latest \ 17 | /opt/riscv-none-embed/libexec \ 18 | /opt/riscv-none-embed/libexec 19 | 20 | COPY --from=fiveembeddev/riscv_xpack_gcc_dev_env:latest \ 21 | /opt/riscv-none-embed/include \ 22 | /opt/riscv-none-embed/include 23 | 24 | ENV PATH=/opt/riscv-none-embed/bin:${PATH} 25 | RUN /opt/riscv-none-embed/bin/riscv-none-elf-gdb --version 26 | 27 | RUN sudo apt-get update -qq && sudo apt-get install -y ncat 28 | ENV PATH=/opt/riscv-openocd/bin:/opt/riscv-isa-sim/bin:/bin:/usr/bin:/usr/local/bin:/opt/riscv-none-embed/bin/ 29 | 30 | COPY riscv_spike.cfg /opt/ 31 | COPY sim_helpers.sh /opt/ 32 | COPY entrypoint_gdb.sh /opt/ 33 | RUN sudo chmod +x /opt/entrypoint_gdb.sh 34 | 35 | ENV RISCV_ISA=rv32imac 36 | ENV RISCV_PRIV=m 37 | ENV BOARD_MEM=0x8000000:0x2000,0x80000000:0x4000,0x20010000:0x6a120 38 | ENV START_PC=0x20010000 39 | 40 | ENTRYPOINT ["/opt/entrypoint_gdb.sh"] 41 | -------------------------------------------------------------------------------- /docker/riscv-gtkwave/README.md: -------------------------------------------------------------------------------- 1 | # Container for running GTKWave with decoders. 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/riscv_gtkwave_base:latest`| 6 | |*User*| `docker_user`| 7 | |*Home Dir*| `/home/docker_user`| 8 | |*Workdir*| `/project`| 9 | |*Tool Path*| `/opt/riscv-gtkwave/`| 10 | 11 | Following tools installed: 12 | - [GTKWave](https://gtkwave.sourceforge.net/) 13 | - [RISC-V GTKWave Decoders](https://github.com/five-embeddev/riscv-gtkwave) 14 | 15 | GTKWave is an x11 app, expose X11 env. 16 | 17 | ```bash 18 | docker run \ 19 | --tty \ 20 | --interactive \ 21 | --rm \ 22 | -v .:/project \ 23 | -v /tmp/.X11-unix:/tmp/.X11-unix \ 24 | -e DISPLAY=:0 \ 25 | fiveembeddev/riscv_gtkwave_base:latest \ 26 | gtkwave vcd-trace.vcd config.gtkw 27 | ``` 28 | 29 | Decode elf address: 30 | 31 | ``` bash 32 | docker run \ 33 | --tty \ 34 | --interactive \ 35 | --rm \ 36 | -v .:/project \ 37 | -eDECODE_ELF=build_target/src/main.elf \ 38 | fiveembeddev/riscv_gtkwave_base:latest 39 | /opt/riscv_gtkwave/bin/decode_addr 40 | 0x21000000 41 | __clz_tab+0xfeffec 42 | ``` 43 | 44 | 45 | Decode risc-v opcode: 46 | 47 | ``` bash 48 | docker run \ 49 | --tty \ 50 | --interactive \ 51 | --rm \ 52 | fiveembeddev/riscv_gtkwave_base:latest 53 | /opt/riscv_gtkwave/bin/decode_inst-rv32imac 54 | 0 55 | c.unimp 56 | ``` 57 | 58 | -------------------------------------------------------------------------------- /docker/targets.mak: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: 3 | build: docker-build-${IMAGE_NAME} 4 | 5 | 6 | .PHONY: compose-build-${IMAGE_NAME} 7 | compose-build-${IMAGE_NAME} : 8 | ${DOCKER_COMPOSE} build \ 9 | ${DOCKER_BUILD_ARGS:%=--build-arg %} \ 10 | ${IMAGE_NAME} 11 | 12 | .PHONY: docker-build-${IMAGE_NAME} 13 | docker-build-${IMAGE_NAME} : 14 | ${DOCKER} build ${NO_CACHE} \ 15 | ${DOCKER_BUILD_ARGS:%=--build-arg %} \ 16 | --tag ${BUILD_TAG} \ 17 | . 18 | 19 | # --progress=plain \ 20 | 21 | .PHONY: shell 22 | shell : 23 | ${DOCKER} run \ 24 | --tty \ 25 | --interactive \ 26 | --rm \ 27 | --user ${DOCKER_USER_UID}:${DOCKER_USER_GID} \ 28 | -v .:/project \ 29 | ${DOCKER_RUN_ARGS} \ 30 | --entrypoint ${DOCKER_RUN_SHELL} \ 31 | ${BUILD_TAG} 32 | 33 | 34 | .PHONY: push 35 | push : 36 | ${DOCKER} push ${BUILD_TAG} 37 | docker tag ${BUILD_TAG} ${RELEASE_TAG} 38 | ${DOCKER} push ${RELEASE_TAG} 39 | 40 | COMPILE_DIRS=\ 41 | riscv-gnu-toolchain \ 42 | riscv-gnu-toolchain-2 \ 43 | riscv-openocd \ 44 | riscv-rust \ 45 | riscv-spike \ 46 | riscv-spike-debug-sim \ 47 | riscv-tool-build \ 48 | riscv-xpack-gcc 49 | 50 | .PHONY: ${COMPILE_DIRS} 51 | ${COMPILE_DIRS} : 52 | ${MAKE} -C ../$@ 53 | 54 | .PHONY: riscv-spike-vcd 55 | riscv-spike-vcd : 56 | ${MAKE} -C ../riscv-spike -f Makefile.vcd_spike 57 | 58 | 59 | 60 | riscv_spike.cfg : ../riscv-openocd/riscv_spike.cfg 61 | cp $< $@ 62 | 63 | sim_helpers.sh : ../riscv-spike-debug-sim/sim_helpers.sh 64 | cp $< $@ 65 | -------------------------------------------------------------------------------- /docker/riscv-tool-build/README.md: -------------------------------------------------------------------------------- 1 | # Docker environment for building RISC-V tools. 2 | 3 | | | | 4 | |-------|-----------------------------------------| 5 | |*Image*| `fiveembeddev/build_env:latest`| 6 | |*User*| `docker_user`| 7 | |*Home Dir*| `/home/docker_user`| 8 | |*Workdir*| `/project`| 9 | |*Tool Path*| `/opt/riscv-gtkwave/`| 10 | 11 | Build tools (g++, autoconf, etc) and libraries for building development tools. 12 | 13 | Non-root user environment and workdir. 14 | 15 | ```bash 16 | docker run \ 17 | --tty \ 18 | --interactive \ 19 | --rm \ 20 | -v .:/project \ 21 | fiveembeddev/build_env:latest 22 | ``` 23 | 24 | ```bash 25 | docker_user@4b308be4da67:/project$ gcc --version 26 | gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0 27 | Copyright (C) 2019 Free Software Foundation, Inc. 28 | This is free software; see the source for copying conditions. There is NO 29 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 30 | 31 | docker_user@4b308be4da67:/project$ autoconf --version 32 | autoconf (GNU Autoconf) 2.69 33 | Copyright (C) 2012 Free Software Foundation, Inc. 34 | License GPLv3+/Autoconf: GNU GPL version 3 or later 35 | , 36 | This is free software: you are free to change and redistribute it. 37 | There is NO WARRANTY, to the extent permitted by law. 38 | 39 | Written by David J. MacKenzie and Akim Demaille. 40 | docker_user@4b308be4da67:/project$ 41 | ``` 42 | -------------------------------------------------------------------------------- /docker/riscv-spike/README.md: -------------------------------------------------------------------------------- 1 | # Docker container for running the RISC-V spike ISA simulator. 2 | 3 | The source will be downloaded and compiled within the docker container. 4 | 5 | ## Standard Version 6 | 7 | | | | 8 | |-------|-----------------------------------------| 9 | |*Image*| `fiveembeddev/riscv_spike_dev_env:latest`| 10 | |*User*| `docker_user`| 11 | |*Home Dir*| `/home/docker_user`| 12 | |*Workdir*| `/project`| 13 | |*Tool Path*| `/opt/riscv-isa-sim/`| 14 | 15 | RISC-V reference ISA simulator, Spike. 16 | 17 | ```bash 18 | docker run \ 19 | --tty \ 20 | --interactive \ 21 | --rm \ 22 | -v .:/project \ 23 | fiveembeddev/riscv_spike_dev_env:latest \ 24 | spike --help 25 | ``` 26 | 27 | ## Forked Version with VCD Tracing and command file extensions 28 | 29 | Compiled from my fork with VCD tracing https://github.com/five-embeddev/riscv-isa-sim/tree/vcd_trace 30 | 31 | | | | 32 | |-------|-----------------------------------------| 33 | |*Image*| `fiveembeddev/forked_riscv_spike_dev_env:latest`| 34 | |*User*| `docker_user`| 35 | |*Home Dir*| `/home/docker_user`| 36 | |*Workdir*| `/project`| 37 | |*Tool Path*| `/opt/riscv-isa-sim/`| 38 | 39 | ```bash 40 | docker run \ 41 | --tty \ 42 | --interactive \ 43 | --rm \ 44 | -v .:/project \ 45 | fiveembeddev/forked_riscv_spike_dev_env:latest \ 46 | spike --help 47 | ``` 48 | 49 | Note the new options 50 | 51 | ``` 52 | --vcd-log= Log VCD to this file. 53 | --max-cycles= Limit simulation to this number of cycles. 54 | ``` 55 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-gdb/entrypoint_gdb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # USAGE: ./entrypoint.sh 3 | 4 | source /opt/sim_helpers.sh 5 | 6 | # ------------------------------------------ 7 | # Setup 8 | 9 | trap clean_up SIGHUP SIGINT SIGTERM 10 | 11 | # ------------------------------------------ 12 | # Print args 13 | 14 | echo "SPIKE: STARTING with ARGS: $@" 15 | 16 | ELF_FILE=$(find_elf_args $@) 17 | echo "FOUND ELF: ${ELF_FILE}" 18 | echo "OTHER ARGS: ${@}" 19 | 20 | 21 | # ------------------------------------------ 22 | # Start sim 23 | 24 | nohup \ 25 | /opt/riscv-isa-sim/bin/spike \ 26 | --rbb-port=${BITBANG_PORT} \ 27 | -H \ 28 | --isa=${RISCV_ISA} \ 29 | --priv=${RISCV_PRIV} \ 30 | -m${BOARD_MEM} \ 31 | --pc=${START_PC} \ 32 | $@ \ 33 | > ${LOG_DIR}/spike.log 2>&1 & echo $! > ${PID_DIR}/spike.pid 34 | 35 | if [ -f ${PID_DIR}/spike.pid ] ; then 36 | SPIKE_PID=`cat ${PID_DIR}/spike.pid` 37 | fi 38 | 39 | echo "SPIKE: WAIT FOR PORT ${BITBANG_PORT}" 40 | 41 | waitport "SPIKE" ${SPIKE_PID} ${BITBANG_PORT} 42 | 43 | echo "SPIKE: READY" 44 | 45 | # ------------------------------------------ 46 | # Start openocd 47 | 48 | echo "OPENOCD: STARTING" 49 | 50 | nohup \ 51 | /opt/riscv-openocd/bin/openocd \ 52 | -f /opt/riscv_spike.cfg \ 53 | > ${LOG_DIR}/openocd.log 2>&1 & echo $! > ${PID_DIR}/openocd.pid 54 | 55 | if [ -f ${PID_DIR}/openocd.pid ] ; then 56 | OPENOCD_PID=`cat ${PID_DIR}/openocd.pid` 57 | fi 58 | 59 | waitport "OPENOCD" ${OPENOCD_PID} ${CMD_PORT} 60 | 61 | # ------------------------------------------ 62 | # Wait for exit 63 | 64 | echo "OPENOCD: READY" 65 | echo "GDB: LOAD: ${ELF_FILE}" 66 | 67 | riscv-none-elf-gdb \ 68 | -ex 'target remote 127.0.0.1:3333' \ 69 | ${ELF_FILE} 70 | 71 | -------------------------------------------------------------------------------- /examples/test-code-c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.10) 3 | 4 | # set the project name 5 | project(baremetal_startup_c C) 6 | 7 | # specify the C standard 8 | set(CMAKE_C_FLAGS "\ 9 | -march=${CMAKE_SYSTEM_PROCESSOR} \ 10 | -std=c99 \ 11 | -Os \ 12 | -g \ 13 | -Wall \ 14 | -ffunction-sections \ 15 | ") 16 | set ( STACK_SIZE 0xf00 ) 17 | set ( TARGET main ) 18 | 19 | # add the executable 20 | 21 | add_executable(${TARGET}.elf ${TARGET}.c startup.c timer.c) 22 | SET(LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/linker.lds") 23 | 24 | set_target_properties(${TARGET}.elf PROPERTIES LINK_DEPENDS "${LINKER_SCRIPT}") 25 | target_include_directories(${TARGET}.elf PRIVATE ../include/ ) 26 | 27 | # Linker control 28 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nostartfiles -Xlinker --defsym=__stack_size=${STACK_SIZE} -T ${LINKER_SCRIPT} -Wl,-Map=${TARGET}.map") 29 | 30 | # Post processing command to create a disassembly file 31 | add_custom_command(TARGET ${TARGET}.elf POST_BUILD 32 | COMMAND ${CMAKE_OBJDUMP} -S ${TARGET}.elf > ${TARGET}.disasm 33 | COMMENT "Invoking: Disassemble") 34 | 35 | # Post processing command to create a hex file 36 | add_custom_command(TARGET ${TARGET}.elf POST_BUILD 37 | COMMAND ${CMAKE_OBJCOPY} -O ihex ${TARGET}.elf ${TARGET}.hex 38 | COMMENT "Invoking: Hexdump") 39 | 40 | # Pre-processing command to create disassembly for each source file 41 | foreach (SRC_MODULE main startup) 42 | add_custom_command(TARGET ${TARGET}.elf 43 | PRE_LINK 44 | COMMAND ${CMAKE_OBJDUMP} -S CMakeFiles/${TARGET}.elf.dir/${SRC_MODULE}.c.obj > ${SRC_MODULE}.s 45 | COMMENT "Invoking: Disassemble ( CMakeFiles/${TARGET}.elf.dir/${SRC_MODULE}.c.obj)") 46 | endforeach() 47 | 48 | SET(DCMAKE_EXPORT_COMPILE_COMMANDS ON) 49 | -------------------------------------------------------------------------------- /docker/riscv-spike-debug-sim/sim_entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # USAGE: ./entrypoint.sh 3 | 4 | source /opt/sim_helpers.sh 5 | 6 | # ------------------------------------------ 7 | # Setup 8 | 9 | trap clean_up SIGHUP SIGINT SIGTERM 10 | 11 | # ------------------------------------------ 12 | # Print args 13 | 14 | echo "SPIKE: STARTING with ARGS: $@" 15 | ELF=$(find_elf_args $@) 16 | echo "FOUND ELF: ${ELF}" 17 | 18 | if [ "${ELF}" == "" ] ; then 19 | echo "NO ELF FILE FOUND: ${ELF}" 20 | fi 21 | 22 | # ------------------------------------------ 23 | # Start sim 24 | 25 | nohup \ 26 | /opt/riscv-isa-sim/bin/spike \ 27 | --rbb-port=${BITBANG_PORT} \ 28 | -H \ 29 | --isa=${RISCV_ISA} \ 30 | --priv=${RISCV_PRIV} \ 31 | -m${BOARD_MEM} \ 32 | --pc=${START_PC} \ 33 | "$@" \ 34 | > ${LOG_DIR}/spike.log 2>&1 & echo $! > ${PID_DIR}/spike.pid 35 | 36 | if [ -f ${PID_DIR}/spike.pid ] ; then 37 | SPIKE_PID=`cat ${PID_DIR}/spike.pid` 38 | fi 39 | 40 | echo "SPIKE: WAIT FOR PORT ${BITBANG_PORT}" 41 | 42 | waitport "SPIKE" ${SPIKE_PID} ${BITBANG_PORT} 43 | 44 | echo "SPIKE: READY" 45 | 46 | # ------------------------------------------ 47 | # Start openocd 48 | 49 | echo "OPENOCD: STARTING" 50 | 51 | nohup \ 52 | /opt/riscv-openocd/bin/openocd \ 53 | -f /opt/riscv_spike.cfg \ 54 | > ${LOG_DIR}/openocd.log 2>&1 & echo $! > ${PID_DIR}/openocd.pid 55 | 56 | if [ -f ${PID_DIR}/openocd.pid ] ; then 57 | OPENOCD_PID=`cat ${PID_DIR}/openocd.pid` 58 | fi 59 | 60 | waitport "OPENOCD" ${OPENOCD_PID} ${CMD_PORT} 61 | 62 | # ------------------------------------------ 63 | # Wait for exit 64 | 65 | echo "OPENOCD: READY, GDB: ${GDB_PORT}, COMMAND: ${CMD_PORT}" 66 | 67 | while [ 1 ] ; do 68 | sleep 0.1 ; 69 | test_alive "SPIKE" $SPIKE_PID 70 | test_alive "OPENOCD" $OPENOCD_PID 71 | done 72 | 73 | 74 | # will not reach here. 75 | -------------------------------------------------------------------------------- /docker/riscv-rust/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG DOCKER_USER_UID=1000 2 | ARG TZ=UTC 3 | 4 | # ------------------------------------------------------------------------ 5 | # Just the RUST installer 6 | 7 | ARG BASE_IMAGE=ubuntu:jammy 8 | FROM ${BASE_IMAGE} AS riscv_rustup_env 9 | 10 | ARG DOCKER_USER_UID 11 | ARG TZ 12 | 13 | # Basic OS update 14 | RUN apt-get update -qq 15 | RUN apt-get install -y sudo 16 | 17 | # Setup user 18 | RUN useradd \ 19 | -u ${DOCKER_USER_UID} \ 20 | -m \ 21 | -r \ 22 | -G sudo -s /sbin/nologin \ 23 | -c "Docker image user" \ 24 | docker_user 25 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 26 | USER docker_user 27 | 28 | WORKDIR /home/docker_user 29 | 30 | # Basic OS Tools 31 | RUN DEBIAN_FRONTEND="noninteractive" sudo apt-get -y install tzdata 32 | RUN sudo apt-get install -y curl 33 | 34 | RUN curl \ 35 | --proto '=https' \ 36 | --tlsv1.2 \ 37 | -sSf \ 38 | https://sh.rustup.rs \ 39 | -o setup.rustup.sh 40 | 41 | RUN sh ./setup.rustup.sh \ 42 | -y \ 43 | --no-modify-path \ 44 | --profile minimal \ 45 | --default-toolchain stable 46 | 47 | ENV PATH=/home/docker_user/.cargo/bin:/bin/:/usr/bin 48 | 49 | RUN sudo mkdir /project && sudo chown docker_user /project 50 | WORKDIR /project 51 | 52 | # ------------------------------------------------------------------------ 53 | # Add the RISC-V target 54 | 55 | FROM riscv_rustup_env AS riscv_rustup_dev_env 56 | 57 | RUN rustup target add riscv32imac-unknown-none-elf 58 | RUN rustup target add riscv32i-unknown-none-elf 59 | RUN rustup target add riscv32imac-unknown-none-elf 60 | RUN rustup target add riscv32imc-unknown-none-elf 61 | RUN rustup target add riscv64gc-unknown-none-elf 62 | RUN rustup target add riscv64imac-unknown-none-elf 63 | 64 | RUN sudo apt-get install -y build-essential 65 | 66 | # For cargo objdump etc 67 | RUN cargo install cargo-binutils 68 | RUN rustup component add llvm-tools-preview 69 | -------------------------------------------------------------------------------- /docker/riscv-openocd/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG OPENOCD_TAG=riscv 2 | ARG DOCKER_USER_UID=1000 3 | ARG BASE_IMAGE=ubuntu:jammy 4 | 5 | FROM fiveembeddev/build_env:latest AS riscv_openocd_build_config 6 | 7 | ARG OPENOCD_TAG 8 | ENV INSTALL_PATH=/opt/riscv-openocd/ 9 | 10 | # Clone git repos 11 | RUN sudo apt-get update && sudo apt-get install -y ca-certificates pkg-config 12 | 13 | RUN sudo mkdir -p /work/git && sudo chown -R docker_user /work/ 14 | WORKDIR /work/git 15 | RUN git clone \ 16 | --depth 1 \ 17 | --branch ${OPENOCD_TAG} \ 18 | https://github.com/riscv/riscv-openocd.git 19 | 20 | WORKDIR /work/git/riscv-openocd 21 | RUN ls 22 | RUN git submodule update \ 23 | --init \ 24 | --recommend-shallow \ 25 | jimtcl 26 | 27 | RUN git submodule update \ 28 | --init \ 29 | --recommend-shallow \ 30 | src/jtag/drivers/libjaylink 31 | 32 | RUN sudo apt-get update && sudo apt-get install -y libjim-dev 33 | 34 | # Configure 35 | RUN ./bootstrap 36 | RUN ./configure \ 37 | --enable-dummy \ 38 | --enable-remote-bitbang \ 39 | --prefix=${INSTALL_PATH} 40 | 41 | # Build and install 42 | RUN make 43 | RUN sudo make install 44 | 45 | # Lightwieght container with only tools, no source 46 | ARG BASE_IMAGE 47 | FROM ${BASE_IMAGE} AS riscv_openocd_base 48 | 49 | ARG DOCKER_USER_UID 50 | ARG TZ 51 | 52 | ENV INSTALL_PATH=/opt/riscv-openocd/ 53 | 54 | # Basic OS update 55 | RUN apt-get update -qq 56 | RUN apt-get install -y sudo 57 | 58 | # Setup user 59 | RUN useradd \ 60 | -u ${DOCKER_USER_UID} \ 61 | -m \ 62 | -r \ 63 | -G sudo -s /sbin/nologin \ 64 | -c "Docker image user" \ 65 | docker_user 66 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 67 | USER docker_user 68 | 69 | COPY --from=riscv_openocd_build_config ${INSTALL_PATH} ${INSTALL_PATH} 70 | 71 | ENV PATH=${INSTALL_PATH}/bin:/bin:/usr/bin:/usr/local/bin 72 | 73 | COPY riscv_spike.cfg /opt/riscv-openocd/ 74 | 75 | RUN sudo mkdir /project && sudo chown docker_user /project 76 | WORKDIR /project 77 | 78 | -------------------------------------------------------------------------------- /examples/test-code-c/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | Baremetal main program with timer interrupt. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | https://five-embeddev.com/ 6 | 7 | Tested with sifive-hifive-revb, but should not have any 8 | dependencies to any particular implementation. 9 | 10 | */ 11 | // RISC-V CSR definitions and access classes 12 | #include "riscv-csr.h" 13 | #include "riscv-interrupts.h" 14 | #include "timer.h" 15 | 16 | // Machine mode interrupt service routine 17 | static void irq_entry(void) __attribute__ ((interrupt ("machine"))); 18 | 19 | // Global to hold current timestamp 20 | static volatile uint64_t timestamp = 0; 21 | 22 | int main(void) { 23 | // Global interrupt disable 24 | csr_clr_bits_mstatus(MSTATUS_MIE_BIT_MASK); 25 | csr_write_mie(0); 26 | 27 | // Setup timer for 1 second interval 28 | timestamp = mtimer_get_raw_time(); 29 | mtimer_set_raw_time_cmp(MTIMER_SECONDS_TO_CLOCKS(1)); 30 | 31 | // Setup the IRQ handler entry point 32 | csr_write_mtvec((uint_xlen_t) irq_entry); 33 | 34 | // Enable MIE.MTI 35 | csr_set_bits_mie(MIE_MTI_BIT_MASK); 36 | 37 | // Global interrupt enable 38 | csr_set_bits_mstatus(MSTATUS_MIE_BIT_MASK); 39 | 40 | // Busy loop 41 | do { 42 | __asm__ volatile ("wfi"); 43 | } while (1); 44 | 45 | return 0; 46 | 47 | } 48 | 49 | #pragma GCC push_options 50 | // Force the alignment for mtvec.BASE. A 'C' extension program could be aligned to to bytes. 51 | #pragma GCC optimize ("align-functions=4") 52 | static void irq_entry(void) { 53 | uint_xlen_t this_cause = csr_read_mcause(); 54 | if (this_cause & MCAUSE_INTERRUPT_BIT_MASK) { 55 | this_cause &= 0xFF; 56 | // Known exceptions 57 | switch (this_cause) { 58 | case RISCV_INT_MASK_MTI : 59 | // Timer exception, keep up the one second tick. 60 | mtimer_set_raw_time_cmp(MTIMER_SECONDS_TO_CLOCKS(1)); 61 | timestamp = mtimer_get_raw_time(); 62 | break; 63 | } 64 | } 65 | } 66 | #pragma GCC pop_options 67 | -------------------------------------------------------------------------------- /docker/riscv-gtkwave/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG OPENOCD_TAG=riscv 2 | ARG DOCKER_USER_UID=1000 3 | ARG BASE_IMAGE=ubuntu:jammy 4 | ARG RISCV_GTKWAVE_TAG=main 5 | ARG RISCV_GTKWAVE_URL=https://github.com/five-embeddev/riscv-gtkwave.git 6 | ARG INSTALL_PATH=/opt/riscv_gtkwave/ 7 | 8 | # ------------------------------------------------------------------------ 9 | FROM fiveembeddev/build_env:latest AS riscv_gtkwave_build 10 | 11 | ARG INSTALL_PATH 12 | ARG RISCV_GTKWAVE_TAG 13 | ARG RISCV_GTKWAVE_URL 14 | 15 | RUN sudo mkdir -p /work/git && sudo chown -R docker_user /work/ 16 | RUN sudo mkdir -p /opt/riscv_gtkwave && sudo chown -R docker_user /work/ 17 | WORKDIR /work/git/ 18 | 19 | RUN git clone \ 20 | --depth 1\ 21 | --recursive \ 22 | --branch ${RISCV_GTKWAVE_TAG} \ 23 | ${RISCV_GTKWAVE_URL} 24 | 25 | RUN sudo apt-get update && sudo apt-get install -y \ 26 | python3-pip \ 27 | device-tree-compiler \ 28 | libboost-all-dev \ 29 | libboost-regex-dev 30 | 31 | 32 | WORKDIR /work/git/riscv-gtkwave/ 33 | RUN pip3 install -r requirements.txt 34 | RUN cd extern/riscv-isa-sim/ && ./configure 35 | RUN make -C extern/riscv-isa-sim/ -j8 36 | RUN make csrs 37 | RUN make -C src 38 | RUN sudo mkdir -p ${INSTALL_PATH} 39 | RUN sudo make install PREFIX_DIR=${INSTALL_PATH} 40 | 41 | # ------------------------------------------------------------------------ 42 | ARG BASE_IMAGE 43 | FROM ${BASE_IMAGE} AS riscv_gtkwave_base 44 | 45 | ARG INSTALL_PATH 46 | ARG DOCKER_USER_UID 47 | 48 | # Basic OS update 49 | RUN apt-get update -qq 50 | RUN apt-get install -y sudo 51 | 52 | # Setup user 53 | RUN useradd \ 54 | -u ${DOCKER_USER_UID} \ 55 | -m \ 56 | -r \ 57 | -G sudo -s /sbin/nologin \ 58 | -c "Docker image user" \ 59 | docker_user 60 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 61 | USER docker_user 62 | 63 | COPY --from=riscv_gtkwave_build ${INSTALL_PATH} ${INSTALL_PATH} 64 | 65 | RUN sudo apt-get update && sudo apt-get install -y \ 66 | libboost-regex1.71.0 \ 67 | gtkwave 68 | 69 | RUN sudo mkdir /project && sudo chown docker_user /project 70 | WORKDIR /project 71 | -------------------------------------------------------------------------------- /docker/riscv-tool-build/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE=ubuntu:jammy 2 | FROM ${BASE_IMAGE} AS riscv_tools_build_env 3 | 4 | ARG DOCKER_USER_UID=1000 5 | ARG TZ=UTC 6 | 7 | # Basic OS update 8 | RUN apt-get update -qq 9 | RUN apt-get install -y sudo 10 | 11 | # Setup user 12 | RUN useradd \ 13 | -u ${DOCKER_USER_UID} \ 14 | -r \ 15 | -G sudo -s /sbin/nologin \ 16 | -c "Docker image user" \ 17 | --create-home \ 18 | docker_user 19 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 20 | USER docker_user 21 | 22 | # Basic OS update 23 | RUN DEBIAN_FRONTEND="noninteractive" sudo apt-get update && sudo apt-get -y install tzdata 24 | RUN sudo apt-get update && sudo apt-get install -y git 25 | RUN sudo apt-get update && sudo apt-get install -y \ 26 | bison \ 27 | build-essential \ 28 | flex 29 | 30 | RUN sudo apt-get update && sudo apt-get install -y \ 31 | autoconf \ 32 | automake \ 33 | autotools-dev 34 | 35 | RUN sudo apt-get update && sudo apt-get install -y \ 36 | bc \ 37 | curl \ 38 | gawk \ 39 | gperf \ 40 | libtool \ 41 | patchutils \ 42 | python3 \ 43 | texinfo 44 | 45 | RUN sudo apt-get update && sudo apt-get install -y \ 46 | libexpat-dev \ 47 | libgmp-dev \ 48 | libmpc-dev \ 49 | libmpfr-dev \ 50 | zlib1g-dev 51 | 52 | # HTTP Git clone is unreliable for gcc etc 53 | # gh cli may resolve this, but need to setup token. 54 | # RUN sudo apt-get update && sudo apt-get install -y \ 55 | # gpg 56 | # RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ 57 | # | sudo gpg --dearmor -o /usr/share/keyrings/githubcli-archive-keyring.gpg 58 | # RUN echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ 59 | # | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null; 60 | # RUN sudo apt-get update && sudo apt-get install -y \ 61 | # gh 62 | 63 | 64 | RUN sudo mkdir /project && sudo chown docker_user /project 65 | RUN sudo chown docker_user /opt 66 | WORKDIR /project 67 | 68 | -------------------------------------------------------------------------------- /examples/test-code-c/timer.c: -------------------------------------------------------------------------------- 1 | /* 2 | Simple machine mode timer driver for RISC-V standard timer. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | (https://five-embeddev.com/) 6 | 7 | */ 8 | 9 | #include "timer.h" 10 | 11 | void mtimer_set_raw_time_cmp(uint64_t clock_offset) { 12 | // First of all set 13 | uint64_t new_mtimecmp = mtimer_get_raw_time() + clock_offset; 14 | #if (__riscv_xlen == 64) 15 | // Single bus access 16 | volatile uint64_t *mtimecmp = (volatile uint64_t*)(RISCV_MTIMECMP_ADDR); 17 | *mtimecmp = new_mtimecmp; 18 | #else 19 | volatile uint32_t *mtimecmpl = (volatile uint32_t *)(RISCV_MTIMECMP_ADDR); 20 | volatile uint32_t *mtimecmph = (volatile uint32_t *)(RISCV_MTIMECMP_ADDR+4); 21 | // AS we are doing 32 bit writes, an intermediate mtimecmp value may cause spurious interrupts. 22 | // Prevent that by first setting the dummy MSB to an unacheivable value 23 | *mtimecmph = 0xFFFFFFFF; // cppcheck-suppress redundantAssignment 24 | // set the LSB 25 | *mtimecmpl = (uint32_t)(new_mtimecmp & 0x0FFFFFFFFUL); 26 | // Set the correct MSB 27 | *mtimecmph = (uint32_t)(new_mtimecmp >> 32); // cppcheck-suppress redundantAssignment 28 | #endif 29 | } 30 | 31 | /** Read the raw time of the system timer in system timer clocks 32 | */ 33 | uint64_t mtimer_get_raw_time(void) { 34 | #if ( __riscv_xlen == 64) 35 | // Directly read 64 bit value 36 | volatile uint64_t *mtime = (volatile uint64_t *)(RISCV_MTIME_ADDR); 37 | return *mtime; 38 | #else 39 | volatile uint32_t * mtimel = (volatile uint32_t *)(RISCV_MTIME_ADDR); 40 | volatile uint32_t * mtimeh = (volatile uint32_t *)(RISCV_MTIME_ADDR+4); 41 | uint32_t mtimeh_val; 42 | uint32_t mtimel_val; 43 | do { 44 | // There is a small risk the mtimeh will tick over after reading mtimel 45 | mtimeh_val = *mtimeh; 46 | mtimel_val = *mtimel; 47 | // Poll mtimeh to ensure it's consistent after reading mtimel 48 | // The frequency of mtimeh ticking over is low 49 | } while (mtimeh_val != *mtimeh); 50 | return (uint64_t) ( ( ((uint64_t)mtimeh_val)<<32) | mtimel_val); 51 | #endif 52 | } 53 | -------------------------------------------------------------------------------- /docker/riscv-gnu-toolchain-2/Makefile: -------------------------------------------------------------------------------- 1 | # -*- Makefile -*- 2 | # 3 | IMAGE_NAME=riscv_gnu_toolchain_dev_env2 4 | 5 | include ../common.mak 6 | 7 | RELEASE_TAG:=${RELEASE_TAG}_gcc_${GCC_TAG} 8 | 9 | MOUNT_BUILD_PATH=/project/build_dir 10 | MOUNT_INSTALL_PATH=/opt/riscv-gnu-toolchain 11 | COMPOSE_RUN_BUILD_DIR=${DOCKER_COMPOSE} run -w ${MOUNT_BUILD_PATH} build_env 12 | COMPOSE_RUN_SRC_DIR=${DOCKER_COMPOSE} run -w ${MOUNT_BUILD_PATH}/riscv-gnu-toolchain build_env 13 | #BASE_REPO=https://github.com/riscv-collab/riscv-gnu-toolchain.git 14 | BASE_REPO=git@github.com:riscv-collab/riscv-gnu-toolchain.git 15 | 16 | # Https clone in docker is unreliable 17 | #GIT_RUN_BUILD_DIR=${COMPOSE_RUN_BUILD_DIR} 18 | #GIT_RUN_SRC_DIR=${COMPOSE_RUN_SRC_DIR} 19 | # Do git operations in host 20 | GIT_RUN_BUILD_DIR=cd build_dir && 21 | GIT_RUN_SRC_DIR=cd build_dir/riscv-gnu-toolchain && 22 | 23 | 24 | 25 | all : dev_env 26 | 27 | tools : docker_build/install_dir/bin/riscv32-unknown-elf-gcc 28 | 29 | docker_build/install_dir/bin/riscv32-unknown-elf-gcc : 30 | if [ ! -d docker_build/install_dir ] ; then mkdir docker_build/install_dir; fi 31 | if [ ! -d build_dir ] ; then mkdir build_dir; fi 32 | ${DOCKER_COMPOSE} build \ 33 | --build-arg DOCKER_USER_UID=${DOCKER_USER_UID} \ 34 | build_env 35 | ${COMPOSE_RUN_BUILD_DIR} rm -rf riscv-gnu-toolchain 36 | ${GIT_RUN_BUILD_DIR} git clone \ 37 | --depth 1 \ 38 | --branch ${GNU_TOOLCHAIN_TAG} \ 39 | ${BASE_REPO} 40 | ${GIT_RUN_SRC_DIR} git submodule set-branch --branch ${GCC_TAG} gcc 41 | ${GIT_RUN_SRC_DIR} git submodule update \ 42 | --init \ 43 | --recursive \ 44 | --recommend-shallow \ 45 | binutils dejagnu gdb glibc newlib gcc 46 | ${COMPOSE_RUN_SRC_DIR} ./configure \ 47 | --prefix=${MOUNT_INSTALL_PATH} \ 48 | --with-tune=size \ 49 | --with-arch=${RISCV_MARCH} \ 50 | --with-abi=${RISCV_ABI} 51 | ${COMPOSE_RUN_SRC_DIR} make 52 | 53 | dev_env : docker_build/install_dir/bin/riscv32-unknown-elf-gcc 54 | ${DOCKER_COMPOSE} build \ 55 | --build-arg DOCKER_USER_UID=${DOCKER_USER_UID} \ 56 | dev_env 57 | 58 | distclean: 59 | rm -rf docker_build/install_dir 60 | rm -rf build_dir 61 | 62 | include ../targets.mak 63 | 64 | -------------------------------------------------------------------------------- /docker/riscv-spike/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG DOCKER_USER_UID=1000 2 | ARG TZ=UTC 3 | ARG SPIKE_TAG=master 4 | ARG SPIKE_URL=https://github.com/riscv-software-src/riscv-isa-sim.git 5 | ARG BASE_IMAGE=ubuntu:jammy 6 | 7 | # ------------------------------------------------------------------------ 8 | FROM fiveembeddev/build_env:latest AS riscv_spike_build_config 9 | 10 | ARG SPIKE_TAG 11 | ARG SPIKE_URL 12 | ENV INSTALL_PATH=/opt/riscv-isa-sim/ 13 | 14 | RUN sudo apt-get update -qq && sudo apt-get install -y device-tree-compiler 15 | 16 | 17 | RUN sudo mkdir -p /work/git && sudo chown -R docker_user /work/ 18 | WORKDIR /work/git/ 19 | 20 | RUN git clone \ 21 | --depth 1\ 22 | --recursive \ 23 | --branch ${SPIKE_TAG} \ 24 | ${SPIKE_URL} 25 | 26 | WORKDIR /work/git/riscv-isa-sim 27 | RUN git submodule update \ 28 | --init \ 29 | --recursive \ 30 | --recommend-shallow 31 | 32 | RUN sudo apt-get install -y libasio-dev libboost-regex-dev libboost-system-dev libboost-thread-dev 33 | # Configure 34 | RUN mkdir build/ 35 | WORKDIR /work/git/riscv-isa-sim/build 36 | RUN ../configure \ 37 | --enable-histogram \ 38 | --prefix=${INSTALL_PATH} 39 | 40 | # Build and install 41 | RUN make 42 | RUN sudo make install 43 | 44 | # ------------------------------------------------------------------------ 45 | # Lightwieght container with only tools, no source 46 | ARG BASE_IMAGE 47 | FROM ${BASE_IMAGE} AS riscv_spike_dev_env 48 | 49 | ARG DOCKER_USER_UID 50 | 51 | RUN apt-get update -qq && apt-get install -y device-tree-compiler 52 | 53 | ENV INSTALL_PATH=/opt/riscv-isa-sim 54 | 55 | RUN apt-get install -y sudo 56 | 57 | # Setup user 58 | RUN useradd \ 59 | -u ${DOCKER_USER_UID} \ 60 | -m \ 61 | -r \ 62 | -G sudo -s /sbin/nologin \ 63 | -c "Docker image user" \ 64 | docker_user 65 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 66 | 67 | COPY --from=riscv_spike_build_config ${INSTALL_PATH} ${INSTALL_PATH} 68 | 69 | RUN sudo apt-get install -y libboost-regex1.74.0 70 | 71 | USER docker_user 72 | ENV PATH=${INSTALL_PATH}/bin:/bin:/usr/bin:/usr/local/bin 73 | 74 | RUN sudo mkdir /project && sudo chown docker_user /project 75 | WORKDIR /project 76 | 77 | -------------------------------------------------------------------------------- /examples/build-run-sim/Makefile: -------------------------------------------------------------------------------- 1 | RISCV_ISA=rv32imac 2 | RISCV_PRIV=m 3 | # See test_code/linker.lds 4 | BOARD_MEM=0x8000000:0x2000,0x80000000:0x4000,0x20010000:0x6a120 5 | BITBANG_PORT=9824 6 | ELF_FILE=/project/build/main.elf 7 | 8 | DOCKER_CMD= docker run \ 9 | --rm \ 10 | -v .:/project \ 11 | -v ${CURDIR}/../test-code-c:/project/test_code 12 | 13 | all : build 14 | 15 | build: 16 | ${DOCKER_CMD} \ 17 | fiveembeddev/riscv_xpack_gcc_dev_env:latest \ 18 | cmake \ 19 | -S test_code \ 20 | -B build \ 21 | -G "Unix Makefiles" \ 22 | -DCMAKE_TOOLCHAIN_FILE=../test_code/riscv.cmake 23 | ${DOCKER_CMD} \ 24 | fiveembeddev/riscv_xpack_gcc_dev_env:latest \ 25 | make \ 26 | VERBOSE=1 \ 27 | -C build 28 | 29 | 30 | sim: 31 | ${DOCKER_CMD} \ 32 | fiveembeddev/riscv_spike_dev_env:latest \ 33 | /opt/riscv-isa-sim/bin/spike \ 34 | -l \ 35 | -d \ 36 | --isa=${RISCV_ISA} \ 37 | --priv=${RISCV_PRIV} \ 38 | -m${BOARD_MEM} \ 39 | --pc=0x20010000 \ 40 | ${ELF_FILE} 41 | 42 | gdb: 43 | ${DOCKER_CMD} \ 44 | --tty \ 45 | --interactive \ 46 | fiveembeddev/riscv_spike_debug_gdb:latest \ 47 | --isa=${RISCV_ISA} \ 48 | --priv=${RISCV_PRIV} \ 49 | -m${BOARD_MEM} \ 50 | --pc=0x20010000 \ 51 | ${ELF_FILE} 52 | 53 | trace: 54 | ${DOCKER_CMD} \ 55 | fiveembeddev/forked_riscv_spike_debug_sim:latest \ 56 | --isa=${RISCV_ISA} \ 57 | --priv=${RISCV_PRIV} \ 58 | -m${BOARD_MEM} \ 59 | --pc=0x20010000 \ 60 | --vcd-log=test.vcd \ 61 | --max-cycles=10000 \ 62 | ${ELF_FILE} 63 | 64 | gtkwave: 65 | ${DOCKER_CMD} \ 66 | --tty \ 67 | --interactive \ 68 | -v /tmp/.X11-unix:/tmp/.X11-unix \ 69 | -e DISPLAY=:0 \ 70 | -e DECODE_ELF=${ELF_FILE} \ 71 | fiveembeddev/riscv_gtkwave_base:latest \ 72 | gtkwave test.vcd test.gtkw 73 | 74 | decode-test: 75 | ${DOCKER_CMD} \ 76 | --tty \ 77 | --interactive \ 78 | -e DECODE_ELF=${ELF_FILE} \ 79 | fiveembeddev/riscv_gtkwave_base:latest \ 80 | ./test-decode.sh 81 | 82 | 83 | sim_help: 84 | docker-compose run sim_test_code \ 85 | /opt/riscv-isa-sim/bin/spike \ 86 | --help 87 | 88 | clean : 89 | rm -rf test.vcd build/ 90 | 91 | .PHONY : build sim clean 92 | -------------------------------------------------------------------------------- /examples/test-code-c/riscv-interrupts.h: -------------------------------------------------------------------------------- 1 | /* 2 | RISC-V machine interrupts. 3 | SPDX-License-Identifier: Unlicense 4 | 5 | https://five-embeddev.com/ 6 | 7 | */ 8 | 9 | #ifndef RISCV_INTERRUPTS_H 10 | #define RISCV_INTERRUPTS_H 11 | 12 | enum { 13 | RISCV_INT_POS_MSI = 3, 14 | RISCV_INT_POS_MTI = 7, 15 | RISCV_INT_POS_MEI = 11, 16 | RISCV_INT_POS_SSI = 1, 17 | RISCV_INT_POS_STI = 5, 18 | RISCV_INT_POS_SEI = 9, 19 | RISCV_INT_POS_USI = 0, 20 | RISCV_INT_POS_UTI = 4, 21 | RISCV_INT_POS_UEI = 8, 22 | }; 23 | 24 | enum { 25 | RISCV_INT_MASK_MSI = (1UL<> /etc/sudoers 70 | USER docker_user 71 | 72 | COPY --from=riscv_gnu_toolchain_build_config ${INSTALL_PATH} ${INSTALL_PATH} 73 | 74 | ENV PATH=${INSTALL_PATH}/bin:/bin:/usr/bin:/usr/local/bin 75 | 76 | RUN sudo mkdir /project && sudo chown docker_user /project 77 | WORKDIR /project 78 | -------------------------------------------------------------------------------- /docker/riscv-xpack-gcc/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG XPACK_GCC_VERSION=12.2.0-3.1 2 | #ARG XPACK_GCC_VERSION=10.1.0-1.1.1 3 | ARG PACKAGE=riscv-none-elf-gcc 4 | ARG NODE_VERSION=16.16.0 5 | ARG NVM_VERSION=v0.38.0 6 | ARG DOCKER_USER_UID=1000 7 | ARG TZ=UTC 8 | ARG BASE_IMAGE=ubuntu:jammy 9 | 10 | FROM ${BASE_IMAGE} AS riscv_xpack_gcc_base_env 11 | 12 | ARG DOCKER_USER_UID 13 | ARG TZ 14 | 15 | # Basic OS update 16 | RUN apt-get update -qq 17 | RUN apt-get install -y sudo 18 | 19 | # Setup user 20 | RUN useradd \ 21 | -u ${DOCKER_USER_UID} \ 22 | -m \ 23 | -r \ 24 | -G sudo -s /sbin/nologin \ 25 | -c "Docker image user" \ 26 | docker_user 27 | RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers 28 | USER docker_user 29 | 30 | # Basic OS Tools 31 | RUN DEBIAN_FRONTEND="noninteractive" sudo apt-get -y install tzdata 32 | RUN sudo apt-get update && sudo apt-get install -y cmake 33 | RUN sudo apt-get update && sudo apt-get install -y curl 34 | 35 | # ------------------------------------------------------------------------ 36 | # Node install 37 | FROM riscv_xpack_gcc_base_env AS riscv_xpack_gcc_node_env 38 | 39 | ARG NODE_VERSION 40 | ARG NVM_VERSION 41 | 42 | # Node is used to install xpack 43 | ENV NVM_DIR=/home/docker_user/.nvm 44 | RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh | bash 45 | 46 | RUN . "$NVM_DIR/nvm.sh" && nvm install ${NODE_VERSION} 47 | RUN . "$NVM_DIR/nvm.sh" && nvm use v${NODE_VERSION} 48 | RUN . "$NVM_DIR/nvm.sh" && nvm alias default v${NODE_VERSION} 49 | 50 | # Check it works 51 | ENV PATH="/home/docker_user/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}" 52 | RUN node --version 53 | RUN npm --version 54 | 55 | # ------------------------------------------------------------------------ 56 | # XPM install 57 | FROM riscv_xpack_gcc_node_env AS riscv_xpack_gcc_xpm_env 58 | 59 | ARG XPACK_GCC_VERSION 60 | ARG PACKAGE 61 | 62 | ENV XPACKS_REPO_FOLDER=/home/docker_user/.xpack/repos 63 | ENV XPACKS_SYSTEM_FOLDER=/home/docker_user/.xpack/system 64 | 65 | RUN npm install --global xpm@latest 66 | RUN xpm install --global --verbose @xpack-dev-tools/${PACKAGE}@${XPACK_GCC_VERSION} 67 | # ------------------------------------------------------------------------ 68 | # Just the embedded dev tools - no node or xpm 69 | 70 | FROM riscv_xpack_gcc_base_env AS riscv_xpack_gcc_dev_env 71 | 72 | ARG XPACK_GCC_VERSION 73 | ARG PACKAGE 74 | 75 | COPY --from=riscv_xpack_gcc_xpm_env /home/docker_user/.xpack/ /home/docker_user/.xpack/ 76 | 77 | ENV PATH=/home/docker_user/.xpack/repos/@xpack-dev-tools/${PACKAGE}/${XPACK_GCC_VERSION}/.content/bin:/bin/:/usr/bin 78 | 79 | RUN sudo ln -s /home/docker_user/.xpack/repos/@xpack-dev-tools/${PACKAGE}/${XPACK_GCC_VERSION}/.content /opt/riscv-none-embed 80 | 81 | RUN sudo mkdir /project && sudo chown docker_user /project 82 | WORKDIR /project 83 | -------------------------------------------------------------------------------- /examples/test-code-c/startup.c: -------------------------------------------------------------------------------- 1 | /* 2 | Simple C++ startup routine to setup CRT 3 | SPDX-License-Identifier: Unlicense 4 | 5 | (https://five-embeddev.com/ | http://www.shincbm.com/) 6 | 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | // Generic C function pointer. 13 | typedef void (*function_t)(); 14 | 15 | // These symbols are defined by the linker script. 16 | // See linker.lds 17 | extern void *metal_segment_bss_target_start; 18 | extern void *metal_segment_bss_target_end; 19 | extern const void *metal_segment_data_source_start; 20 | extern void *metal_segment_data_target_start; 21 | extern void *metal_segment_data_target_end; 22 | extern const void *metal_segment_itim_source_start; 23 | extern void *metal_segment_itim_target_start; 24 | extern void *metal_segment_itim_target_end; 25 | 26 | extern function_t __init_array_start[]; 27 | extern function_t __init_array_end[]; 28 | 29 | 30 | // This function will be placed by the linker script according to the section 31 | // Raw function 'called' by the CPU with no runtime. 32 | extern void _enter(void) __attribute__ ((naked, section(".text.metal.init.enter"))); 33 | 34 | // Entry and exit points as C functions. 35 | extern void _start(void) __attribute__ ((noreturn)); 36 | void _Exit(int exit_code) __attribute__ ((noreturn)); 37 | 38 | // Standard entry point, no arguments. 39 | extern int main(void); 40 | 41 | 42 | // The linker script will place this in the reset entry point. 43 | // It will be 'called' with no stack or C runtime configuration. 44 | // NOTE - this only supports a single hart. 45 | // tp will not be initialized 46 | void _enter(void) { 47 | // Setup SP and GP 48 | // The locations are defined in the linker script 49 | __asm__ volatile ( 50 | ".option push;" 51 | // The 'norelax' option is critical here. 52 | // Without 'norelax' the global pointer will 53 | // be loaded relative to the global pointer! 54 | ".option norelax;" 55 | "la gp, __global_pointer$;" 56 | ".option pop;" 57 | "la sp, _sp;" 58 | "jal zero, _start;" 59 | : /* output: none %0 */ 60 | : /* input: none */ 61 | : "gp"/* clobbers: none */); 62 | // This point will not be executed, _start() will be called with no return. 63 | } 64 | 65 | // At this point we have a stack and global poiner, but no access to global variables. 66 | void _start(void) { 67 | 68 | // Init memory regions 69 | // Clear the .bss section (global variables with no initial values) 70 | memset(metal_segment_bss_target_start, 71 | 0, 72 | (metal_segment_bss_target_end - metal_segment_bss_target_start)); 73 | 74 | // Initialize the .data section (global variables with initial values) 75 | memcpy(metal_segment_data_target_start, 76 | metal_segment_data_source_start, 77 | (metal_segment_data_target_end-metal_segment_data_target_start)); 78 | 79 | // Initialize the .itim section (code moved from flash to SRAM to improve performance) 80 | memcpy(metal_segment_itim_target_start, 81 | metal_segment_itim_source_start, 82 | (metal_segment_itim_target_start-metal_segment_itim_target_end)); 83 | 84 | // Call constructors 85 | for (unsigned int i=0; i< (__init_array_start-__init_array_end)/sizeof(function_t); i++) { 86 | __init_array_start[i](); 87 | } 88 | 89 | _Exit(main()); 90 | } 91 | 92 | // This should never be called. Busy loop with the CPU in idle state. 93 | void _Exit(int exit_code) { 94 | // Halt 95 | while (1) { 96 | __asm__ volatile ("wfi"); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /examples/test-code-c/riscv.cmake: -------------------------------------------------------------------------------- 1 | #include(CMakeForceCompiler) 2 | 3 | # usage 4 | # cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/rv32imac.cmake ../ 5 | 6 | # Look for GCC in path 7 | # https://xpack.github.io/riscv-none-embed-gcc/ 8 | FIND_FILE( RISCV_XPACK_GCC_COMPILER_EXE "riscv-none-elf-gcc.exe" PATHS ENV INCLUDE) 9 | FIND_FILE( RISCV_XPACK_GCC_COMPILER "riscv-none-elf-gcc" PATHS ENV INCLUDE) 10 | 11 | # Look for RISC-V github GCC 12 | # https://github.com/riscv/riscv-gnu-toolchain 13 | FIND_FILE( RISCV_XPACK_GCC_COMPILER_EXT "riscv32-unknown-elf-gcc.exe" PATHS ENV INCLUDE) 14 | FIND_FILE( RISCV_XPACK_GCC_COMPILER "riscv32-unknown-elf-gcc" PATHS ENV INCLUDE) 15 | 16 | # Select which is found 17 | if (EXISTS ${RISCV_XPACK_GCC_COMPILER}) 18 | set( RISCV_GCC_COMPILER ${RISCV_XPACK_GCC_COMPILER}) 19 | elseif (EXISTS ${RISCV_XPACK_GCC_COMPILER_EXE}) 20 | set( RISCV_GCC_COMPILER ${RISCV_XPACK_GCC_COMPILER_EXE}) 21 | elseif (EXISTS ${RISCV_GITHUB_GCC_COMPILER}) 22 | set( RISCV_GCC_COMPILER ${RISCV_GITHUB_GCC_COMPILER}) 23 | elseif (EXISTS ${RISCV_GITHUB_GCC_COMPILER_EXE}) 24 | set( RISCV_GCC_COMPILER ${RISCV_GITHUB_GCC_COMPILER_EXE}) 25 | else() 26 | message(FATAL_ERROR "RISC-V GCC not found. ${RISCV_GITHUB_GCC_COMPILER} ${RISCV_XPACK_GCC_COMPILER} ${RISCV_GITHUB_GCC_COMPILER_EXE} ${RISCV_XPACK_GCC_COMPILER_EXE}") 27 | endif() 28 | 29 | message( "RISC-V GCC found: ${RISCV_GCC_COMPILER}") 30 | 31 | get_filename_component(RISCV_TOOLCHAIN_BIN_PATH ${RISCV_GCC_COMPILER} DIRECTORY) 32 | get_filename_component(RISCV_TOOLCHAIN_BIN_GCC ${RISCV_GCC_COMPILER} NAME_WE) 33 | get_filename_component(RISCV_TOOLCHAIN_BIN_EXT ${RISCV_GCC_COMPILER} EXT) 34 | 35 | message( "RISC-V GCC Path: ${RISCV_TOOLCHAIN_BIN_PATH}" ) 36 | 37 | STRING(REGEX REPLACE "\-gcc" "-" CROSS_COMPILE ${RISCV_TOOLCHAIN_BIN_GCC}) 38 | message( "RISC-V Cross Compile: ${CROSS_COMPILE}" ) 39 | 40 | # The Generic system name is used for embedded targets (targets without OS) in 41 | # CMake 42 | set( CMAKE_SYSTEM_NAME Generic ) 43 | set( CMAKE_SYSTEM_PROCESSOR rv32imac_zicsr ) 44 | set( CMAKE_EXECUTABLE_SUFFIX ".elf") 45 | 46 | # specify the cross compiler. We force the compiler so that CMake doesn't 47 | # attempt to build a simple test program as this will fail without us using 48 | # the -nostartfiles option on the command line 49 | #CMAKE_FORCE_C_COMPILER( "${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}gcc${RISCV_TOOLCHAIN_BIN_EXT}" GNU ) 50 | #CMAKE_FORCE_CXX_COMPILER( "${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}g++${RISCV_TOOLCHAIN_BIN_EXT}" GNU ) 51 | set(CMAKE_ASM_COMPILER {CROSS_COMPILE}gcc ) 52 | set(CMAKE_AR ${CROSS_COMPILE}ar) 53 | set(CMAKE_ASM_COMPILER ${CROSS_COMPILE}gcc) 54 | set(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc) 55 | set(CMAKE_CXX_COMPILER ${CROSS_COMPILE}g++) 56 | 57 | # We must set the OBJCOPY setting into cache so that it's available to the 58 | # whole project. Otherwise, this does not get set into the CACHE and therefore 59 | # the build doesn't know what the OBJCOPY filepath is 60 | set( CMAKE_OBJCOPY ${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}objcopy 61 | CACHE FILEPATH "The toolchain objcopy command " FORCE ) 62 | 63 | set( CMAKE_OBJDUMP ${RISCV_TOOLCHAIN_BIN_PATH}/${CROSS_COMPILE}objdump 64 | CACHE FILEPATH "The toolchain objdump command " FORCE ) 65 | 66 | # Set the common build flags 67 | 68 | # Set the CMAKE C flags (which should also be used by the assembler! 69 | set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g" ) 70 | set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR}" ) 71 | 72 | set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) 73 | set( CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) 74 | set( CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "" ) 75 | set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR} -nostartfiles " ) 76 | 77 | -------------------------------------------------------------------------------- /examples/test-code-c/linker.lds: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2020 SiFive Inc. */ 2 | /* SPDX-License-Identifier: Apache-2.0 */ 3 | OUTPUT_ARCH("riscv") 4 | 5 | /* Default Linker Script 6 | * 7 | * This is the default linker script for all Freedom Metal applications. 8 | */ 9 | 10 | ENTRY(_enter) 11 | 12 | MEMORY 13 | { 14 | itim (airwx) : ORIGIN = 0x8000000, LENGTH = 0x2000 15 | ram (arw!xi) : ORIGIN = 0x80000000, LENGTH = 0x4000 16 | rom (irx!wa) : ORIGIN = 0x20010000, LENGTH = 0x6a120 17 | } 18 | 19 | PHDRS 20 | { 21 | rom PT_LOAD; 22 | ram_init PT_LOAD; 23 | tls PT_TLS; 24 | ram PT_LOAD; 25 | itim_init PT_LOAD; 26 | text PT_LOAD; 27 | lim_init PT_LOAD; 28 | } 29 | 30 | SECTIONS 31 | { 32 | /* Each hart is allocated its own stack of size __stack_size. This value 33 | * can be overriden at build-time by adding the following to CFLAGS: 34 | * 35 | * -Xlinker --defsym=__stack_size=0xf00 36 | * 37 | * where 0xf00 can be replaced with a multiple of 16 of your choice. 38 | * 39 | * __stack_size is PROVIDE-ed as a symbol so that initialization code 40 | * initializes the stack pointers for each hart at the right offset from 41 | * the _sp symbol. 42 | */ 43 | __stack_size = DEFINED(__stack_size) ? __stack_size : 0x400; 44 | PROVIDE(__stack_size = __stack_size); 45 | 46 | /* The size of the heap can be overriden at build-time by adding the 47 | * following to CFLAGS: 48 | * 49 | * -Xlinker --defsym=__heap_size=0xf00 50 | * 51 | * where 0xf00 can be replaced with the value of your choice. 52 | * 53 | * Altertatively, the heap can be grown to fill the entire remaining region 54 | * of RAM by adding the following to CFLAGS: 55 | * 56 | * -Xlinker --defsym=__heap_max=1 57 | * 58 | * Note that depending on the memory layout, the bitness (32/64bit) of the 59 | * target, and the code model in use, this might cause a relocation error. 60 | */ 61 | __heap_size = DEFINED(__heap_size) ? __heap_size : 0x800; 62 | 63 | /* The boot hart sets which hart runs the pre-main initialization routines, 64 | * including copying .data into RAM, zeroing the BSS region, running 65 | * constructors, etc. After initialization, the boot hart is also the only 66 | * hart which runs application code unless the application overrides the 67 | * secondary_main() function to start execution on secondary harts. 68 | */ 69 | PROVIDE(__metal_boot_hart = 0); 70 | 71 | /* The chicken bit is used by pre-main initialization to enable/disable 72 | * certain core features */ 73 | PROVIDE(__metal_chicken_bit = 1); 74 | 75 | /* The memory_ecc_scrub bit is used by _entry code to enable/disable 76 | * memories scrubbing to zero */ 77 | PROVIDE(__metal_eccscrub_bit = 0); 78 | 79 | /* The RAM memories map for ECC scrubbing */ 80 | PROVIDE( metal_dtim_0_memory_start = 0x80000000 ); 81 | PROVIDE( metal_dtim_0_memory_end = 0x80000000 + 0x4000 ); 82 | PROVIDE( metal_itim_0_memory_start = 0x8000000 ); 83 | PROVIDE( metal_itim_0_memory_end = 0x8000000 + 0x2000 ); 84 | 85 | /* ROM SECTION 86 | * 87 | * The following sections contain data which lives in read-only memory, if 88 | * such memory is present in the design, for the entire duration of program 89 | * execution. 90 | */ 91 | 92 | .init : { 93 | /* The _enter symbol is placed in the .text.metal.init.enter section 94 | * and must be placed at the beginning of the program */ 95 | KEEP (*(.text.metal.init.enter)) 96 | KEEP (*(.text.metal.init.*)) 97 | KEEP (*(SORT_NONE(.init))) 98 | KEEP (*(.text.libgloss.start)) 99 | } >rom :rom 100 | 101 | .fini : { 102 | KEEP (*(SORT_NONE(.fini))) 103 | } >rom :rom 104 | 105 | .preinit_array : ALIGN(8) { 106 | PROVIDE_HIDDEN (__preinit_array_start = .); 107 | KEEP (*(.preinit_array)) 108 | PROVIDE_HIDDEN (__preinit_array_end = .); 109 | } >rom :rom 110 | 111 | .init_array : ALIGN(8) { 112 | PROVIDE_HIDDEN (__init_array_start = .); 113 | KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) 114 | KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) 115 | PROVIDE_HIDDEN (__init_array_end = .); 116 | PROVIDE_HIDDEN ( metal_constructors_start = .); 117 | KEEP (*(SORT_BY_INIT_PRIORITY(.metal.init_array.*))); 118 | KEEP (*(.metal.init_array)); 119 | PROVIDE_HIDDEN ( metal_constructors_end = .); 120 | } >rom :rom 121 | 122 | .fini_array : ALIGN(8) { 123 | PROVIDE_HIDDEN (__fini_array_start = .); 124 | KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) 125 | KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) 126 | PROVIDE_HIDDEN (__fini_array_end = .); 127 | PROVIDE_HIDDEN ( metal_destructors_start = .); 128 | KEEP (*(SORT_BY_INIT_PRIORITY(.metal.fini_array.*))); 129 | KEEP (*(.metal.fini_array)); 130 | PROVIDE_HIDDEN ( metal_destructors_end = .); 131 | } >rom :rom 132 | 133 | 134 | 135 | .ctors : { 136 | KEEP (*crtbegin.o(.ctors)) 137 | KEEP (*crtbegin?.o(.ctors)) 138 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) 139 | KEEP (*(SORT(.ctors.*))) 140 | KEEP (*(.ctors)) 141 | KEEP (*(.metal.ctors .metal.ctors.*)) 142 | } >rom :rom 143 | 144 | .dtors : { 145 | KEEP (*crtbegin.o(.dtors)) 146 | KEEP (*crtbegin?.o(.dtors)) 147 | KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) 148 | KEEP (*(SORT(.dtors.*))) 149 | KEEP (*(.dtors)) 150 | KEEP (*(.metal.dtors .metal.dtors.*)) 151 | } >rom : rom 152 | 153 | .rodata : { 154 | *(.rdata) 155 | *(.rodata .rodata.*) 156 | *(.gnu.linkonce.r.*) 157 | . = ALIGN(8); 158 | *(.srodata.cst16) 159 | *(.srodata.cst8) 160 | *(.srodata.cst4) 161 | *(.srodata.cst2) 162 | *(.srodata .srodata.*) 163 | } >rom :rom 164 | 165 | /* ITIM SECTION 166 | * 167 | * The following sections contain data which is copied from read-only 168 | * memory into an instruction tightly-integrated memory (ITIM), if one 169 | * is present in the design, during pre-main program initialization. 170 | * 171 | * Generally, the data copied into the ITIM should be performance-critical 172 | * functions which benefit from low instruction-fetch latency. 173 | */ 174 | 175 | .itim : ALIGN(8) { 176 | *(.itim .itim.*) 177 | } >itim AT>rom :itim_init 178 | 179 | PROVIDE( metal_segment_itim_source_start = LOADADDR(.itim) ); 180 | PROVIDE( metal_segment_itim_target_start = ADDR(.itim) ); 181 | PROVIDE( metal_segment_itim_target_end = ADDR(.itim) + SIZEOF(.itim) ); 182 | 183 | /* LIM SECTION 184 | * 185 | * The following sections contain data which is copied from read-only 186 | * memory into a loosely integrated memory (LIM), which is shared with L2 187 | * cache, during pre-main program initialization. 188 | * 189 | * Generally, the data copied into the LIM should be performance-critical 190 | * functions which benefit from low instruction-fetch latency. 191 | */ 192 | 193 | .lim : ALIGN(8) { 194 | *(.lim .lim.*) 195 | } >ram AT>rom :lim_init 196 | 197 | PROVIDE( metal_segment_lim_source_start = LOADADDR(.lim) ); 198 | PROVIDE( metal_segment_lim_target_start = ADDR(.lim) ); 199 | PROVIDE( metal_segment_lim_target_end = ADDR(.lim) + SIZEOF(.lim) ); 200 | 201 | /* TEXT SECTION 202 | * 203 | * The following section contains the code of the program, excluding 204 | * everything that's been allocated into the ITIM/LIM already 205 | */ 206 | 207 | .text : { 208 | *(.text.unlikely .text.unlikely.*) 209 | *(.text.startup .text.startup.*) 210 | *(.text .text.*) 211 | *(.gnu.linkonce.t.*) 212 | } >rom :text 213 | 214 | /* RAM SECTION 215 | * 216 | * The following sections contain data which is copied from read-only 217 | * memory into a read-write-capable memory such as data tightly-integrated 218 | * memory (DTIM) or another main memory, as well as the BSS, stack, and 219 | * heap. 220 | * 221 | * You might notice that .data, .tdata, .tbss, .tbss_space, and .bss all 222 | * have an apparently unnecessary ALIGN at their top. This is because 223 | * the implementation of _start in Freedom Metal libgloss depends on the 224 | * ADDR and LOADADDR being 8-byte aligned. 225 | */ 226 | 227 | .data : ALIGN(8) { 228 | *(.data .data.*) 229 | *(.gnu.linkonce.d.*) 230 | . = ALIGN(8); 231 | PROVIDE( __global_pointer$ = . + 0x800 ); 232 | *(.sdata .sdata.* .sdata2.*) 233 | *(.gnu.linkonce.s.*) 234 | } >ram AT>rom :ram_init 235 | 236 | .tdata : ALIGN(8) { 237 | PROVIDE( __tls_base = . ); 238 | *(.tdata .tdata.* .gnu.linkonce.td.*) 239 | } >ram AT>rom :tls :ram_init 240 | 241 | PROVIDE( __tdata_source = LOADADDR(.tdata) ); 242 | PROVIDE( __tdata_size = SIZEOF(.tdata) ); 243 | 244 | PROVIDE( metal_segment_data_source_start = LOADADDR(.data) ); 245 | PROVIDE( metal_segment_data_target_start = ADDR(.data) ); 246 | PROVIDE( metal_segment_data_target_end = ADDR(.tdata) + SIZEOF(.tdata) ); 247 | 248 | .tbss : ALIGN(8) { 249 | *(.tbss .tbss.* .gnu.linkonce.tb.*) 250 | *(.tcommon .tcommon.*) 251 | PROVIDE( __tls_end = . ); 252 | } >ram AT>ram :tls :ram 253 | PROVIDE( __tbss_size = SIZEOF(.tbss) ); 254 | PROVIDE( __tls_size = __tls_end - __tls_base ); 255 | 256 | .tbss_space : ALIGN(8) { 257 | . = . + __tbss_size; 258 | } >ram :ram 259 | 260 | .bss (NOLOAD): ALIGN(8) { 261 | *(.sbss*) 262 | *(.gnu.linkonce.sb.*) 263 | *(.bss .bss.*) 264 | *(.gnu.linkonce.b.*) 265 | *(COMMON) 266 | } >ram :ram 267 | 268 | PROVIDE( metal_segment_bss_source_start = LOADADDR(.tbss) ); 269 | PROVIDE( metal_segment_bss_target_start = ADDR(.tbss) ); 270 | PROVIDE( metal_segment_bss_target_end = ADDR(.bss) + SIZEOF(.bss) ); 271 | 272 | 273 | 274 | .stack (NOLOAD) : ALIGN(16) { 275 | PROVIDE(metal_segment_stack_begin = .); 276 | . += __stack_size; /* Hart 0 */ 277 | PROVIDE( _sp = . ); 278 | PROVIDE(metal_segment_stack_end = .); 279 | } >ram :ram 280 | 281 | .heap (NOLOAD) : ALIGN(8) { 282 | PROVIDE( __end = . ); 283 | PROVIDE( __heap_start = . ); 284 | PROVIDE( metal_segment_heap_target_start = . ); 285 | /* If __heap_max is defined, grow the heap to use the rest of RAM, 286 | * otherwise set the heap size to __heap_size */ 287 | . = DEFINED(__heap_max) ? MIN( LENGTH(ram) - ( . - ORIGIN(ram)) , 0x10000000) : __heap_size; 288 | PROVIDE( metal_segment_heap_target_end = . ); 289 | PROVIDE( _heap_end = . ); 290 | PROVIDE( __heap_end = . ); 291 | } >ram :ram 292 | 293 | /* C++ exception handling information is 294 | * not useful with our current runtime environment, 295 | * and it consumes flash space. Discard it until 296 | * we have something that can use it 297 | */ 298 | /DISCARD/ : { 299 | *(.eh_frame .eh_frame.*) 300 | } 301 | } 302 | --------------------------------------------------------------------------------