Repository navigation
Update Linux Driver to reworked SPIbone Burst Mode #8
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
| # Zephyr firmware CI: twister boot test on the QEMU/mock target plus the | |
| # AMWA nmos-testing conformance suites against the emulated node. | |
| # | |
| # The workspace mirrors the local layout exactly: the repository root is | |
| # the west topdir (manifest repo soc_firmware, manifest file | |
| # app/west-manifest/west.yml, Zephyr pinned + patched into | |
| # external/zephyr). The aes67_bridge CSR headers are generated by LiteX | |
| # (litex_soc/build is not checked in). | |
| name: firmware-ci | |
| on: | |
| push: | |
| paths: | |
| - "soc_firmware/**" | |
| - "litex_soc/**" | |
| - ".github/workflows/firmware-ci.yml" | |
| - "scripts/ci/**" | |
| pull_request: | |
| paths: | |
| - "soc_firmware/**" | |
| - "litex_soc/**" | |
| - ".github/workflows/firmware-ci.yml" | |
| - "scripts/ci/**" | |
| workflow_dispatch: | |
| env: | |
| ZSDK_DIR: /opt/zephyr-sdk | |
| jobs: | |
| firmware-qemu: | |
| runs-on: ubuntu-22.04 | |
| timeout-minutes: 90 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Install build tools | |
| # Preinstalled on GitHub-hosted runners (fast no-op there), but | |
| # needed when running via `act` or on self-hosted runners. | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends \ | |
| git cmake ninja-build gperf ccache device-tree-compiler \ | |
| wget curl xz-utils file make gcc jq iproute2 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install python dependencies | |
| run: | | |
| pip install west | |
| # LiteX for the aes67_bridge CSR header generation (no synthesis). | |
| pip install "migen @ git+https://github.com/m-labs/migen" \ | |
| "litex @ git+https://github.com/enjoy-digital/litex" | |
| - name: West workspace (pinned Zephyr + local patches) | |
| run: | | |
| # Repo root == west topdir, same as the local checkout. | |
| west init -l --mf app/west-manifest/west.yml soc_firmware | |
| west update --narrow -o=--depth=1 | |
| # base + build/run-test (twister needs natsort, psutil, ...) | |
| pip install -r external/zephyr/scripts/requirements-base.txt \ | |
| -r external/zephyr/scripts/requirements-build-test.txt \ | |
| -r external/zephyr/scripts/requirements-run-test.txt | |
| cd external/zephyr | |
| git config user.email ci@localhost && git config user.name CI | |
| git am ../../soc_firmware/zephyr-patches/*.patch | |
| - name: Zephyr SDK (riscv64 toolchain + QEMU hosttools) | |
| run: | | |
| # The pinned Zephyr tree dictates the SDK version (SDK_VERSION | |
| # file) — the same series the local checkout uses. | |
| ZSDK_VERSION=$(cat external/zephyr/SDK_VERSION) | |
| echo "Zephyr SDK $ZSDK_VERSION" | |
| if [ "$(cat "$ZSDK_DIR/sdk_version" 2>/dev/null)" != "$ZSDK_VERSION" ]; then | |
| sudo rm -rf "$ZSDK_DIR" | |
| curl -sL -o /tmp/sdk.tar.xz \ | |
| "https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v${ZSDK_VERSION}/zephyr-sdk-${ZSDK_VERSION}_linux-x86_64_minimal.tar.xz" | |
| sudo mkdir -p "$ZSDK_DIR" && sudo chown "$USER" "$ZSDK_DIR" | |
| tar -xf /tmp/sdk.tar.xz -C "$ZSDK_DIR" --strip-components=1 | |
| "$ZSDK_DIR/setup.sh" -t riscv64-zephyr-elf -h -c | |
| fi | |
| echo "ZEPHYR_SDK_INSTALL_DIR=$ZSDK_DIR" >> "$GITHUB_ENV" | |
| echo "ZEPHYR_TOOLCHAIN_VARIANT=zephyr" >> "$GITHUB_ENV" | |
| # Locate the SDK's qemu-system-riscv64; the minimal tarball may | |
| # ship hosttools only as an installer (or not at all) — run the | |
| # installer if present, fall back to the distro package. | |
| # The hosttools carry TWO qemu builds (usr/bin and the Xilinx | |
| # variant under usr/xilinx/bin) — only usr/bin supports the | |
| # generic virt machine, so never pick by blind find order. | |
| find_qemu() { | |
| for p in "$ZSDK_DIR"/sysroots/*/usr/bin/qemu-system-riscv64 \ | |
| "$ZSDK_DIR"/hosttools/sysroots/*/usr/bin/qemu-system-riscv64; do | |
| if [ -x "$p" ]; then echo "$p"; return; fi | |
| done | |
| find "$ZSDK_DIR" -name qemu-system-riscv64 -type f \ | |
| -not -path "*xilinx*" 2>/dev/null | head -1 | |
| } | |
| QEMU_BIN=$(find_qemu) | |
| if [ -z "$QEMU_BIN" ]; then | |
| HT=$(find "$ZSDK_DIR" -name "*hosttools*standalone*.sh" 2>/dev/null | head -1) | |
| if [ -n "$HT" ]; then | |
| sh "$HT" -y -d "$ZSDK_DIR" | |
| QEMU_BIN=$(find_qemu) | |
| fi | |
| fi | |
| # The SDK-built qemu may not run on this host (glibc/library | |
| # mismatch) — verify it actually executes before trusting it. | |
| if [ -n "$QEMU_BIN" ] && ! "$QEMU_BIN" --version; then | |
| echo "SDK qemu is not runnable on this host, falling back" | |
| QEMU_BIN="" | |
| fi | |
| if [ -z "$QEMU_BIN" ]; then | |
| sudo apt-get install -y --no-install-recommends qemu-system-misc | |
| QEMU_BIN=$(command -v qemu-system-riscv64) | |
| "$QEMU_BIN" --version | |
| fi | |
| echo "Using QEMU: $QEMU_BIN" | |
| echo "QEMU_BIN=$QEMU_BIN" >> "$GITHUB_ENV" | |
| echo "QEMU_BIN_PATH=$(dirname "$QEMU_BIN")" >> "$GITHUB_ENV" | |
| - name: Generate aes67_bridge CSR headers | |
| run: python litex_soc/generate.py --target aes67_bridge | |
| - name: Twister (unit tests + QEMU boot test) | |
| # soc_firmware/tests holds the ztest unit suites (parsers, | |
| # config/streams, FPGA HAL mock, PTP facade); soc_firmware/app | |
| # holds the full-image boot test. Both run on qemu_riscv64. | |
| run: | | |
| west twister -T soc_firmware/tests -T soc_firmware/app \ | |
| -p qemu_riscv64 --inline-logs -v -O twister-out | |
| - name: Dump twister logs on failure | |
| if: failure() | |
| run: | | |
| # Twister keeps the emulator's own output in qemu.stdout / | |
| # qemu.stderr inside each build directory — NOT in handler.log, | |
| # which only carries the guest's serial console. A "unexpected | |
| # eof" verdict means the `ninja run` target died before the | |
| # harness saw its end marker, and the reason is in qemu.stderr. | |
| for f in $(find twister-out \( -name "handler.log" \ | |
| -o -name "qemu.stdout" \ | |
| -o -name "qemu.stderr" \ | |
| -o -name "device.log" \) -size +0); do | |
| echo "::group::$f" | |
| cat "$f" | |
| echo "::endgroup::" | |
| done | |
| # Per-configuration verdicts, so the failing scenario is named | |
| # even when the console stayed empty. | |
| if [ -f twister-out/twister.json ]; then | |
| echo "===== scenario status =====" | |
| jq -r '.testsuites[] | "\(.status)\t\(.name)\t\(.reason // "")"' \ | |
| twister-out/twister.json || true | |
| fi | |
| - name: Re-run a failed configuration by hand | |
| # Runs the exact `ninja run` target twister invoked, with its | |
| # output on stdout instead of in a file nobody reads. Catches the | |
| # cases twister reports only as "unexpected eof": a re-configure | |
| # error, a missing emulator binary, rejected machine arguments. | |
| if: failure() | |
| run: | | |
| echo "QEMU_BIN=$QEMU_BIN" | |
| "$QEMU_BIN" --version || true | |
| DIR=$(jq -r '[.testsuites[] | select(.status != "passed")][0].name // empty' \ | |
| twister-out/twister.json 2>/dev/null) | |
| echo "first failing scenario: ${DIR:-<unknown>}" | |
| # Map the scenario back to its build directory; fall back to any | |
| # build directory that has a zephyr.elf. | |
| BUILD=$(find twister-out -name build.ninja -printf '%h\n' | head -1) | |
| if [ -n "$DIR" ]; then | |
| CAND=$(find twister-out -type d -name "$(basename "$DIR")" | head -1) | |
| [ -n "$CAND" ] && BUILD="$CAND" | |
| fi | |
| echo "build dir: $BUILD" | |
| # `run` needs a reader on the fifo or QEMU blocks; give it one. | |
| mkfifo "$BUILD/qemu-fifo.in" "$BUILD/qemu-fifo.out" 2>/dev/null || true | |
| timeout 30 ninja -C "$BUILD" run < /dev/null 2>&1 | tail -60 || true | |
| - name: Upload twister artifacts | |
| # Skipped under act: no artifact service (ACTIONS_RUNTIME_TOKEN). | |
| if: ${{ always() && !env.ACT }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: twister-out | |
| path: | | |
| twister-out/twister.json | |
| twister-out/twister.log | |
| twister-out/**/handler.log | |
| twister-out/**/qemu.stdout | |
| twister-out/**/qemu.stderr | |
| twister-out/**/build.log | |
| if-no-files-found: ignore | |
| - name: Build QEMU image (TAP networking) | |
| run: west build -b qemu_riscv64 -d soc_firmware/app/build_qemu soc_firmware/app | |
| # ---- NMOS conformance: needs a host TAP device ---- | |
| # Creating "zeth" requires NET_ADMIN, which act's container does not | |
| # have by default ("Failed to send flush request: Operation not | |
| # permitted"). The steps below are therefore skipped under act; to | |
| # run them locally anyway, give the container the capability: | |
| # | |
| # act --container-options "--cap-add=NET_ADMIN --device=/dev/net/tun" | |
| # | |
| # Everything up to and including twister runs under act unchanged. | |
| - name: TAP interface for QEMU | |
| if: ${{ !env.ACT }} | |
| run: sudo scripts/ci/qemu-net-setup.sh | |
| - name: Fetch nmos-testing | |
| if: ${{ !env.ACT }} | |
| run: git clone --depth 1 https://github.com/AMWA-TV/nmos-testing "$RUNNER_TEMP/nmos-testing" | |
| - name: NMOS conformance (IS-04 / IS-05 / IS-08) | |
| if: ${{ !env.ACT }} | |
| run: | | |
| NMOS_TESTING="$RUNNER_TEMP/nmos-testing" \ | |
| BUILD_DIR="$PWD/soc_firmware/app/build_qemu" \ | |
| RESULTS_DIR="$PWD/nmos-results" \ | |
| QEMU="$QEMU_BIN" \ | |
| scripts/ci/run-nmos-conformance.sh | |
| - name: Note skipped steps (act) | |
| # So a green local run is not mistaken for full coverage. | |
| if: ${{ env.ACT }} | |
| run: | | |
| echo "Skipped under act: TAP setup + NMOS conformance (no NET_ADMIN)." | |
| echo "Built and ran: twister unit suites + QEMU boot test." | |
| echo "To include NMOS locally, re-run act with:" | |
| echo " --container-options \"--cap-add=NET_ADMIN --device=/dev/net/tun\"" | |
| - name: Upload NMOS results | |
| # Skipped under act: no artifact service (ACTIONS_RUNTIME_TOKEN). | |
| if: ${{ always() && !env.ACT }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: nmos-results | |
| path: nmos-results/ | |
| if-no-files-found: ignore |