ci: Add AHB controller tests to GitHub CI #873
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-License-Identifier: Apache-2.0 | |
| # | |
| # I3C Core - Parallel Test and Documentation Workflow | |
| # | |
| # This workflow runs cocotb verification tests in parallel for AHB, AXI, | |
| # AXI-Controller, and AHB-controller bus configurations, then builds and | |
| # deploys documentation. | |
| # | |
| # Architecture: | |
| # 1. generate-timing-docs: Generates timing CSR markdown documents | |
| # 2. generate-matrix: Uses nox's JSON output to discover test sessions | |
| # 3. tests-ahb: Runs all AHB-tagged tests in parallel (one job per test) | |
| # 4. tests-ahb-controller-and-target: Runs all AHB-Controller tests in parallel | |
| # 5. tests-ahb-controller-only: Runs all AHB-Controller only tests in parallel | |
| # 6. tests-axi: Runs all AXI-tagged tests in parallel (one job per test) | |
| # 7. tests-axi-controller-and-target: Runs all AXI-Controller tests in parallel | |
| # 8. tests-axi-controller-only: Runs all AXI-Controller only tests in parallel | |
| # 9. test-results: Aggregates results from all test jobs | |
| # 10. docs-build: Builds and deploys documentation (only after tests pass) | |
| # | |
| # Optional: Long-running tests (i3c_ahb_verify, i3c_axi_verify) can be split | |
| # into individual parametrized runs by enabling SPLIT_TESTS in generate-matrix. | |
| # | |
| # The parallel execution reduces total CI time significantly. | |
| name: Run Tests | |
| on: | |
| push: | |
| pull_request: | |
| permissions: | |
| contents: write | |
| env: | |
| DEBIAN_FRONTEND: "noninteractive" | |
| VERILATOR_VERSION: "v5.050" | |
| WAVES: "0" | |
| jobs: | |
| # =========================================================================== | |
| # Job: Generate Timing CSR Docs | |
| # =========================================================================== | |
| generate-timing-docs: | |
| name: Generate timing docs | |
| runs-on: ubuntu-latest | |
| env: | |
| I3C_ROOT_DIR: ${{ github.workspace }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt -qqy update | |
| sudo apt -qqy --no-install-recommends install \ | |
| wget curl help2man libfl-dev make g++ git bison flex gperf \ | |
| libreadline-dev libbz2-dev autoconf python3-dev python3-venv \ | |
| python3-jsonschema python3-yaml python3-sphinx python3-docopt | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Install Python dependencies | |
| run: | | |
| python -m pip install uv | |
| uv sync | |
| - name: Generate timing docs | |
| run: | | |
| mkdir -p doc/source | |
| echo "" >> doc/source/timing_csr.md | |
| python tools/timing/timings.py --freq=200e6 --target_name="FPGA" --md >> doc/source/timing_csr.md | |
| echo "" >> doc/source/timing_csr.md | |
| python tools/timing/timings.py --freq=500e6 --target_name="ASIC" --md >> doc/source/timing_csr.md | |
| - name: Upload timing docs artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: timing-csr-docs | |
| path: doc/source/timing_csr.md | |
| # =========================================================================== | |
| # Job: Generate Test Matrix | |
| # =========================================================================== | |
| generate-matrix: | |
| name: Generate test matrix | |
| runs-on: ubuntu-latest | |
| outputs: | |
| ahb-matrix: ${{ steps.gen.outputs.ahb_matrix }} | |
| ahb-controller-and-target-matrix: ${{ steps.gen.outputs.ahb_controller_and_target_matrix }} | |
| ahb-controller-only-matrix: ${{ steps.gen.outputs.ahb_controller_only_matrix }} | |
| axi-matrix: ${{ steps.gen.outputs.axi_matrix }} | |
| axi-controller-and-target-matrix: ${{ steps.gen.outputs.axi_controller_and_target_matrix }} | |
| axi-controller-only-matrix: ${{ steps.gen.outputs.axi_controller_only_matrix }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install nox and dependencies | |
| run: | | |
| pip install nox==2023.4.22 pyyaml | |
| pip install -e tools/nox_utils | |
| - name: Query nox for test sessions | |
| id: gen | |
| run: | | |
| cd verification/cocotb | |
| python3 << 'EOF' | |
| import json | |
| import subprocess | |
| import os | |
| import sys | |
| # Long-running tests that should be split into individual parametrized runs | |
| SPLIT_TESTS = {"i3c_ahb_verify", "i3c_axi_verify"} | |
| # We set DUT_CONFIG to controller_and_target to force nox to | |
| # expose all tests, so we can route them ourselves based on tags. | |
| result = subprocess.run( | |
| ["nox", "-l", "--json", "-f", "noxfile.py"], | |
| capture_output=True, text=True, | |
| env={ | |
| **os.environ, | |
| "PYTHONDONTWRITEBYTECODE": "1", | |
| "DUT_CONFIG": "controller_and_target" | |
| } | |
| ) | |
| if result.returncode != 0: | |
| print(f"nox failed with return code {result.returncode}", file=sys.stderr) | |
| print(f"stderr: {result.stderr}", file=sys.stderr) | |
| sys.exit(1) | |
| if not result.stdout.strip(): | |
| print("nox returned empty output", file=sys.stderr) | |
| print(f"stderr: {result.stderr}", file=sys.stderr) | |
| sys.exit(1) | |
| try: | |
| sessions = json.loads(result.stdout) | |
| except json.JSONDecodeError as e: | |
| print(f"Failed to parse JSON: {e}", file=sys.stderr) | |
| sys.exit(1) | |
| ahb_tests = set() | |
| ahb_controller_and_target_tests = set() | |
| ahb_controller_only_tests = set() | |
| axi_tests = set() | |
| axi_controller_and_target_tests = set() | |
| axi_controller_only_tests = set() | |
| for session in sessions: | |
| tags = session.get("tags", []) | |
| if "tests" not in tags: | |
| continue | |
| name = session["name"] | |
| if name in SPLIT_TESTS: | |
| session_id = session["session"] | |
| else: | |
| session_id = name | |
| # Check for specific role/bus tags | |
| has_ahb = "ahb" in tags | |
| has_axi = "axi" in tags | |
| has_controller = "controller" in tags | |
| has_target = "target" in tags | |
| if has_ahb: | |
| if has_controller: | |
| # If it has a controller tag, it always runs in the combined job | |
| ahb_controller_and_target_tests.add(session_id) | |
| # Exclude tests that also require a target from the controller_only job | |
| if not has_target: | |
| ahb_controller_only_tests.add(session_id) | |
| else: | |
| # Standard AHB tests (target-only, no controller tag) | |
| ahb_tests.add(session_id) | |
| if has_axi: | |
| if has_controller: | |
| # If it has a controller tag, it always runs in the combined job | |
| axi_controller_and_target_tests.add(session_id) | |
| # Exclude tests that also require a target from the controller_only job | |
| if not has_target: | |
| axi_controller_only_tests.add(session_id) | |
| else: | |
| # Standard AXI tests (target-only, no controller tag) | |
| axi_tests.add(session_id) | |
| # Sort for consistent ordering | |
| ahb_tests = sorted(ahb_tests) | |
| ahb_controller_and_target_tests = sorted(ahb_controller_and_target_tests) | |
| ahb_controller_only_tests = sorted(ahb_controller_only_tests) | |
| axi_tests = sorted(axi_tests) | |
| axi_controller_and_target_tests = sorted(axi_controller_and_target_tests) | |
| axi_controller_only_tests = sorted(axi_controller_only_tests) | |
| print(f"Discovered {len(ahb_tests)} AHB tests") | |
| print(f"Discovered {len(ahb_controller_and_target_tests)} AHB-Controller+Target tests") | |
| print(f"Discovered {len(ahb_controller_only_tests)} AHB-Controller-Only tests") | |
| print(f"Discovered {len(axi_tests)} AXI (Target-Only) tests") | |
| print(f"Discovered {len(axi_controller_and_target_tests)} AXI-Controller+Target tests") | |
| print(f"Discovered {len(axi_controller_only_tests)} AXI-Controller-Only tests") | |
| with open(os.environ['GITHUB_OUTPUT'], 'a') as f: | |
| f.write(f"ahb_matrix={json.dumps(ahb_tests)}\n") | |
| f.write(f"ahb_controller_and_target_matrix={json.dumps(ahb_controller_and_target_tests)}\n") | |
| f.write(f"ahb_controller_only_matrix={json.dumps(ahb_controller_only_tests)}\n") | |
| f.write(f"axi_matrix={json.dumps(axi_tests)}\n") | |
| f.write(f"axi_controller_and_target_matrix={json.dumps(axi_controller_and_target_tests)}\n") | |
| f.write(f"axi_controller_only_matrix={json.dumps(axi_controller_only_tests)}\n") | |
| EOF | |
| lint-testplans: | |
| name: Lint Testplan Documentation | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.12' | |
| - name: Run Testplan Linter | |
| run: | | |
| export I3C_ROOT_DIR=$GITHUB_WORKSPACE | |
| python tools/lint_testplan.py | |
| # =========================================================================== | |
| # Job: Run AHB Tests (Parallel) | |
| # =========================================================================== | |
| tests-ahb: | |
| name: "AHB: ${{ matrix.test }}" | |
| needs: [generate-matrix, lint-testplans] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test: ${{ fromJson(needs.generate-matrix.outputs.ahb-matrix) }} | |
| steps: | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt -qqy update | |
| sudo apt -qqy --no-install-recommends install \ | |
| help2man libfl-dev make g++ git bison flex gperf \ | |
| libreadline-dev libbz2-dev autoconf | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Initialize submodules | |
| run: git submodule update --init --recursive | |
| - name: Cache Verilator installation | |
| id: cache-verilator | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/verilator-install | |
| key: verilator-install-${{ env.VERILATOR_VERSION }}-${{ runner.os }} | |
| - name: Build Verilator (if not cached) | |
| if: steps.cache-verilator.outputs.cache-hit != 'true' | |
| run: | | |
| git clone https://github.com/verilator/verilator -b ${{ env.VERILATOR_VERSION }} | |
| cd verilator | |
| autoconf | |
| ./configure --prefix=$HOME/verilator-install | |
| make -j$(nproc) | |
| make install | |
| - name: Add Verilator to PATH | |
| run: | | |
| echo "$HOME/verilator-install/bin" >> $GITHUB_PATH | |
| echo "VERILATOR_ROOT=$HOME/verilator-install/share/verilator" >> $GITHUB_ENV | |
| - name: Setup Python environment (pyenv + dependencies) | |
| run: ./install.sh | |
| - name: Configure RTL and run test | |
| id: run-test | |
| env: | |
| TEST_SESSION: ${{ matrix.test }} | |
| run: | | |
| source activate.sh | |
| make config CFG_NAME=ahb_target_only | |
| cd verification/cocotb && python -m nox -R -s "$TEST_SESSION" --no-venv --forcecolor | |
| - name: Display test logs on failure | |
| if: failure() && steps.run-test.outcome == 'failure' | |
| run: | | |
| echo "=== Test failed - displaying log files ===" | |
| find verification/cocotb -name "*.log" -type f -exec sh -c \ | |
| 'echo ""; echo "========================================"; echo "=== {} ==="; echo "========================================"; cat "{}"' \; | |
| - name: Rename XML results to avoid collisions | |
| if: always() | |
| run: | | |
| find verification/cocotb -name "*.xml" -exec sh -c 'mv "$1" "${1%.xml}_target_only_ahb.xml"' _ {} \; | |
| - name: Sanitize artifact name | |
| if: always() | |
| id: sanitize | |
| run: | | |
| NAME='${{ matrix.test }}' | |
| SANITIZED=$(echo "$NAME" | sed "s/[()='\" ,]/_/g" | sed 's/__*/_/g' | sed 's/_$//') | |
| echo "name=$SANITIZED" >> $GITHUB_OUTPUT | |
| - name: Upload test artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-ahb-${{ steps.sanitize.outputs.name }} | |
| path: | | |
| verification/cocotb/**/*.xml | |
| verification/cocotb/**/*.log | |
| # =========================================================================== | |
| # Job: Run AHB-Controller and Target Tests (Parallel) | |
| # =========================================================================== | |
| tests-ahb-controller-and-target: | |
| name: "AHB-Ctrl+Target: ${{ matrix.test }}" | |
| needs: [generate-matrix, lint-testplans] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test: ${{ fromJson(needs.generate-matrix.outputs.ahb-controller-and-target-matrix) }} | |
| steps: | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt -qqy update | |
| sudo apt -qqy --no-install-recommends install \ | |
| help2man libfl-dev make g++ git bison flex gperf \ | |
| libreadline-dev libbz2-dev autoconf | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Initialize submodules | |
| run: git submodule update --init --recursive | |
| - name: Cache Verilator installation | |
| id: cache-verilator | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/verilator-install | |
| key: verilator-install-${{ env.VERILATOR_VERSION }}-${{ runner.os }} | |
| - name: Build Verilator (if not cached) | |
| if: steps.cache-verilator.outputs.cache-hit != 'true' | |
| run: | | |
| git clone https://github.com/verilator/verilator -b ${{ env.VERILATOR_VERSION }} | |
| cd verilator | |
| autoconf | |
| ./configure --prefix=$HOME/verilator-install | |
| make -j$(nproc) | |
| make install | |
| - name: Add Verilator to PATH | |
| run: | | |
| echo "$HOME/verilator-install/bin" >> $GITHUB_PATH | |
| echo "VERILATOR_ROOT=$HOME/verilator-install/share/verilator" >> $GITHUB_ENV | |
| - name: Setup Python environment (pyenv + dependencies) | |
| run: ./install.sh | |
| - name: Configure RTL and run test | |
| id: run-test | |
| env: | |
| TEST_SESSION: ${{ matrix.test }} | |
| CONTROLLER_SUPPORT: "1" | |
| TARGET_SUPPORT: "1" | |
| DUT_CONFIG: "controller_and_target" | |
| CFG_NAME: "ahb_controller_and_target_sim" | |
| I3C_ROOT_DIR: ${{ github.workspace }} | |
| run: | | |
| source activate.sh | |
| make config CFG_NAME=ahb_controller_and_target_sim | |
| cd verification/cocotb && python -m nox -R -s "$TEST_SESSION" --no-venv --forcecolor | |
| - name: Display test logs on failure | |
| if: failure() && steps.run-test.outcome == 'failure' | |
| run: | | |
| echo "=== Test failed - displaying log files ===" | |
| find verification/cocotb -name "*.log" -type f -exec sh -c \ | |
| 'echo ""; echo "========================================"; echo "=== {} ==="; echo "========================================"; cat "{}"' \; | |
| - name: Sanitize artifact name | |
| if: always() | |
| id: sanitize | |
| run: | | |
| NAME='${{ matrix.test }}' | |
| SANITIZED=$(echo "$NAME" | sed "s/[()='\" ,]/_/g" | sed 's/__*/_/g' | sed 's/_$//') | |
| echo "name=$SANITIZED" >> $GITHUB_OUTPUT | |
| - name: Upload test artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-ahb-controller-and-target-${{ steps.sanitize.outputs.name }} | |
| path: | | |
| verification/cocotb/**/*.xml | |
| verification/cocotb/**/*.log | |
| # =========================================================================== | |
| # Job: Run AHB-Controller Only Tests (Parallel) | |
| # =========================================================================== | |
| tests-ahb-controller-only: | |
| name: "AHB-Ctrl Only: ${{ matrix.test }}" | |
| needs: [generate-matrix, lint-testplans] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test: ${{ fromJson(needs.generate-matrix.outputs.ahb-controller-only-matrix) }} | |
| steps: | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt -qqy update | |
| sudo apt -qqy --no-install-recommends install \ | |
| help2man libfl-dev make g++ git bison flex gperf \ | |
| libreadline-dev libbz2-dev autoconf | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Initialize submodules | |
| run: git submodule update --init --recursive | |
| - name: Cache Verilator installation | |
| id: cache-verilator | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/verilator-install | |
| key: verilator-install-${{ env.VERILATOR_VERSION }}-${{ runner.os }} | |
| - name: Build Verilator (if not cached) | |
| if: steps.cache-verilator.outputs.cache-hit != 'true' | |
| run: | | |
| git clone https://github.com/verilator/verilator -b ${{ env.VERILATOR_VERSION }} | |
| cd verilator | |
| autoconf | |
| ./configure --prefix=$HOME/verilator-install | |
| make -j$(nproc) | |
| make install | |
| - name: Add Verilator to PATH | |
| run: | | |
| echo "$HOME/verilator-install/bin" >> $GITHUB_PATH | |
| echo "VERILATOR_ROOT=$HOME/verilator-install/share/verilator" >> $GITHUB_ENV | |
| - name: Setup Python environment (pyenv + dependencies) | |
| run: ./install.sh | |
| - name: Configure RTL and run test | |
| id: run-test | |
| env: | |
| TEST_SESSION: ${{ matrix.test }} | |
| CONTROLLER_SUPPORT: "1" | |
| TARGET_SUPPORT: "0" | |
| DUT_CONFIG: "controller_only" | |
| CFG_NAME: "ahb_controller_only_sim" | |
| I3C_ROOT_DIR: ${{ github.workspace }} | |
| run: | | |
| source activate.sh | |
| make config CFG_NAME=ahb_controller_only_sim | |
| cd verification/cocotb && python -m nox -R -s "$TEST_SESSION" --no-venv --forcecolor | |
| - name: Display test logs on failure | |
| if: failure() && steps.run-test.outcome == 'failure' | |
| run: | | |
| echo "=== Test failed - displaying log files ===" | |
| find verification/cocotb -name "*.log" -type f -exec sh -c \ | |
| 'echo ""; echo "========================================"; echo "=== {} ==="; echo "========================================"; cat "{}"' \; | |
| - name: Rename XML results to avoid collisions | |
| if: always() | |
| run: | | |
| find verification/cocotb -name "*.xml" -exec sh -c 'mv "$1" "${1%.xml}_ctrl_only.xml"' _ {} \; | |
| - name: Sanitize artifact name | |
| if: always() | |
| id: sanitize | |
| run: | | |
| NAME='${{ matrix.test }}' | |
| SANITIZED=$(echo "$NAME" | sed "s/[()='\" ,]/_/g" | sed 's/__*/_/g' | sed 's/_$//') | |
| echo "name=$SANITIZED" >> $GITHUB_OUTPUT | |
| - name: Upload test artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-ahb-controller-only-${{ steps.sanitize.outputs.name }} | |
| path: | | |
| verification/cocotb/**/*.xml | |
| verification/cocotb/**/*.log | |
| # =========================================================================== | |
| # Job: Run AXI Tests (Parallel) | |
| # =========================================================================== | |
| tests-axi: | |
| name: "AXI: ${{ matrix.test }}" | |
| needs: [generate-matrix, lint-testplans] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test: ${{ fromJson(needs.generate-matrix.outputs.axi-matrix) }} | |
| steps: | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt -qqy update | |
| sudo apt -qqy --no-install-recommends install \ | |
| help2man libfl-dev make g++ git bison flex gperf \ | |
| libreadline-dev libbz2-dev autoconf | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Initialize submodules | |
| run: git submodule update --init --recursive | |
| - name: Cache Verilator installation | |
| id: cache-verilator | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/verilator-install | |
| key: verilator-install-${{ env.VERILATOR_VERSION }}-${{ runner.os }} | |
| - name: Build Verilator (if not cached) | |
| if: steps.cache-verilator.outputs.cache-hit != 'true' | |
| run: | | |
| git clone https://github.com/verilator/verilator -b ${{ env.VERILATOR_VERSION }} | |
| cd verilator | |
| autoconf | |
| ./configure --prefix=$HOME/verilator-install | |
| make -j$(nproc) | |
| make install | |
| - name: Add Verilator to PATH | |
| run: | | |
| echo "$HOME/verilator-install/bin" >> $GITHUB_PATH | |
| echo "VERILATOR_ROOT=$HOME/verilator-install/share/verilator" >> $GITHUB_ENV | |
| - name: Setup Python environment (pyenv + dependencies) | |
| run: ./install.sh | |
| - name: Configure RTL and run test | |
| id: run-test | |
| env: | |
| TEST_SESSION: ${{ matrix.test }} | |
| run: | | |
| source activate.sh | |
| make config CFG_NAME=axi_target_only | |
| cd verification/cocotb && python -m nox -R -s "$TEST_SESSION" --no-venv --forcecolor | |
| - name: Display test logs on failure | |
| if: failure() && steps.run-test.outcome == 'failure' | |
| run: | | |
| echo "=== Test failed - displaying log files ===" | |
| find verification/cocotb -name "*.log" -type f -exec sh -c \ | |
| 'echo ""; echo "========================================"; echo "=== {} ==="; echo "========================================"; cat "{}"' \; | |
| - name: Sanitize artifact name | |
| if: always() | |
| id: sanitize | |
| run: | | |
| NAME='${{ matrix.test }}' | |
| SANITIZED=$(echo "$NAME" | sed "s/[()='\" ,]/_/g" | sed 's/__*/_/g' | sed 's/_$//') | |
| echo "name=$SANITIZED" >> $GITHUB_OUTPUT | |
| - name: Upload test artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-axi-${{ steps.sanitize.outputs.name }} | |
| path: | | |
| verification/cocotb/**/*.xml | |
| verification/cocotb/**/*.log | |
| # =========================================================================== | |
| # Job: Run AXI-Controller and Target Tests (Parallel) | |
| # =========================================================================== | |
| tests-axi-controller-and-target: | |
| name: "AXI-Ctrl+Target: ${{ matrix.test }}" | |
| needs: [generate-matrix, lint-testplans] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test: ${{ fromJson(needs.generate-matrix.outputs.axi-controller-and-target-matrix) }} | |
| steps: | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt -qqy update | |
| sudo apt -qqy --no-install-recommends install \ | |
| help2man libfl-dev make g++ git bison flex gperf \ | |
| libreadline-dev libbz2-dev autoconf | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Initialize submodules | |
| run: git submodule update --init --recursive | |
| - name: Cache Verilator installation | |
| id: cache-verilator | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/verilator-install | |
| key: verilator-install-${{ env.VERILATOR_VERSION }}-${{ runner.os }} | |
| - name: Build Verilator (if not cached) | |
| if: steps.cache-verilator.outputs.cache-hit != 'true' | |
| run: | | |
| git clone https://github.com/verilator/verilator -b ${{ env.VERILATOR_VERSION }} | |
| cd verilator | |
| autoconf | |
| ./configure --prefix=$HOME/verilator-install | |
| make -j$(nproc) | |
| make install | |
| - name: Add Verilator to PATH | |
| run: | | |
| echo "$HOME/verilator-install/bin" >> $GITHUB_PATH | |
| echo "VERILATOR_ROOT=$HOME/verilator-install/share/verilator" >> $GITHUB_ENV | |
| - name: Setup Python environment (pyenv + dependencies) | |
| run: ./install.sh | |
| - name: Configure RTL and run test | |
| id: run-test | |
| env: | |
| TEST_SESSION: ${{ matrix.test }} | |
| CONTROLLER_SUPPORT: "1" | |
| TARGET_SUPPORT: "1" | |
| DUT_CONFIG: "controller_and_target" | |
| CFG_NAME: "axi_controller_and_target_sim" | |
| I3C_ROOT_DIR: ${{ github.workspace }} | |
| run: | | |
| source activate.sh | |
| make config CFG_NAME=axi_controller_and_target_sim | |
| cd verification/cocotb && python -m nox -R -s "$TEST_SESSION" --no-venv --forcecolor | |
| - name: Display test logs on failure | |
| if: failure() && steps.run-test.outcome == 'failure' | |
| run: | | |
| echo "=== Test failed - displaying log files ===" | |
| find verification/cocotb -name "*.log" -type f -exec sh -c \ | |
| 'echo ""; echo "========================================"; echo "=== {} ==="; echo "========================================"; cat "{}"' \; | |
| - name: Sanitize artifact name | |
| if: always() | |
| id: sanitize | |
| run: | | |
| NAME='${{ matrix.test }}' | |
| SANITIZED=$(echo "$NAME" | sed "s/[()='\" ,]/_/g" | sed 's/__*/_/g' | sed 's/_$//') | |
| echo "name=$SANITIZED" >> $GITHUB_OUTPUT | |
| - name: Upload test artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-axi-controller-and-target-${{ steps.sanitize.outputs.name }} | |
| path: | | |
| verification/cocotb/**/*.xml | |
| verification/cocotb/**/*.log | |
| # =========================================================================== | |
| # Job: Run AXI-Controller Only Tests (Parallel) | |
| # =========================================================================== | |
| tests-axi-controller-only: | |
| name: "AXI-Ctrl Only: ${{ matrix.test }}" | |
| needs: [generate-matrix, lint-testplans] | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| test: ${{ fromJson(needs.generate-matrix.outputs.axi-controller-only-matrix) }} | |
| steps: | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt -qqy update | |
| sudo apt -qqy --no-install-recommends install \ | |
| help2man libfl-dev make g++ git bison flex gperf \ | |
| libreadline-dev libbz2-dev autoconf | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Initialize submodules | |
| run: git submodule update --init --recursive | |
| - name: Cache Verilator installation | |
| id: cache-verilator | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/verilator-install | |
| key: verilator-install-${{ env.VERILATOR_VERSION }}-${{ runner.os }} | |
| - name: Build Verilator (if not cached) | |
| if: steps.cache-verilator.outputs.cache-hit != 'true' | |
| run: | | |
| git clone https://github.com/verilator/verilator -b ${{ env.VERILATOR_VERSION }} | |
| cd verilator | |
| autoconf | |
| ./configure --prefix=$HOME/verilator-install | |
| make -j$(nproc) | |
| make install | |
| - name: Add Verilator to PATH | |
| run: | | |
| echo "$HOME/verilator-install/bin" >> $GITHUB_PATH | |
| echo "VERILATOR_ROOT=$HOME/verilator-install/share/verilator" >> $GITHUB_ENV | |
| - name: Setup Python environment (pyenv + dependencies) | |
| run: ./install.sh | |
| - name: Configure RTL and run test | |
| id: run-test | |
| env: | |
| TEST_SESSION: ${{ matrix.test }} | |
| CONTROLLER_SUPPORT: "1" | |
| TARGET_SUPPORT: "0" | |
| DUT_CONFIG: "controller_only" | |
| CFG_NAME: "axi_controller_only_sim" | |
| I3C_ROOT_DIR: ${{ github.workspace }} | |
| run: | | |
| source activate.sh | |
| make config CFG_NAME=axi_controller_only_sim | |
| cd verification/cocotb && python -m nox -R -s "$TEST_SESSION" --no-venv --forcecolor | |
| - name: Display test logs on failure | |
| if: failure() && steps.run-test.outcome == 'failure' | |
| run: | | |
| echo "=== Test failed - displaying log files ===" | |
| find verification/cocotb -name "*.log" -type f -exec sh -c \ | |
| 'echo ""; echo "========================================"; echo "=== {} ==="; echo "========================================"; cat "{}"' \; | |
| - name: Rename XML results to avoid collisions | |
| if: always() | |
| run: | | |
| find verification/cocotb -name "*.xml" -exec sh -c 'mv "$1" "${1%.xml}_ctrl_only.xml"' _ {} \; | |
| - name: Sanitize artifact name | |
| if: always() | |
| id: sanitize | |
| run: | | |
| NAME='${{ matrix.test }}' | |
| SANITIZED=$(echo "$NAME" | sed "s/[()='\" ,]/_/g" | sed 's/__*/_/g' | sed 's/_$//') | |
| echo "name=$SANITIZED" >> $GITHUB_OUTPUT | |
| - name: Upload test artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results-axi-controller-only-${{ steps.sanitize.outputs.name }} | |
| path: | | |
| verification/cocotb/**/*.xml | |
| verification/cocotb/**/*.log | |
| # =========================================================================== | |
| # Job: Aggregate Test Results | |
| # =========================================================================== | |
| test-results: | |
| name: Aggregate test results | |
| needs: [tests-ahb, tests-ahb-controller-and-target, tests-ahb-controller-only, tests-axi, tests-axi-controller-and-target, tests-axi-controller-only] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download all test artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: test-results-* | |
| path: test-results | |
| merge-multiple: true | |
| - name: Debug downloaded artifacts | |
| run: | | |
| echo "=== Files downloaded from test jobs ===" | |
| find test-results -type f 2>/dev/null | head -30 || echo "No files found" | |
| echo "" | |
| echo "=== XML files specifically ===" | |
| find test-results -name "*.xml" -type f 2>/dev/null | head -20 || echo "No XML files" | |
| - name: Upload combined test results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: tests-results | |
| path: test-results | |
| - name: Verify all tests passed | |
| run: | | |
| if [ "${{ needs.tests-ahb.result }}" != "success" ] || \ | |
| [ "${{ needs.tests-ahb-controller-and-target.result }}" != "success" ] || \ | |
| [ "${{ needs.tests-ahb-controller-only.result }}" != "success" ] || \ | |
| [ "${{ needs.tests-axi.result }}" != "success" ] || \ | |
| [ "${{ needs.tests-axi-controller-and-target.result }}" != "success" ] || \ | |
| [ "${{ needs.tests-axi-controller-only.result }}" != "success" ]; then | |
| echo "❌ Some tests failed!" | |
| echo " AHB tests: ${{ needs.tests-ahb.result }}" | |
| echo " AHB-Ctrl and Target tests: ${{ needs.tests-ahb-controller-and-target.result }}" | |
| echo " AHB-Ctrl only tests: ${{ needs.tests-ahb-controller-only.result }}" | |
| echo " AXI tests: ${{ needs.tests-axi.result }}" | |
| echo " AXI-Ctrl and Target tests: ${{ needs.tests-axi-controller-and-target.result }}" | |
| echo " AXI-Ctrl only tests: ${{ needs.tests-axi-controller-only.result }}" | |
| exit 1 | |
| fi | |
| echo "✅ All tests passed!" | |
| # =========================================================================== | |
| # Job: Build and Deploy Documentation | |
| # =========================================================================== | |
| docs-build: | |
| name: Build documentation | |
| runs-on: ubuntu-latest | |
| needs: [test-results, generate-timing-docs] | |
| if: always() && needs.test-results.result == 'success' && needs.generate-timing-docs.result == 'success' | |
| steps: | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt -qqy update | |
| sudo apt -qqy --no-install-recommends install \ | |
| python3 python3-pip python3-venv git | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Initialize submodules | |
| run: git submodule update --init --recursive | |
| - name: Download test results | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: tests-results | |
| path: tests-results | |
| - name: Download timing docs artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: timing-csr-docs | |
| path: doc/source | |
| - name: Debug downloaded artifacts | |
| run: | | |
| echo "=== Full structure of tests-results ===" | |
| find tests-results -type f 2>/dev/null | head -30 || echo "No files found or directory doesn't exist" | |
| echo "" | |
| echo "=== Directory listing ===" | |
| ls -laR tests-results 2>/dev/null | head -50 || echo "tests-results directory not found" | |
| - name: Setup Python environment (uv) | |
| run: | | |
| python3 -m pip install uv | |
| uv sync | |
| uv pip install -r doc/requirements.txt | |
| - name: Generate verification documentation | |
| run: | | |
| source .venv/bin/activate | |
| if [ -d "tests-results/verification/cocotb" ]; then | |
| echo "Found nested structure, copying from tests-results/verification/cocotb/" | |
| cp -r tests-results/verification/cocotb/* verification/cocotb/ | |
| elif [ -d "tests-results" ] && [ "$(ls -A tests-results 2>/dev/null)" ]; then | |
| echo "Found flat structure, copying from tests-results/" | |
| cp -r tests-results/* verification/cocotb/ | |
| else | |
| echo "WARNING: No test results found to copy!" | |
| fi | |
| echo "Filtering out controller_only test results from documentation generation..." | |
| find verification/cocotb -name "*_ctrl_only.xml" -type f -delete | |
| find verification/cocotb -name "*_ctrl_only.log" -type f -delete | |
| echo "=== Surviving XML files in verification/cocotb ===" | |
| find verification/cocotb -name "*.xml" -type f | head -10 | |
| XML_COUNT=$(find verification/cocotb -name "*.xml" -type f | wc -l) | |
| if [ "$XML_COUNT" -gt 0 ]; then | |
| echo "Found $XML_COUNT XML files, generating verification docs..." | |
| REPO_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/tree/$GITHUB_REF_NAME/" \ | |
| make verification-docs-with-sim | |
| else | |
| echo "WARNING: No XML files found, skipping verification-docs-with-sim" | |
| echo "Running verification-docs without sim results instead..." | |
| REPO_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/tree/$GITHUB_REF_NAME/" \ | |
| make verification-docs || true | |
| fi | |
| - name: Build Sphinx documentation | |
| run: | | |
| source .venv/bin/activate | |
| pushd doc | |
| TZ=UTC make html | |
| popd | |
| git clone https://github.com/antmicro/i3c-core-coverage-results || true | |
| cp i3c-core-coverage-results/*html doc/build/html 2>/dev/null || true | |
| - name: Upload documentation artifact | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docs | |
| path: ./doc/build | |
| - name: Deploy to GitHub Pages | |
| if: github.ref == 'refs/heads/main' | |
| uses: peaceiris/actions-gh-pages@v4 | |
| with: | |
| github_token: ${{ secrets.GITHUB_TOKEN }} | |
| publish_dir: ./doc/build/html |