From 1666eab02b77da43bef5150afd8e30000ca1a807 Mon Sep 17 00:00:00 2001 From: cassuto Date: Thu, 23 Apr 2026 22:33:50 -0400 Subject: [PATCH 1/2] add regression test --- tests/regression/Makefile | 4 ++ tests/regression/jalr/Makefile | 21 ++++++++ tests/regression/jalr/common.h | 8 +++ tests/regression/jalr/kernel.cpp | 52 +++++++++++++++++++ tests/regression/jalr/main.cpp | 87 ++++++++++++++++++++++++++++++++ tests/regression/jalr/start.S | 24 +++++++++ 6 files changed, 196 insertions(+) create mode 100644 tests/regression/jalr/Makefile create mode 100644 tests/regression/jalr/common.h create mode 100644 tests/regression/jalr/kernel.cpp create mode 100644 tests/regression/jalr/main.cpp create mode 100644 tests/regression/jalr/start.S diff --git a/tests/regression/Makefile b/tests/regression/Makefile index d08a48f3b..54fdad66d 100644 --- a/tests/regression/Makefile +++ b/tests/regression/Makefile @@ -5,6 +5,7 @@ NP ?= 4 all: $(MAKE) -C basic + $(MAKE) -C jalr $(MAKE) -C demo $(MAKE) -C dogfood $(MAKE) -C dropout @@ -36,6 +37,7 @@ all-mpi: run-simx: $(MAKE) -C basic run-simx + $(MAKE) -C jalr run-simx $(MAKE) -C demo run-simx $(MAKE) -C dogfood run-simx $(MAKE) -C dropout run-simx @@ -67,6 +69,7 @@ run-simx-mpi: run-rtlsim: $(MAKE) -C basic run-rtlsim + $(MAKE) -C jalr run-rtlsim $(MAKE) -C demo run-rtlsim $(MAKE) -C dogfood run-rtlsim $(MAKE) -C dropout run-rtlsim @@ -88,6 +91,7 @@ run-rtlsim: clean: $(MAKE) -C basic clean + $(MAKE) -C jalr clean $(MAKE) -C demo clean $(MAKE) -C dogfood clean $(MAKE) -C dropout clean diff --git a/tests/regression/jalr/Makefile b/tests/regression/jalr/Makefile new file mode 100644 index 000000000..70710e2fe --- /dev/null +++ b/tests/regression/jalr/Makefile @@ -0,0 +1,21 @@ +ROOT_DIR := $(realpath ../../..) +include $(ROOT_DIR)/config.mk + +PROJECT := jalr + +SRC_DIR := $(VORTEX_HOME)/tests/regression/$(PROJECT) + +SRCS := $(SRC_DIR)/main.cpp + +VX_SRCS := $(SRC_DIR)/kernel.cpp $(VORTEX_HOME)/kernel/src/vx_perf.c $(SRC_DIR)/start.S + +OPTS ?= + +include ../common.mk + +VX_LDFLAGS = -Wl,-Bstatic,--gc-sections,-T,$(VORTEX_HOME)/kernel/scripts/link$(XLEN).ld,--defsym=STARTUP_ADDR=$(STARTUP_ADDR) + +VX_CC = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-gcc +VX_CXX = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-g++ +VX_DP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objdump +VX_CP = $(RISCV_TOOLCHAIN_PATH)/bin/$(RISCV_PREFIX)-objcopy diff --git a/tests/regression/jalr/common.h b/tests/regression/jalr/common.h new file mode 100644 index 000000000..91c2ca32b --- /dev/null +++ b/tests/regression/jalr/common.h @@ -0,0 +1,8 @@ +#ifndef _COMMON_H_ +#define _COMMON_H_ + +typedef struct { + uint64_t dst_addr; +} kernel_arg_t; + +#endif diff --git a/tests/regression/jalr/kernel.cpp b/tests/regression/jalr/kernel.cpp new file mode 100644 index 000000000..7455ab9b6 --- /dev/null +++ b/tests/regression/jalr/kernel.cpp @@ -0,0 +1,52 @@ +#include +#include "common.h" + +int main() { + kernel_arg_t* __UNIFORM__ arg = (kernel_arg_t*)csr_read(VX_CSR_MSCRATCH); + + if (vx_warp_id() != 0 || vx_thread_id() != 0) + return 0; + + uint32_t value = 0; + asm volatile( + // x1 is prepared so that the misaligned decode path can immediately + // execute a valid JALR to label 3 and produce a deterministic failure + // value instead of aborting in the decoder. + "la x1, 3f\n" + // 1744 is chosen to match the immediate embedded in the overlapped + // misaligned instruction below: jalr x0, -1744(x1). + "addi x1, x1, 1744\n" + "la t0, 1f\n" + // Add 1 on purpose. A correct JALR implementation must clear bit 0 and + // land at 1f. An incorrect implementation enters at 1f + 1 instead. + "addi t0, t0, 1\n" + "jalr x0, t0, 0\n" + ".balign 4\n" + "1:\n" + // 0x00806713 is a hand-picked overlapped instruction word: + // - from the aligned entry at 1f it decodes as: ori x14, x0, 8 + // - from the misaligned entry at 1f + 1 it decodes as: + // jalr x0, -1744(x1) + // + // That lets both fixed and unfixed builds decode valid instructions while + // still producing different results. + ".4byte 0x00806713\n" + // This is the next aligned instruction after the pass-path overlap word. + ".4byte 0x00000093\n" + "j 4f\n" + "3:\n" + // Fail signature used when JALR does not clear bit 0. + "li %[value], 0x2468ace0\n" + "j 5f\n" + "4:\n" + // Pass signature used when JALR correctly clears bit 0. + "li %[value], 0x13579bdf\n" + "5:\n" + : [value] "=r" (value) + : + : "x1", "t0", "x14"); + + uint32_t* dst_ptr = (uint32_t*)arg->dst_addr; + dst_ptr[vx_core_id()] = value; + return 0; +} diff --git a/tests/regression/jalr/main.cpp b/tests/regression/jalr/main.cpp new file mode 100644 index 000000000..c5cfa71f2 --- /dev/null +++ b/tests/regression/jalr/main.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include +#include "common.h" + +#define RT_CHECK(_expr) \ + do { \ + int _ret = _expr; \ + if (0 == _ret) \ + break; \ + printf("Error: '%s' returned %d!\n", #_expr, (int)_ret); \ + cleanup(); \ + exit(-1); \ + } while (false) + +static constexpr uint32_t kPassValue = 0x13579bdf; + +const char* kernel_file = "kernel.vxbin"; + +vx_device_h device = nullptr; +vx_buffer_h dst_buffer = nullptr; +vx_buffer_h krnl_buffer = nullptr; +vx_buffer_h args_buffer = nullptr; +kernel_arg_t kernel_arg = {}; + +void cleanup() { + if (device) { + vx_mem_free(dst_buffer); + vx_mem_free(krnl_buffer); + vx_mem_free(args_buffer); + vx_dev_close(device); + } +} + +int main() { + std::cout << "open device connection" << std::endl; + RT_CHECK(vx_dev_open(&device)); + + uint64_t num_cores = 0; + RT_CHECK(vx_dev_caps(device, VX_CAPS_NUM_CORES, &num_cores)); + + uint32_t buf_size = num_cores * sizeof(uint32_t); + std::vector h_dst(num_cores, 0); + + std::cout << "allocate device memory" << std::endl; + RT_CHECK(vx_mem_alloc(device, buf_size, VX_MEM_WRITE, &dst_buffer)); + RT_CHECK(vx_mem_address(dst_buffer, &kernel_arg.dst_addr)); + RT_CHECK(vx_copy_to_dev(dst_buffer, h_dst.data(), 0, buf_size)); + + std::cout << "upload kernel binary" << std::endl; + RT_CHECK(vx_upload_kernel_file(device, kernel_file, &krnl_buffer)); + + std::cout << "upload kernel argument" << std::endl; + RT_CHECK(vx_upload_bytes(device, &kernel_arg, sizeof(kernel_arg_t), &args_buffer)); + + std::cout << "start device" << std::endl; + RT_CHECK(vx_start(device, krnl_buffer, args_buffer)); + RT_CHECK(vx_ready_wait(device, VX_MAX_TIMEOUT)); + + std::cout << "download destination buffer" << std::endl; + RT_CHECK(vx_copy_from_dev(h_dst.data(), dst_buffer, 0, buf_size)); + + int errors = 0; + for (uint64_t i = 0; i < num_cores; ++i) { + if (h_dst[i] != kPassValue) { + std::cout << "error at core " << std::dec << i + << ": actual=0x" << std::hex << h_dst[i] + << ", expected=0x" << kPassValue << std::endl; + ++errors; + } + } + + std::cout << "cleanup" << std::endl; + cleanup(); + + if (errors != 0) { + std::cout << "FAILED!" << std::endl; + return errors; + } + + std::cout << "PASSED!" << std::endl; + return 0; +} diff --git a/tests/regression/jalr/start.S b/tests/regression/jalr/start.S new file mode 100644 index 000000000..87fd88c70 --- /dev/null +++ b/tests/regression/jalr/start.S @@ -0,0 +1,24 @@ +// Copyright © 2019-2023 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +.section .init, "ax" +.global _start +.type _start, @function +_start: + call main + call vx_perf_dump + .insn r 0x0b, 0, 0, x0, x0, x0 +.size _start, .-_start From 926828e12f482a0b1e3f1f6ab13c07745855a354 Mon Sep 17 00:00:00 2001 From: cassuto Date: Thu, 23 Apr 2026 22:34:15 -0400 Subject: [PATCH 2/2] Fix simx jalr target alignment --- sim/simx/execute.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sim/simx/execute.cpp b/sim/simx/execute.cpp index ba36bca15..c24e8d2c8 100644 --- a/sim/simx/execute.cpp +++ b/sim/simx/execute.cpp @@ -466,7 +466,7 @@ instr_trace_t* Emulator::execute(const Instr &instr, uint32_t wid) { continue; rd_data[t].i = next_pc; } - next_pc = rs1_data[thread_last].i + offset; + next_pc = (rs1_data[thread_last].u + offset) & ~Word(1); trace->fetch_stall = true; rd_write = true; } break; @@ -1562,4 +1562,4 @@ instr_trace_t* Emulator::execute(const Instr &instr, uint32_t wid) { } return trace; -} \ No newline at end of file +}