Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions .github/workflows/make-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,26 @@ jobs:

steps:
- uses: actions/checkout@v5
- name: make
run: make
- name: make test
- name: Setup Node.js for xpm
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install xpm and riscv-none-elf toolchain
shell: bash
run: |
set -euox pipefail
npm install --location=global xpm@latest
mkdir -p .ci-xpm
printf '%s\n' '{' \
' "name": "vbo-ci-xpm",' \
' "version": "0.0.0",' \
' "private": true,' \
' "xpack": {}' \
'}' > .ci-xpm/package.json
( cd .ci-xpm && xpm install @xpack-dev-tools/riscv-none-elf-gcc@14.2.0-3.1 --verbose )
TOOLCHAIN_BIN="$HOME/.local/xPacks/@xpack-dev-tools/riscv-none-elf-gcc/14.2.0-3.1/.content/bin"
echo "$TOOLCHAIN_BIN" >> "$GITHUB_PATH"
echo "RV_PREFIX=riscv-none-elf-" >> "$GITHUB_ENV"
"$TOOLCHAIN_BIN/riscv-none-elf-gcc" --version
- name: make test # test incorporates build into it
run: make test
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,10 @@ test/**/*

*.bin
*.app
*.img
*.img

# latex
paper/**/*
!paper/**/*.tex
!paper/**/*.bib
!paper/**/*.pdf
37 changes: 17 additions & 20 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ SRC_MAIN = src/main.c $(SRC_COMMON)

FLAGS = -Wall -Wextra -Werror -g -std=c11 -pedantic

# RISC-V cross toolchain (see docs/compiler.md)
# RISC-V cross toolchain (see the wiki)
RV_PREFIX ?= ~/.local/xPacks/riscv-none-elf-gcc/xpack-riscv-none-elf-gcc-14.2.0-3/bin/riscv-none-elf-
RV_GCC := $(RV_PREFIX)gcc
RV_OBJCOPY:= $(RV_PREFIX)objcopy
Expand All @@ -27,7 +27,7 @@ ORIGIN ?= 0x3000

define ensure_rv_toolchain
@if ! command -v $(RV_GCC) >/dev/null 2>&1; then \
echo "[Make] Missing toolchain: $(RV_GCC). See docs/compiler.md to install and add to PATH."; \
echo "[Make] Missing toolchain: $(RV_GCC). See the wiki for info on how to install and add to PATH."; \
exit 1; \
fi
@if ! command -v $(RV_OBJCOPY) >/dev/null 2>&1; then \
Expand All @@ -44,7 +44,7 @@ endif

TEST_DIR = test

.PHONY: all build clean test distclean app image embed run demo clean-app test-integration test-all help
.PHONY: all build clean test app image embed run demo distclean test-integration test-all help

all: build

Expand All @@ -61,16 +61,26 @@ clean:
rm -f $(TEST_DIR)/test_utils
rm -f images/vbo_image.o
rm -rf $(OUT_DIR)

distclean: clean

test:
test: build
$(CC) $(INC) $(TEST_DIR)/test_utils.c src/utils.c src/riscv32i.c -o $(TEST_DIR)/test_utils $(FLAGS)
$(TEST_DIR)/test_utils
rm $(TEST_DIR)/test_utils

# Run both unit and integration tests (integration is skipped if toolchain is missing)
test-all: test test-integration
$(CC) $(INC) $(TEST_DIR)/test_riscv32i.c src/riscv32i.c -o $(TEST_DIR)/test_riscv32i $(FLAGS)
$(TEST_DIR)/test_riscv32i
rm $(TEST_DIR)/test_riscv32i

@if ! command -v $(RV_GCC) >/dev/null 2>&1 || ! command -v $(RV_OBJCOPY) >/dev/null 2>&1; then \
echo "[Test] Skipping integration test (toolchain not found). See the wiki"; \
exit 0; \
fi
@$(MAKE) --no-print-directory image
@out=$$($(BIN) $(APP_IMG)); echo "$$out" | grep -q "Hello from RV32I VM" && echo "OK" || (echo "FAIL"; exit 1)




# --- App build pipeline ---

Expand Down Expand Up @@ -104,19 +114,6 @@ run: build image

demo: embed run

clean-app:
rm -rf $(OUT_DIR)

# Integration test (optional): requires toolchain, builds hello and checks output
test-integration: build
@if ! command -v $(RV_GCC) >/dev/null 2>&1 || ! command -v $(RV_OBJCOPY) >/dev/null 2>&1; then \
echo "[Test] Skipping integration test (toolchain not found). See docs/compiler.md"; \
exit 0; \
fi
@$(MAKE) --no-print-directory image
@echo "[Test] Running integration test (hello)"
@out=$$($(BIN) $(APP_IMG)); echo "$$out" | grep -q "Hello from RV32I VM" && echo "[Test] OK" || (echo "[Test] FAIL"; exit 1)

help:
@echo "Targets:"
@echo " build - Build the VM"
Expand Down
66 changes: 33 additions & 33 deletions include/riscv32i.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ static inline int32_t rv32i_sext(uint32_t val, int bits) {


// define instructions
void exec_riscv32i(uint32_t instruction);
void exec_rv32i(uint32_t instruction);

// functions for all instructions, in the format:
// void exec_riscv32i_<mnemonic>(uint32_t instruction);
// void exec_rv32i_<mnemonic>(uint32_t instruction);

/* canonical order:
addi, slti[u], andi, ori, xori, slli, srli, srai, lui, auipc, // integer register-immediate
Expand Down Expand Up @@ -171,46 +171,46 @@ enum


// integer register-immediate
void exec_riscv32i_addi(uint32_t instruction);
void exec_riscv32i_slti(uint32_t instruction);
void exec_riscv32i_andi(uint32_t instruction);
void exec_riscv32i_ori(uint32_t instruction);
void exec_riscv32i_xori(uint32_t instruction);
void exec_riscv32i_slli(uint32_t instruction);
void exec_riscv32i_srli_srai(uint32_t instruction);
void exec_riscv32i_lui(uint32_t instruction);
void exec_riscv32i_auipc(uint32_t instruction);
void exec_riscv32i_sltiu(uint32_t instruction);
void exec_rv32i_addi(uint32_t instruction);
void exec_rv32i_slti(uint32_t instruction);
void exec_rv32i_andi(uint32_t instruction);
void exec_rv32i_ori(uint32_t instruction);
void exec_rv32i_xori(uint32_t instruction);
void exec_rv32i_slli(uint32_t instruction);
void exec_rv32i_srli_srai(uint32_t instruction);
void exec_rv32i_lui(uint32_t instruction);
void exec_rv32i_auipc(uint32_t instruction);
void exec_rv32i_sltiu(uint32_t instruction);
// integer register-register
void exec_riscv32i_add_sub(uint32_t instruction);
void exec_riscv32i_slt(uint32_t instruction);
void exec_riscv32i_sltu(uint32_t instruction);
void exec_riscv32i_and(uint32_t instruction);
void exec_riscv32i_or(uint32_t instruction);
void exec_riscv32i_xor(uint32_t instruction);
void exec_riscv32i_sll(uint32_t instruction);
void exec_riscv32i_srl_sra(uint32_t instruction);
void exec_rv32i_add_sub(uint32_t instruction);
void exec_rv32i_slt(uint32_t instruction);
void exec_rv32i_sltu(uint32_t instruction);
void exec_rv32i_and(uint32_t instruction);
void exec_rv32i_or(uint32_t instruction);
void exec_rv32i_xor(uint32_t instruction);
void exec_rv32i_sll(uint32_t instruction);
void exec_rv32i_srl_sra(uint32_t instruction);
// unconditional jumps
void exec_riscv32i_jal(uint32_t instruction);
void exec_riscv32i_jalr(uint32_t instruction);
void exec_rv32i_jal(uint32_t instruction);
void exec_rv32i_jalr(uint32_t instruction);
// conditional branches
void exec_riscv32i_beq(uint32_t instruction);
void exec_riscv32i_bne(uint32_t instruction);
void exec_riscv32i_blt(uint32_t instruction);
void exec_riscv32i_bge(uint32_t instruction);
void exec_riscv32i_bltu(uint32_t instruction);
void exec_riscv32i_bgeu(uint32_t instruction);
void exec_rv32i_beq(uint32_t instruction);
void exec_rv32i_bne(uint32_t instruction);
void exec_rv32i_blt(uint32_t instruction);
void exec_rv32i_bge(uint32_t instruction);
void exec_rv32i_bltu(uint32_t instruction);
void exec_rv32i_bgeu(uint32_t instruction);
// load and store
void exec_riscv32i_load(uint32_t instruction);
void exec_riscv32i_store(uint32_t instruction);
void exec_rv32i_load(uint32_t instruction);
void exec_rv32i_store(uint32_t instruction);
// memory ordering
void exec_riscv32i_fence(uint32_t instruction);
void exec_rv32i_fence(uint32_t instruction);
// environment call and breakpoints
void exec_riscv32i_system(uint32_t instruction);
void exec_rv32i_system(uint32_t instruction);


// error handling
void exec_riscv32i_bad_opcode(uint32_t instruction);
void exec_rv32i_bad_opcode(uint32_t instruction);

//

Expand Down
2 changes: 2 additions & 0 deletions include/rv32_syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// Each wrapper issues an ecall with a7=syscall number and returns a0.
// On error, the return value is a negative errno (Linux convention).

// ? for a real-world use, it'd be much more efficient to implement a c library (newlib?)

#ifndef RV32_SYSCALLS_H
#define RV32_SYSCALLS_H

Expand Down
2 changes: 1 addition & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ int main(int argc, const char* argv[])
break;
}
rv32i_reg[pc] += 4; // advance to next 32-bit instruction
exec_riscv32i(instr);
exec_rv32i(instr);
}
return 0;
}
Loading