CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
158 lines
5.1 KiB
C++
158 lines
5.1 KiB
C++
// Copyright (c) 2025 Advanced Micro Devices, Inc.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "rocjitsu/vm/risc_v/hart.h"
|
|
#include "simdojo/sim/clock_domain.h"
|
|
#include "simdojo/sim/component.h"
|
|
#include "simdojo/sim/simulation.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
|
|
namespace {
|
|
|
|
/// Helper: build a single-hart topology, load a program, and run it.
|
|
class RvSimTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
simdojo::SimulationEngine::Config config{};
|
|
config.max_ticks = 1000;
|
|
config.num_threads = 1;
|
|
engine_ = std::make_unique<simdojo::SimulationEngine>(config);
|
|
|
|
auto *clk = engine_->topology().add_clock_domain("core_clk",
|
|
/*frequency_hz=*/simdojo::TICKS_PER_SECOND);
|
|
|
|
auto root_ptr = std::make_unique<simdojo::CompositeComponent>("soc");
|
|
auto hart_ptr = std::make_unique<rocjitsu::risc_v::Hart>("hart0", *clk);
|
|
hart_ = static_cast<rocjitsu::risc_v::Hart *>(root_ptr->add_child(std::move(hart_ptr)));
|
|
|
|
engine_->topology().set_root(std::move(root_ptr));
|
|
engine_->create();
|
|
}
|
|
|
|
void load_and_run(const uint32_t *program, size_t num_words, uint64_t base_addr = 0) {
|
|
hart_->memory().load_image(reinterpret_cast<const uint8_t *>(program),
|
|
num_words * sizeof(uint32_t), base_addr);
|
|
hart_->state().pc = base_addr;
|
|
|
|
engine_->run();
|
|
}
|
|
|
|
rocjitsu::risc_v::Hart *hart_ = nullptr;
|
|
std::unique_ptr<simdojo::SimulationEngine> engine_;
|
|
};
|
|
|
|
TEST_F(RvSimTest, ArithmeticAndMemory) {
|
|
// addi x1, x0, 42 # x1 = 42
|
|
// addi x2, x0, 8 # x2 = 8
|
|
// add x3, x1, x2 # x3 = 50
|
|
// addi x4, x0, 100 # x4 = 100
|
|
// sub x5, x4, x3 # x5 = 50
|
|
// lui x6, 0x10 # x6 = 0x10000
|
|
// sw x3, 0(x6) # mem[0x10000] = 50
|
|
// lw x7, 0(x6) # x7 = 50
|
|
// ebreak # halt
|
|
const uint32_t program[] = {
|
|
0x02a00093, // addi x1, x0, 42
|
|
0x00800113, // addi x2, x0, 8
|
|
0x002081b3, // add x3, x1, x2
|
|
0x06400213, // addi x4, x0, 100
|
|
0x403202b3, // sub x5, x4, x3
|
|
0x00010337, // lui x6, 0x10
|
|
0x00332023, // sw x3, 0(x6)
|
|
0x00032383, // lw x7, 0(x6)
|
|
0x00100073, // ebreak
|
|
};
|
|
load_and_run(program, std::size(program));
|
|
|
|
const auto &s = hart_->state();
|
|
EXPECT_TRUE(s.halted);
|
|
EXPECT_EQ(s.pc, 0x24u); // ebreak at 0x20, PC advances to 0x24
|
|
EXPECT_EQ(s.read_xreg(1), 42);
|
|
EXPECT_EQ(s.read_xreg(2), 8);
|
|
EXPECT_EQ(s.read_xreg(3), 50);
|
|
EXPECT_EQ(s.read_xreg(4), 100);
|
|
EXPECT_EQ(s.read_xreg(5), 50);
|
|
EXPECT_EQ(s.read_xreg(6), 0x10000);
|
|
EXPECT_EQ(s.read_xreg(7), 50);
|
|
EXPECT_EQ(hart_->memory().read32(0x10000), 50u);
|
|
}
|
|
|
|
TEST_F(RvSimTest, BranchAndJump) {
|
|
// addi x1, x0, 5 # x1 = 5
|
|
// addi x2, x0, 5 # x2 = 5
|
|
// beq x1, x2, 8 # branch forward 8 bytes (skip next instr)
|
|
// addi x3, x0, 99 # x3 = 99 (should be skipped)
|
|
// addi x4, x0, 1 # x4 = 1 (branch target)
|
|
// ebreak # halt
|
|
const uint32_t program[] = {
|
|
0x00500093, // addi x1, x0, 5
|
|
0x00500113, // addi x2, x0, 5
|
|
0x00208463, // beq x1, x2, +8
|
|
0x06300193, // addi x3, x0, 99
|
|
0x00100213, // addi x4, x0, 1
|
|
0x00100073, // ebreak
|
|
};
|
|
load_and_run(program, std::size(program));
|
|
|
|
const auto &s = hart_->state();
|
|
EXPECT_TRUE(s.halted);
|
|
EXPECT_EQ(s.read_xreg(1), 5);
|
|
EXPECT_EQ(s.read_xreg(3), 0); // skipped
|
|
EXPECT_EQ(s.read_xreg(4), 1); // branch target reached
|
|
}
|
|
|
|
TEST_F(RvSimTest, JalAndJalr) {
|
|
// jal x1, 8 # x1 = PC+4 = 4, jump to 0x8
|
|
// ebreak # should be skipped
|
|
// addi x2, x0, 42 # x2 = 42 (jal target at 0x8)
|
|
// jalr x3, x1, 0 # x3 = PC+4 = 0xC+4 = 0x10, jump to x1 = 4
|
|
// ebreak # halt (at 0x4, reached via jalr)
|
|
const uint32_t program[] = {
|
|
0x008000ef, // jal x1, 8
|
|
0x00100073, // ebreak (addr 0x4 - jalr target)
|
|
0x02a00113, // addi x2, x0, 42 (addr 0x8 - jal target)
|
|
0x000081e7, // jalr x3, x1, 0 (addr 0xC)
|
|
};
|
|
load_and_run(program, std::size(program));
|
|
|
|
const auto &s = hart_->state();
|
|
EXPECT_TRUE(s.halted);
|
|
EXPECT_EQ(s.read_xreg(1), 4); // return address from jal
|
|
EXPECT_EQ(s.read_xreg(2), 42);
|
|
EXPECT_EQ(s.read_xreg(3), 0x10); // return address from jalr
|
|
}
|
|
|
|
TEST_F(RvSimTest, ShiftsAndLogic) {
|
|
// addi x1, x0, 1 # x1 = 1
|
|
// slli x2, x1, 10 # x2 = 1024
|
|
// ori x3, x0, 0xFF # x3 = 255
|
|
// andi x4, x3, 0x0F # x4 = 15
|
|
// xori x5, x3, 0xFF # x5 = 0
|
|
// srli x6, x2, 5 # x6 = 32
|
|
// ebreak
|
|
const uint32_t program[] = {
|
|
0x00100093, // addi x1, x0, 1
|
|
0x00a09113, // slli x2, x1, 10
|
|
0x0ff06193, // ori x3, x0, 0xFF
|
|
0x00f1f213, // andi x4, x3, 0x0F
|
|
0x0ff1c293, // xori x5, x3, 0xFF
|
|
0x00515313, // srli x6, x2, 5
|
|
0x00100073, // ebreak
|
|
};
|
|
load_and_run(program, std::size(program));
|
|
|
|
const auto &s = hart_->state();
|
|
EXPECT_EQ(s.read_xreg(1), 1);
|
|
EXPECT_EQ(s.read_xreg(2), 1024);
|
|
EXPECT_EQ(s.read_xreg(3), 255);
|
|
EXPECT_EQ(s.read_xreg(4), 15);
|
|
EXPECT_EQ(s.read_xreg(5), 0);
|
|
EXPECT_EQ(s.read_xreg(6), 32);
|
|
}
|
|
|
|
} // namespace
|