> $GITHUB_OUTPUT
-
- - name: Create GitHub Release
- uses: softprops/action-gh-release@v2
- with:
- draft: false
- prerelease: ${{ needs.verify-tag.outputs.is_prerelease == 'true' }}
- body: |
- ## Changes
- ${{ steps.release_notes.outputs.changelog }}
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- publish:
- name: Publish to crates.io
- runs-on: ubuntu-latest
- needs: [verify-tag, check]
- if: needs.verify-tag.outputs.should_release == 'true'
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Install Rust toolchain
- uses: dtolnay/rust-toolchain@nightly
-
- - name: Dry run publish
- run: cargo publish --dry-run
-
- - name: Publish to crates.io
- run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
+ needs: [check, test]
+ uses: arceos-hypervisor/axci/.github/workflows/release.yml@main
+ with:
+ verify_branch: true
+ verify_version: true
+ secrets:
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index dc3b293..6a58ef8 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,3 +1,6 @@
+# Integration Test Workflow
+# References shared workflow from axci
+
name: Test
on:
@@ -7,44 +10,8 @@ on:
tags-ignore:
- '**'
pull_request:
- workflow_call:
+ workflow_dispatch:
jobs:
- load-config:
- name: Load CI Configuration
- runs-on: ubuntu-latest
- outputs:
- targets: ${{ steps.config.outputs.targets }}
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Load configuration
- id: config
- run: |
- TARGETS=$(jq -c '.targets' .github/config.json)
- echo "targets=$TARGETS" >> $GITHUB_OUTPUT
-
test:
- name: Test
- runs-on: ubuntu-latest
- needs: load-config
- strategy:
- fail-fast: false
- matrix:
- target: ${{ fromJson(needs.load-config.outputs.targets) }}
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Install Rust toolchain
- uses: dtolnay/rust-toolchain@nightly
-
- # - name: Run tests
- # run: cargo test --target ${{ matrix.target }} --all-features -- --nocapture
-
- # - name: Run doc tests
- # run: cargo test --target ${{ matrix.target }} --doc
- - name: Run tests
- run: echo "Tests are skipped!"
+ uses: arceos-hypervisor/axci/.github/workflows/test.yml@main
diff --git a/.gitignore b/.gitignore
index 0728338..6f3a252 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,11 @@ target
# Added by cargo
/target
+
+# Test results (generated by shared test framework)
+/test-results/
+/test_repos/
+*.log
+
+# Downloaded test framework
+/scripts/.axci/
diff --git a/README.md b/README.md
index 31523c4..38e200e 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,11 @@
# riscv-h
-[](https://github.com/arceos-hypervisor/riscv-h/actions/workflows/ci.yml)
[](https://crates.io/crates/riscv-h)
-[](https://docs.rs/riscv-h)
+[](https://docs.rs/riscv-h)
+[](https://www.rust-lang.org/)
+[](https://github.com/arceos-hypervisor/riscv-h/blob/main/LICENSE)
+
+English | [中文](README_CN.md)
RISC-V Hypervisor Extension Register Support
diff --git a/README_CN.md b/README_CN.md
new file mode 100644
index 0000000..4a488c2
--- /dev/null
+++ b/README_CN.md
@@ -0,0 +1,204 @@
+riscv-h
+
+RISC-V 虚拟化扩展寄存器支持库
+
+
+
+[](https://crates.io/crates/riscv-h)
+[](https://docs.rs/riscv-h)
+[](https://www.rust-lang.org/)
+[](https://github.com/arceos-hypervisor/riscv-h/blob/main/LICENSE)
+
+
+
+[English](README.md) | 中文
+
+# 简介
+
+RISC-V 虚拟化扩展寄存器支持库,提供 RISC-V Hypervisor Extension 中定义的控制和状态寄存器(CSR)的低级访问接口。支持 `#![no_std]`,可用于裸机和操作系统内核开发。
+
+本库导出以下核心模块:
+
+- **`register::hstatus`** — 虚拟化管理员状态寄存器
+- **`register::hgatp`** — 虚拟化客户地址翻译和保护寄存器
+- **`register::hvip`** — 虚拟化虚拟中断挂起寄存器
+- **`register::vsstatus`** — 虚拟管理员状态寄存器
+- **`register::vsatp`** — 虚拟管理员地址翻译和保护寄存器
+
+所有寄存器类型均实现了 `Copy`、`Clone`、`Debug` trait,并提供类型安全的位字段访问方法。
+
+## 快速上手
+
+### 环境要求
+
+- Rust nightly 工具链
+- Rust 组件: rust-src, clippy, rustfmt, llvm-tools
+- 目标平台: riscv64gc-unknown-none-elf
+
+```bash
+# 安装 rustup(如未安装)
+curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+
+# 安装 nightly 工具链及组件
+rustup install nightly
+rustup component add rust-src clippy rustfmt llvm-tools --toolchain nightly
+
+# 添加 RISC-V 目标
+rustup target add riscv64gc-unknown-none-elf --toolchain nightly
+```
+
+### 运行检查和测试
+
+```bash
+# 1. 克隆仓库
+git clone https://github.com/arceos-hypervisor/riscv-h.git
+cd riscv-h
+
+# 2. 代码检查(格式检查 + clippy + 构建 + 文档生成)
+./scripts/check.sh
+
+# 3. 运行测试
+# 运行全部测试(单元测试 + 集成测试)
+./scripts/test.sh
+
+# 仅运行单元测试
+./scripts/test.sh unit
+
+# 仅运行集成测试
+./scripts/test.sh integration
+
+# 列出所有可用的测试套件
+./scripts/test.sh list
+
+# 指定单元测试目标
+./scripts/test.sh unit --unit-targets x86_64-unknown-linux-gnu
+```
+
+## 集成使用
+
+### 安装
+
+在 `Cargo.toml` 中添加:
+
+```toml
+[dependencies]
+riscv-h = "0.2.0"
+```
+
+### 使用示例
+
+```rust
+#![no_std]
+
+use riscv_h::register::{hstatus, hgatp, hvip};
+
+fn main() {
+ // 读取虚拟化管理员状态寄存器
+ let hstatus = hstatus::read();
+
+ // 检查是否处于虚拟化模式
+ if hstatus.spv() {
+ // 访问各个字段
+ let vsxl = hstatus.vsxl(); // 虚拟管理员 XLEN
+ let vtw = hstatus.vtw(); // 陷阱 WFI
+ let vtsr = hstatus.vtsr(); // 陷阱 SRET
+ let vgein = hstatus.vgein(); // 虚拟客户外部中断号
+
+ setup_guest_translation();
+ }
+
+ // 配置虚拟中断挂起
+ let mut hvip_val = hvip::Hvip::from_bits(0);
+ hvip_val.set_vssip(true); // 设置虚拟管理员软件中断挂起
+ hvip_val.set_vstip(true); // 设置虚拟管理员定时器中断挂起
+ hvip_val.set_vseip(true); // 设置虚拟管理员外部中断挂起
+
+ unsafe {
+ hvip_val.write();
+ }
+}
+
+fn setup_guest_translation() {
+ unsafe {
+ // 配置客户地址翻译
+ let mut hgatp = hgatp::Hgatp::from_bits(0);
+ hgatp.set_mode(hgatp::HgatpValues::Sv48x4); // 使用 Sv48x4 模式
+ hgatp.set_vmid(1); // 设置 VMID
+ hgatp.set_ppn(0x1000); // 设置根页表 PPN
+ hgatp.write();
+ }
+}
+```
+
+### 异常和中断委托
+
+```rust
+use riscv_h::register::{hedeleg, hideleg};
+
+unsafe {
+ // 将常见异常委托给 VS-mode
+ hedeleg::set_ex2(true); // 非法指令
+ hedeleg::set_ex8(true); // U-mode 环境调用
+ hedeleg::set_ex12(true); // 指令页面错误
+ hedeleg::set_ex13(true); // 加载页面错误
+ hedeleg::set_ex15(true); // 存储页面错误
+
+ // 将定时器和软件中断委托给 VS-mode
+ hideleg::set_vstie(true); // VS-mode 定时器中断
+ hideleg::set_vssie(true); // VS-mode 软件中断
+}
+```
+
+## 支持的寄存器
+
+### 虚拟化控制寄存器
+
+| 寄存器 | 描述 | CSR 地址 |
+|--------|------|----------|
+| `hstatus` | 虚拟化管理员状态寄存器 | 0x600 |
+| `hedeleg` | 虚拟化异常委托寄存器 | 0x602 |
+| `hideleg` | 虚拟化中断委托寄存器 | 0x603 |
+| `hie` | 虚拟化中断使能寄存器 | 0x604 |
+| `hcounteren` | 虚拟化计数器使能寄存器 | 0x606 |
+| `hgatp` | 虚拟化客户地址翻译和保护寄存器 | 0x680 |
+
+### 虚拟管理员寄存器
+
+| 寄存器 | 描述 | CSR 地址 |
+|--------|------|----------|
+| `vsstatus` | 虚拟管理员状态寄存器 | 0x200 |
+| `vsie` | 虚拟管理员中断使能寄存器 | 0x204 |
+| `vstvec` | 虚拟管理员陷阱向量寄存器 | 0x205 |
+| `vsscratch` | 虚拟管理员暂存寄存器 | 0x240 |
+| `vsepc` | 虚拟管理员异常程序计数器 | 0x241 |
+| `vscause` | 虚拟管理员原因寄存器 | 0x242 |
+| `vstval` | 虚拟管理员陷阱值寄存器 | 0x243 |
+| `vsatp` | 虚拟管理员地址翻译和保护寄存器 | 0x280 |
+
+### 其他寄存器
+
+- **中断管理**: `hip`, `hvip`, `hgeie`, `hgeip`
+- **时间管理**: `htimedelta`, `htimedeltah`
+- **陷阱信息**: `htval`, `htinst`
+- **虚拟管理员中断**: `vsip`
+
+### 文档
+
+生成并查看 API 文档:
+
+```bash
+cargo doc --no-deps --open
+```
+
+在线文档:[docs.rs/riscv-h](https://docs.rs/riscv-h)
+
+# 贡献
+
+1. Fork 仓库并创建分支
+2. 运行本地检查:`./scripts/check.sh`
+3. 运行本地测试:`./scripts/test.sh`
+4. 提交 PR 并通过 CI 检查
+
+# 协议
+
+本项目采用 Apache License, Version 2.0 许可证。详见 [LICENSE](LICENSE) 文件。
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index 6289821..adb3ba8 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,5 +1,5 @@
[toolchain]
-channel = "nightly-2025-05-20"
+channel = "nightly-2026-03-18"
components = ["rust-src", "llvm-tools", "rustfmt", "clippy"]
profile = "minimal"
targets = [
diff --git a/scripts/check.sh b/scripts/check.sh
new file mode 100755
index 0000000..1613cbc
--- /dev/null
+++ b/scripts/check.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+#
+# riscv-h 代码检查脚本
+# 下载并调用 axci 仓库中的检查脚本
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+COMPONENT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
+COMPONENT_NAME="$(basename "$COMPONENT_DIR")"
+AXCI_DIR="${SCRIPT_DIR}/.axci"
+AXCI_REPO="https://github.com/arceos-hypervisor/axci.git"
+
+# 下载或更新 axci 仓库
+download_axci() {
+ if [ -d "$AXCI_DIR" ]; then
+ echo "Updating axci repository..."
+ cd "$AXCI_DIR" && git pull --quiet
+ else
+ echo "Downloading axci repository..."
+ git clone --quiet "$AXCI_REPO" "$AXCI_DIR"
+ fi
+}
+
+# 主函数
+main() {
+ download_axci
+
+ # 在组件目录中运行检查
+ cd "$COMPONENT_DIR"
+ exec bash "$AXCI_DIR/check.sh" --component-dir "$COMPONENT_DIR" "$@"
+}
+
+main "$@"
diff --git a/scripts/test.sh b/scripts/test.sh
new file mode 100755
index 0000000..a948928
--- /dev/null
+++ b/scripts/test.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# riscv-h 测试脚本
+# 下载并调用 axci 仓库中的测试框架
+#
+
+set -e
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+COMPONENT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
+AXCI_DIR="${SCRIPT_DIR}/.axci"
+AXCI_REPO="https://github.com/arceos-hypervisor/axci.git"
+
+# 下载或更新 axci 仓库
+download_axci() {
+ if [ -d "$AXCI_DIR" ]; then
+ echo "Updating axci repository..."
+ cd "$AXCI_DIR" && git pull --quiet
+ else
+ echo "Downloading axci repository..."
+ git clone --quiet "$AXCI_REPO" "$AXCI_DIR"
+ fi
+}
+
+# 主函数
+main() {
+ download_axci
+
+ # 在组件目录中运行测试,自动指定当前组件
+ cd "$COMPONENT_DIR"
+ exec bash "$AXCI_DIR/tests.sh" --component-dir "$COMPONENT_DIR" "$@"
+}
+
+main "$@"
diff --git a/tests/register_tests.rs b/tests/register_tests.rs
new file mode 100644
index 0000000..0d91b62
--- /dev/null
+++ b/tests/register_tests.rs
@@ -0,0 +1,425 @@
+// Copyright 2025 The Axvisor Team
+//
+// 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.
+
+//! Unit tests for individual RISC-V hypervisor registers
+
+use riscv_h::register::{hcounteren, hie, hip, hvip, vsatp, vsie, vsip, vstvec};
+
+// ============================================================================
+// Hypervisor Control Registers Tests
+// ============================================================================
+
+mod hvip_tests {
+ use super::*;
+
+ #[test]
+ fn test_hvip_bit_fields() {
+ let mut hvip = hvip::Hvip::from_bits(0);
+
+ // Test VSSIP (bit 2)
+ assert!(!hvip.vssip());
+ hvip.set_vssip(true);
+ assert!(hvip.vssip());
+ assert_eq!(hvip.bits(), 0b100);
+
+ // Test VSTIP (bit 6)
+ hvip.set_vstip(true);
+ assert!(hvip.vstip());
+ assert_eq!(hvip.bits(), 0b100_0100);
+
+ // Test VSEIP (bit 10)
+ hvip.set_vseip(true);
+ assert!(hvip.vseip());
+ // bit 2 + bit 6 + bit 10 = 4 + 64 + 1024 = 1092
+ assert_eq!(hvip.bits(), (1 << 2) | (1 << 6) | (1 << 10));
+ }
+
+ #[test]
+ fn test_hvip_bit_isolation() {
+ let mut hvip = hvip::Hvip::from_bits(0);
+
+ // Set all interrupt pending bits
+ hvip.set_vssip(true);
+ hvip.set_vstip(true);
+ hvip.set_vseip(true);
+
+ // Clear one at a time and verify others unchanged
+ hvip.set_vssip(false);
+ assert!(!hvip.vssip());
+ assert!(hvip.vstip());
+ assert!(hvip.vseip());
+
+ hvip.set_vstip(false);
+ assert!(!hvip.vssip());
+ assert!(!hvip.vstip());
+ assert!(hvip.vseip());
+ }
+}
+
+mod hcounteren_tests {
+ use super::*;
+
+ #[test]
+ fn test_hcounteren_basic_fields() {
+ let mut hcounteren = hcounteren::Hcounteren::from_bits(0);
+
+ // Test CY (bit 0)
+ hcounteren.set_cy(true);
+ assert!(hcounteren.cy());
+
+ // Test TM (bit 1)
+ hcounteren.set_tm(true);
+ assert!(hcounteren.tm());
+
+ // Test IR (bit 2)
+ hcounteren.set_ir(true);
+ assert!(hcounteren.ir());
+
+ assert_eq!(hcounteren.bits(), 0b111);
+ }
+
+ #[test]
+ fn test_hcounteren_hpm_fields() {
+ let mut hcounteren = hcounteren::Hcounteren::from_bits(0);
+
+ // Test a few HPM counters
+ hcounteren.set_hpm3(true);
+ hcounteren.set_hpm10(true);
+ hcounteren.set_hpm31(true);
+
+ assert!(hcounteren.hpm3());
+ assert!(hcounteren.hpm10());
+ assert!(hcounteren.hpm31());
+
+ // Verify bits are at correct positions
+ assert_eq!(hcounteren.bits() & (1 << 3), 1 << 3); // hpm3
+ assert_eq!(hcounteren.bits() & (1 << 10), 1 << 10); // hpm10
+ assert_eq!(hcounteren.bits() & (1 << 31), 1 << 31); // hpm31
+ }
+}
+
+mod hie_tests {
+ use super::*;
+
+ #[test]
+ fn test_hie_bit_fields() {
+ let mut hie = hie::Hie::from_bits(0);
+
+ // Test VSSIE (bit 2)
+ hie.set_vssie(true);
+ assert!(hie.vssie());
+
+ // Test VSTIE (bit 6)
+ hie.set_vstie(true);
+ assert!(hie.vstie());
+
+ // Test VSEIE (bit 10)
+ hie.set_vseie(true);
+ assert!(hie.vseie());
+
+ // Test SGEIE (bit 12)
+ hie.set_sgeie(true);
+ assert!(hie.sgeie());
+
+ assert_eq!(hie.bits(), (1 << 2) | (1 << 6) | (1 << 10) | (1 << 12));
+ }
+
+ #[test]
+ fn test_hie_bit_isolation() {
+ let mut hie = hie::Hie::from_bits(0);
+
+ hie.set_vssie(true);
+ hie.set_vstie(true);
+ hie.set_vseie(true);
+ hie.set_sgeie(true);
+
+ // Clear one at a time
+ hie.set_vssie(false);
+ assert!(!hie.vssie());
+ assert!(hie.vstie());
+ assert!(hie.vseie());
+ assert!(hie.sgeie());
+ }
+}
+
+mod hip_tests {
+ use super::*;
+
+ #[test]
+ fn test_hip_bit_fields() {
+ let mut hip = hip::Hip::from_bits(0);
+
+ // Test VSSIP (bit 2)
+ hip.set_vssip(true);
+ assert!(hip.vssip());
+
+ // Test VSTIP (bit 6)
+ hip.set_vstip(true);
+ assert!(hip.vstip());
+
+ // Test VSEIP (bit 10)
+ hip.set_vseip(true);
+ assert!(hip.vseip());
+
+ // Test SGEIP (bit 12)
+ hip.set_sgeip(true);
+ assert!(hip.sgeip());
+
+ assert_eq!(hip.bits(), (1 << 2) | (1 << 6) | (1 << 10) | (1 << 12));
+ }
+
+ #[test]
+ fn test_hip_bit_isolation() {
+ let mut hip = hip::Hip::from_bits(0);
+
+ hip.set_vssip(true);
+ hip.set_vstip(true);
+ hip.set_vseip(true);
+ hip.set_sgeip(true);
+
+ // Clear one at a time
+ hip.set_sgeip(false);
+ assert!(hip.vssip());
+ assert!(hip.vstip());
+ assert!(hip.vseip());
+ assert!(!hip.sgeip());
+ }
+}
+
+// ============================================================================
+// Virtual Supervisor Registers Tests
+// ============================================================================
+
+mod vsatp_tests {
+ use super::*;
+
+ #[test]
+ fn test_vsatp_mode() {
+ let mut vsatp = vsatp::Vsatp::from_bits(0);
+
+ vsatp.set_mode(vsatp::HgatpValues::Bare);
+ assert!(matches!(vsatp.mode(), vsatp::HgatpValues::Bare));
+
+ vsatp.set_mode(vsatp::HgatpValues::Sv39x4);
+ assert!(matches!(vsatp.mode(), vsatp::HgatpValues::Sv39x4));
+
+ vsatp.set_mode(vsatp::HgatpValues::Sv48x4);
+ assert!(matches!(vsatp.mode(), vsatp::HgatpValues::Sv48x4));
+ }
+
+ #[test]
+ fn test_vsatp_asid() {
+ let mut vsatp = vsatp::Vsatp::from_bits(0);
+
+ // ASID is 16 bits (bits 44-59)
+ vsatp.set_asid(0);
+ assert_eq!(vsatp.asid(), 0);
+
+ vsatp.set_asid(0xFFFF);
+ assert_eq!(vsatp.asid(), 0xFFFF);
+
+ vsatp.set_asid(0x1234);
+ assert_eq!(vsatp.asid(), 0x1234);
+ }
+
+ #[test]
+ fn test_vsatp_ppn() {
+ let mut vsatp = vsatp::Vsatp::from_bits(0);
+
+ // PPN is 44 bits (bits 0-43)
+ vsatp.set_ppn(0);
+ assert_eq!(vsatp.ppn(), 0);
+
+ vsatp.set_ppn(0xFFFFFFFFFFF);
+ assert_eq!(vsatp.ppn(), 0xFFFFFFFFFFF);
+ }
+
+ #[test]
+ fn test_vsatp_field_isolation() {
+ let mut vsatp = vsatp::Vsatp::from_bits(0);
+
+ vsatp.set_mode(vsatp::HgatpValues::Sv48x4);
+ vsatp.set_asid(0xABCD);
+ vsatp.set_ppn(0x123456789);
+
+ // Verify all fields are independent
+ assert!(matches!(vsatp.mode(), vsatp::HgatpValues::Sv48x4));
+ assert_eq!(vsatp.asid(), 0xABCD);
+ assert_eq!(vsatp.ppn(), 0x123456789);
+
+ // Modify one field shouldn't affect others
+ vsatp.set_asid(0);
+ assert!(matches!(vsatp.mode(), vsatp::HgatpValues::Sv48x4));
+ assert_eq!(vsatp.asid(), 0);
+ assert_eq!(vsatp.ppn(), 0x123456789);
+ }
+}
+
+mod vstvec_tests {
+ use super::*;
+
+ #[test]
+ fn test_vstvec_base() {
+ let mut vstvec = vstvec::Vstvec::from_bits(0);
+
+ // Base is bits 2-63, must be 4-byte aligned
+ vstvec.set_base(0x1000);
+ assert_eq!(vstvec.base(), 0x1000);
+
+ vstvec.set_base(0x80000000);
+ assert_eq!(vstvec.base(), 0x80000000);
+ }
+
+ #[test]
+ fn test_vstvec_mode() {
+ let mut vstvec = vstvec::Vstvec::from_bits(0);
+
+ // Mode is bits 0-1
+ vstvec.set_mode(0); // Direct
+ assert_eq!(vstvec.mode(), 0);
+
+ vstvec.set_mode(1); // Vectored
+ assert_eq!(vstvec.mode(), 1);
+ }
+
+ #[test]
+ fn test_vstvec_field_isolation() {
+ let mut vstvec = vstvec::Vstvec::from_bits(0);
+
+ vstvec.set_base(0x12345678);
+ vstvec.set_mode(1);
+
+ // base() returns the raw bits 2-63 value
+ assert_eq!(vstvec.base(), 0x12345678);
+ assert_eq!(vstvec.mode(), 1);
+ }
+}
+
+mod vsie_tests {
+ use super::*;
+
+ #[test]
+ fn test_vsie_bit_fields() {
+ let mut vsie = vsie::Vsie::from_bits(0);
+
+ // Test SSIE (bit 1)
+ vsie.set_ssie(true);
+ assert!(vsie.ssie());
+
+ // Test STIE (bit 5)
+ vsie.set_stie(true);
+ assert!(vsie.stie());
+
+ // Test SEIE (bit 9)
+ vsie.set_seie(true);
+ assert!(vsie.seie());
+
+ assert_eq!(vsie.bits(), (1 << 1) | (1 << 5) | (1 << 9));
+ }
+
+ #[test]
+ fn test_vsie_bit_isolation() {
+ let mut vsie = vsie::Vsie::from_bits(0);
+
+ vsie.set_ssie(true);
+ vsie.set_stie(true);
+ vsie.set_seie(true);
+
+ vsie.set_ssie(false);
+ assert!(!vsie.ssie());
+ assert!(vsie.stie());
+ assert!(vsie.seie());
+ }
+}
+
+mod vsip_tests {
+ use super::*;
+
+ #[test]
+ fn test_vsip_bit_fields() {
+ let mut vsip = vsip::Vsip::from_bits(0);
+
+ // Test SSIP (bit 1)
+ vsip.set_ssip(true);
+ assert!(vsip.ssip());
+
+ // Test STIP (bit 5)
+ vsip.set_stip(true);
+ assert!(vsip.stip());
+
+ // Test SEIP (bit 9)
+ vsip.set_seip(true);
+ assert!(vsip.seip());
+
+ assert_eq!(vsip.bits(), (1 << 1) | (1 << 5) | (1 << 9));
+ }
+
+ #[test]
+ fn test_vsip_bit_isolation() {
+ let mut vsip = vsip::Vsip::from_bits(0);
+
+ vsip.set_ssip(true);
+ vsip.set_stip(true);
+ vsip.set_seip(true);
+
+ vsip.set_ssip(false);
+ assert!(!vsip.ssip());
+ assert!(vsip.stip());
+ assert!(vsip.seip());
+ }
+}
+
+// ============================================================================
+// Copy/Clone Trait Tests
+// ============================================================================
+
+mod trait_tests {
+ use super::*;
+
+ #[test]
+ fn test_all_registers_copy_clone() {
+ // Test that all register types implement Copy and Clone
+ let hvip = hvip::Hvip::from_bits(0x123);
+ let _copy = hvip;
+ let _clone = hvip.clone();
+
+ let hcounteren = hcounteren::Hcounteren::from_bits(0xFF);
+ let _copy = hcounteren;
+ let _clone = hcounteren.clone();
+
+ let vsatp = vsatp::Vsatp::from_bits(0xABC);
+ let _copy = vsatp;
+ let _clone = vsatp.clone();
+
+ let vstvec = vstvec::Vstvec::from_bits(0x1000);
+ let _copy = vstvec;
+ let _clone = vstvec.clone();
+ }
+
+ #[test]
+ fn test_all_registers_debug() {
+ // Test that all register types implement Debug
+ let hvip = hvip::Hvip::from_bits(0x123);
+ assert!(format!("{:?}", hvip).contains("Hvip"));
+
+ let hcounteren = hcounteren::Hcounteren::from_bits(0xFF);
+ assert!(format!("{:?}", hcounteren).contains("Hcounteren"));
+
+ let vsatp = vsatp::Vsatp::from_bits(0xABC);
+ assert!(format!("{:?}", vsatp).contains("Vsatp"));
+
+ let vstvec = vstvec::Vstvec::from_bits(0x1000);
+ assert!(format!("{:?}", vstvec).contains("Vstvec"));
+ }
+}