aboutsummaryrefslogtreecommitdiff
path: root/rv64cpu/scripts/run_compliance.py
blob: 92456ec9cdc19906be5898bba098faffa9e9a012 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python3
"""
run_compliance.py — riscv-arch-test 自动化运行脚本

Usage:
    python3 scripts/run_compliance.py --suite rv64i
    python3 scripts/run_compliance.py --suite rv64im --build-dir build
    python3 scripts/run_compliance.py --list

Requirements:
    - Verilator simulation binary built (tb_soc or compliance_runner)
    - riscv64-unknown-elf-gcc toolchain in PATH
    - sw/riscv-arch-test submodule initialized
"""

import argparse
import subprocess
import sys
import os
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parent.parent
ARCH_TEST_DIR = PROJECT_ROOT / "sw" / "riscv-arch-test"
BUILD_DIR = PROJECT_ROOT / "build"

SUITES = {
    "rv64i":   "riscv-test-suite/rv64i_m/I",
    "rv64im":  "riscv-test-suite/rv64i_m/M",
    "rv64ia":  "riscv-test-suite/rv64i_m/A",
    "rv64if":  "riscv-test-suite/rv64i_m/F",
    "rv64id":  "riscv-test-suite/rv64i_m/D",
    "rv64ic":  "riscv-test-suite/rv64i_m/C",
    "rv64priv": "riscv-test-suite/rv64i_m/privilege",
}


def list_suites():
    print("Available test suites:")
    for name, path in SUITES.items():
        exists = "✓" if (ARCH_TEST_DIR / path).exists() else "✗ (not found)"
        print(f"  {name:12s} → {path}  {exists}")


def run_suite(suite_name: str, build_dir: Path, sim_binary: str, verbose: bool):
    if suite_name not in SUITES:
        print(f"Unknown suite: {suite_name}")
        print(f"Available: {', '.join(SUITES.keys())}")
        sys.exit(1)

    suite_path = ARCH_TEST_DIR / SUITES[suite_name]
    if not suite_path.exists():
        print(f"Suite path not found: {suite_path}")
        print("Did you initialize the submodule?")
        print("  git submodule update --init --recursive")
        sys.exit(1)

    sim_bin = build_dir / sim_binary
    if not sim_bin.exists():
        print(f"Simulation binary not found: {sim_bin}")
        print("Build it first: cmake --build build --target compliance_runner")
        sys.exit(1)

    test_files = sorted(suite_path.glob("src/*.S"))
    if not test_files:
        print(f"No test sources found in {suite_path / 'src'}")
        sys.exit(1)

    print(f"\n{'='*60}")
    print(f"Running {suite_name} compliance tests ({len(test_files)} tests)")
    print(f"{'='*60}\n")

    passed = 0
    failed = 0
    errors = []

    for test_file in test_files:
        test_name = test_file.stem
        if verbose:
            print(f"  [{test_name}] ", end="", flush=True)

        # TODO: Implement actual test compilation and simulation
        # This is a skeleton — fill in with your specific flow:
        #   1. Compile test_file with riscv64-unknown-elf-gcc
        #   2. Run the sim binary with the compiled ELF
        #   3. Compare signature output against reference
        if verbose:
            print("⏭ SKIP (runner not yet implemented)")

    print(f"\n{'='*60}")
    print(f"Results: {passed} passed, {failed} failed, {len(test_files) - passed - failed} skipped")
    print(f"{'='*60}\n")

    return failed == 0


def main():
    parser = argparse.ArgumentParser(description="Run riscv-arch-test compliance tests")
    parser.add_argument("--suite", type=str, help="Test suite to run")
    parser.add_argument("--build-dir", type=str, default="build", help="Build directory")
    parser.add_argument("--sim", type=str, default="compliance_runner", help="Sim binary name")
    parser.add_argument("--list", action="store_true", help="List available suites")
    parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")

    args = parser.parse_args()

    if args.list:
        list_suites()
        return

    if not args.suite:
        parser.print_help()
        sys.exit(1)

    build_dir = Path(args.build_dir)
    success = run_suite(args.suite, build_dir, args.sim, args.verbose)
    sys.exit(0 if success else 1)


if __name__ == "__main__":
    main()