From a4c4a9fbb4a194fb3b9206e5d94784de4c482b74 Mon Sep 17 00:00:00 2001 From: Martijn Bastiaan Date: Fri, 29 Mar 2024 20:12:03 +0100 Subject: [PATCH 1/3] Use own Docker image, add openocd --- .github/docker/Dockerfile | 82 +++++++++++++++++++ .../docker/build-and-publish-docker-image.sh | 48 +++++++++++ .github/workflows/ci.yml | 26 +----- 3 files changed, 134 insertions(+), 22 deletions(-) create mode 100644 .github/docker/Dockerfile create mode 100755 .github/docker/build-and-publish-docker-image.sh diff --git a/.github/docker/Dockerfile b/.github/docker/Dockerfile new file mode 100644 index 0000000..754c775 --- /dev/null +++ b/.github/docker/Dockerfile @@ -0,0 +1,82 @@ +# syntax=docker/dockerfile:1.2 + +# SPDX-FileCopyrightText: 2024 Google LLC + +# SPDX-License-Identifier: CC0-1.0 + +ARG UBUNTU_VERSION +FROM ubuntu:$UBUNTU_VERSION AS builder + +LABEL vendor="QBayLogic B.V." maintainer="devops@qbaylogic.com" +ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 LC_ALL=C.UTF-8 PREFIX=/opt + +ARG DEPS_COMMON="build-essential ca-certificates curl git locales ca-certificates" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends $DEPS_COMMON \ + && locale-gen en_US.UTF-8 \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +FROM builder AS build-openocd-vexriscv + +ARG DEPS_OPENOCD_VEXRISCV="autoconf automake libtool pkg-config libusb-1.0-0-dev libftdi-dev libhidapi-dev libusb-dev libyaml-dev" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends $DEPS_OPENOCD_VEXRISCV \ + && git clone --recursive https://github.com/SpinalHDL/openocd_riscv.git \ + && cd openocd_riscv \ + && ./bootstrap \ + && ./configure --enable-ftdi --enable-dummy --prefix=/opt \ + && make -j$(nproc) \ + && make install + +FROM builder AS build-verilator + +ARG DEPS_VERILATOR="perl python3 make autoconf g++ flex bison ccache libgoogle-perftools-dev numactl perl-doc libfl2 libfl-dev zlib1g zlib1g-dev help2man" +RUN apt-get update \ + && apt-get install -y --no-install-recommends $DEPS_VERILATOR + +ARG verilator_version="v5.020" +RUN git clone https://github.com/verilator/verilator verilator \ + && cd verilator \ + && git checkout $verilator_version \ + && autoconf \ + && ./configure --prefix $PREFIX \ + && make PREFIX=$PREFIX -j$(nproc) \ + && make PREFIX=$PREFIX install \ + && cd ../.. \ + && rm -Rf verilator + +FROM builder AS build-ghc + +ARG ghcup_version="0.1.22.0" + +# Must be explicitly set +ARG ghc_version +ARG cabal_version + +RUN curl "https://downloads.haskell.org/~ghcup/$ghcup_version/x86_64-linux-ghcup-$ghcup_version" --output /usr/bin/ghcup \ + && chmod +x /usr/bin/ghcup \ + && ghcup install ghc $ghc_version --set \ + && ghcup install cabal $cabal_version --set + +FROM builder AS run + +LABEL vendor="QBayLogic B.V." maintainer="devops@qbaylogic.com" +ENV DEBIAN_FRONTEND=noninteractive LANG=C.UTF-8 LC_ALL=C.UTF-8 PATH="$PATH:/opt/bin:/root/.ghcup/bin" + +ARG DEPS_RUNTIME="gnupg pkg-config openjdk-8-jdk gdb-multiarch picocom libtinfo5 libtinfo-dev build-essential curl libc6-dev libgmp10-dev python3 ccache libftdi1 libhidapi-hidraw0 libusb-1.0-0 libyaml-0-2" +RUN apt-get update \ + && apt-get install -y --no-install-recommends $DEPS_RUNTIME \ + && echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | tee /etc/apt/sources.list.d/sbt.list \ + && echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | tee /etc/apt/sources.list.d/sbt_old.list \ + && curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | apt-key add \ + && apt-get update \ + && apt-get install -y --no-install-recommends sbt \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=build-verilator /opt /opt +COPY --from=build-openocd-vexriscv /opt /opt +COPY --from=build-ghc /root/.ghcup /root/.ghcup diff --git a/.github/docker/build-and-publish-docker-image.sh b/.github/docker/build-and-publish-docker-image.sh new file mode 100755 index 0000000..8c47cb3 --- /dev/null +++ b/.github/docker/build-and-publish-docker-image.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: 2024 Google LLC + +# SPDX-License-Identifier: CC0-1.0 +set -xeo pipefail + +REPO="ghcr.io/clash-lang" +NAME="clash-vexriscv-ci" +DIR=$(dirname "$0") +now=$(date +%Y%m%d) + +if [[ "$1" == "-y" ]]; then + push=y +elif [[ "$1" != "" ]]; then + echo "Unrecognized argument: $1" >&2 + exit 1 +fi + +UBUNTU_VERSION=jammy-20240125 +GHC_VERSIONS=( "9.4.8" "9.2.8" "9.0.2") +CABAL_VERSIONS=("3.10.2.0" "3.10.2.0" "3.10.2.0") + +for i in "${!GHC_VERSIONS[@]}" +do + GHC_VERSION="${GHC_VERSIONS[i]}" + CABAL_VERSION="${CABAL_VERSIONS[i]}" + + docker buildx build \ + --build-arg UBUNTU_VERSION=${UBUNTU_VERSION} \ + --build-arg cabal_version=${CABAL_VERSION} \ + --build-arg ghc_version=${GHC_VERSION} \ + -t "${REPO}/${NAME}:${GHC_VERSION}-$now" \ + "$DIR" +done + +if [[ "${push}" == "" ]]; then + read -p "Push to GitHub? (y/N) " push +fi + +if [[ $push =~ ^[Yy]$ ]]; then + for i in "${!GHC_VERSIONS[@]}" + do + GHC_VERSION="${GHC_VERSIONS[i]}" + docker push "${REPO}/${NAME}:${GHC_VERSION}-$now" + done +else + echo "Skipping push to container registry" +fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edf1b89..a6e431f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,7 @@ jobs: run: | apt-get update apt-get install -y curl build-essential + - uses: actions-rs/toolchain@v1 with: toolchain: 1.67 # See Note [Updating Rust versions] @@ -69,7 +70,6 @@ jobs: run: | apt-get update apt-get install -y curl build-essential - - uses: actions-rs/toolchain@v1 with: toolchain: 1.67.1 # See Note [Updating Rust versions] @@ -116,7 +116,7 @@ jobs: - "9.4.8" container: - image: ghcr.io/clash-lang/clash-ci:${{ matrix.ghc }}-20240221 + image: ghcr.io/clash-lang/clash-vexriscv-ci:${{ matrix.ghc }}-20240329 steps: - name: Checkout @@ -132,27 +132,9 @@ jobs: with: path: | ~/.local/state/cabal/store/ - key: packages-cachebust-2-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze', 'cabal.project') }} - restore-keys: packages-cachebust-2-${{ matrix.ghc }} + key: packages-cachebust-3-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze', 'cabal.project') }} + restore-keys: packages-cachebust-3-${{ matrix.ghc }} - - name: Install build deps - run: | - apt-get update - apt-get install gnupg pkg-config -y - - name: Install Java - run: | - # install Java 8 - apt-get update - apt-get install openjdk-8-jdk -y - update-alternatives --config java - update-alternatives --config javac - - name: Install SBT - run: | - echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | tee /etc/apt/sources.list.d/sbt.list - echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | tee /etc/apt/sources.list.d/sbt_old.list - curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | apt-key add - apt-get update - apt-get install sbt -y - name: Stash existing VexRiscv.v run: | cp clash-vexriscv/example-cpu/VexRiscv.v clash-vexriscv/example-cpu/VexRiscv.v.comitted From 28535014d99f5ab068cd3561e8971490a0cbd0ed Mon Sep 17 00:00:00 2001 From: Martijn Bastiaan Date: Fri, 29 Mar 2024 21:27:04 +0100 Subject: [PATCH 2/3] Enable JTAG tests Fixes #24 --- .github/workflows/ci.yml | 4 + Cargo.lock | 10 -- Cargo.toml | 1 - .../test-programs/src/bin/print_a.expected | 1 + .../test-programs}/src/bin/print_a.rs | 0 .../test-programs/src/bin/print_b.expected | 1 + .../test-programs}/src/bin/print_b.rs | 0 clash-vexriscv-sim/tests/Tests/Jtag.hs | 19 +++- clash-vexriscv-sim/tests/tests.hs | 11 +- debug-test/Cargo.toml | 18 --- debug-test/build.rs | 23 ---- debug-test/memory.x | 18 --- debug-test/src/main.rs | 106 ------------------ 13 files changed, 29 insertions(+), 183 deletions(-) create mode 100644 clash-vexriscv-sim/test-programs/src/bin/print_a.expected rename {debug-test => clash-vexriscv-sim/test-programs}/src/bin/print_a.rs (100%) create mode 100644 clash-vexriscv-sim/test-programs/src/bin/print_b.expected rename {debug-test => clash-vexriscv-sim/test-programs}/src/bin/print_b.rs (100%) delete mode 100644 debug-test/Cargo.toml delete mode 100644 debug-test/build.rs delete mode 100644 debug-test/memory.x delete mode 100644 debug-test/src/main.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6e431f..6cf4d0c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -162,6 +162,10 @@ jobs: run: | tar -x -f vexriscv-test-binaries.tar + - name: OpenOCD bin symlink + run: | + ln -s /opt/bin/openocd /opt/bin/openocd-vexriscv + - name: Run `clash-vexriscv` unittests run: | cabal run clash-vexriscv:unittests diff --git a/Cargo.lock b/Cargo.lock index 2725653..1e0609d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,16 +44,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" -[[package]] -name = "debug-test" -version = "0.1.0" -dependencies = [ - "heapless", - "panic-halt", - "riscv", - "riscv-rt", -] - [[package]] name = "embedded-hal" version = "0.2.7" diff --git a/Cargo.toml b/Cargo.toml index 10b2165..596decd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,5 @@ opt-level = "z" [workspace] members = [ "clash-vexriscv-sim/test-programs", - "debug-test", ] resolver = "2" diff --git a/clash-vexriscv-sim/test-programs/src/bin/print_a.expected b/clash-vexriscv-sim/test-programs/src/bin/print_a.expected new file mode 100644 index 0000000..24ebbee --- /dev/null +++ b/clash-vexriscv-sim/test-programs/src/bin/print_a.expected @@ -0,0 +1 @@ +[CPU] a diff --git a/debug-test/src/bin/print_a.rs b/clash-vexriscv-sim/test-programs/src/bin/print_a.rs similarity index 100% rename from debug-test/src/bin/print_a.rs rename to clash-vexriscv-sim/test-programs/src/bin/print_a.rs diff --git a/clash-vexriscv-sim/test-programs/src/bin/print_b.expected b/clash-vexriscv-sim/test-programs/src/bin/print_b.expected new file mode 100644 index 0000000..7280e73 --- /dev/null +++ b/clash-vexriscv-sim/test-programs/src/bin/print_b.expected @@ -0,0 +1 @@ +[CPU] b diff --git a/debug-test/src/bin/print_b.rs b/clash-vexriscv-sim/test-programs/src/bin/print_b.rs similarity index 100% rename from debug-test/src/bin/print_b.rs rename to clash-vexriscv-sim/test-programs/src/bin/print_b.rs diff --git a/clash-vexriscv-sim/tests/Tests/Jtag.hs b/clash-vexriscv-sim/tests/Tests/Jtag.hs index 50948a1..8d87b4e 100644 --- a/clash-vexriscv-sim/tests/Tests/Jtag.hs +++ b/clash-vexriscv-sim/tests/Tests/Jtag.hs @@ -7,9 +7,11 @@ module Tests.Jtag where import Prelude +import Control.Applicative ((<|>)) import Control.Monad.Extra (ifM) import Data.List.Extra (trim) import Data.Maybe (fromJust) +import System.Directory (findExecutable) import System.Exit import System.IO import System.Process @@ -38,9 +40,20 @@ getOpenOcdCfgPath = getDataFileName "data/vexriscv_sim.cfg" getGdbCmdPath :: IO FilePath getGdbCmdPath = getDataFileName "data/vexriscv_gdb.cfg" +getGdb :: HasCallStack => IO String +getGdb = do + gdbMultiArch <- findExecutable "gdb-multiarch" + gdb <- findExecutable "gdb" + case gdbMultiArch <|> gdb of + Nothing -> fail "Neither gdb-multiarch nor gdb found in PATH" + Just x -> pure x + expectLine :: Handle -> String -> Assertion expectLine h expected = do line <- hGetLine h + -- Uncomment for debugging: + -- hPutStr stderr "> " + -- hPutStrLn stderr line ifM (pure $ null line) (expectLine h expected) @@ -49,6 +62,9 @@ expectLine h expected = do waitForLine :: Handle -> String -> IO () waitForLine h expected = do line <- hGetLine h + -- Uncomment for debugging: + -- hPutStr stderr "> " + -- hPutStrLn stderr line if line == expected then pure () else waitForLine h expected @@ -67,6 +83,7 @@ test = do projectRoot <- getProjectRoot openocdCfgPath <- getOpenOcdCfgPath gdbCmdPath <- getGdbCmdPath + gdb <- getGdb let vexRiscvProc = (proc simulateExecPath [printElfPath]){ @@ -79,7 +96,7 @@ test = do , cwd = Just projectRoot } - gdbProc = (proc "gdb" ["--command", gdbCmdPath]){ + gdbProc = (proc gdb ["--command", gdbCmdPath]){ std_out = CreatePipe, -- Comment this line to see GDB output cwd = Just projectRoot } diff --git a/clash-vexriscv-sim/tests/tests.hs b/clash-vexriscv-sim/tests/tests.hs index 022e27b..bbd108b 100644 --- a/clash-vexriscv-sim/tests/tests.hs +++ b/clash-vexriscv-sim/tests/tests.hs @@ -10,6 +10,7 @@ import qualified Data.List as L import Control.Monad (forM) import Data.Maybe (catMaybes, mapMaybe) +import Data.Tuple.Extra (fst3) import Data.Word (Word8) import GHC.Base (when) import System.Directory (copyFile, doesFileExist, listDirectory) @@ -23,8 +24,7 @@ import Test.Tasty.HUnit (Assertion, testCase, (@?=)) import Utils.ProgramLoad (loadProgramDmem) import Utils.Cpu (cpu) --- XXX: Disabled, we need to add OpenOCD + GDB to CI (or use the Nix shell?) --- import qualified Tests.Jtag +import qualified Tests.Jtag runProgramExpect :: -- | action to copy ELF file @@ -109,8 +109,8 @@ runTest name mode n elfPath expectPath = main :: IO () main = do - debugTests <- findTests sourceDir debugBinDir - releaseTests <- findTests sourceDir releaseBinDir + debugTests <- L.sortOn fst3 <$> findTests sourceDir debugBinDir + releaseTests <- L.sortOn fst3 <$> findTests sourceDir releaseBinDir when (L.null debugTests) $ do hPutStrLn stderr "No debug tests found! Was `cargo build` run?" @@ -131,8 +131,7 @@ main = do "VexRiscv Tests" [ testGroup "Debug builds" debugTestCases , testGroup "Release builds" releaseTestCases - -- XXX: Disabled, we need to add OpenOCD + GDB to CI (or use the Nix shell?) - -- , Tests.Jtag.tests + , Tests.Jtag.tests ] defaultMain tests diff --git a/debug-test/Cargo.toml b/debug-test/Cargo.toml deleted file mode 100644 index 65c1785..0000000 --- a/debug-test/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-FileCopyrightText: 2022 Google LLC -# -# SPDX-License-Identifier: CC0-1.0 - -[package] -name = "debug-test" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -authors = ["Google LLC"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -riscv-rt = "0.11.0" -riscv = "^0.10" -heapless = { version = "0.7", default-features = false } -panic-halt = "0.2.0" diff --git a/debug-test/build.rs b/debug-test/build.rs deleted file mode 100644 index 0d6ad00..0000000 --- a/debug-test/build.rs +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Google LLC -// -// SPDX-License-Identifier: Apache-2.0 - -use std::env; -use std::fs; -use std::path::Path; - -/// Put the linker script somewhere the linker can find it. -fn main() { - let out_dir = env::var("OUT_DIR").expect("No out dir"); - let dest_path = Path::new(&out_dir).join("memory.x"); - fs::write(dest_path, include_bytes!("memory.x")).expect("Could not write file"); - - if env::var("CARGO_CFG_TARGET_ARCH").unwrap() == "riscv32" { - println!("cargo:rustc-link-arg=-Tmemory.x"); - println!("cargo:rustc-link-arg=-Tlink.x"); // linker script from riscv-rt - } - println!("cargo:rustc-link-search={out_dir}"); - - println!("cargo:rerun-if-changed=memory.x"); - println!("cargo:rerun-if-changed=build.rs"); -} diff --git a/debug-test/memory.x b/debug-test/memory.x deleted file mode 100644 index 211d12c..0000000 --- a/debug-test/memory.x +++ /dev/null @@ -1,18 +0,0 @@ -/* -SPDX-FileCopyrightText: 2022 Google LLC - -SPDX-License-Identifier: CC0-1.0 -*/ - -MEMORY -{ - DATA : ORIGIN = 0x40000000, LENGTH = 512K - INSTR : ORIGIN = 0x20000000, LENGTH = 512K -} - -REGION_ALIAS("REGION_TEXT", INSTR); -REGION_ALIAS("REGION_RODATA", DATA); -REGION_ALIAS("REGION_DATA", DATA); -REGION_ALIAS("REGION_BSS", DATA); -REGION_ALIAS("REGION_HEAP", DATA); -REGION_ALIAS("REGION_STACK", DATA); diff --git a/debug-test/src/main.rs b/debug-test/src/main.rs deleted file mode 100644 index de1d685..0000000 --- a/debug-test/src/main.rs +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Google LLC -// -// SPDX-License-Identifier: Apache-2.0 - -#![no_std] -#![cfg_attr(not(test), no_main)] - -use core::fmt::Write; - -use heapless::String; -#[cfg(not(test))] -use riscv_rt::entry; - -#[cfg(not(test))] -extern crate panic_halt; - -const ADDR: *mut u8 = 0x0000_1000 as *mut u8; - -fn print(s: &str) { - for b in s.bytes() { - unsafe { - ADDR.write_volatile(b); - } - } -} - -#[cfg_attr(not(test), entry)] -fn main() -> ! { - print("hello, world.\n"); - - print("I am here to be debugged!\n"); - - loop { - for i in 0..30 { - let mut s = String::<16>::new(); - let _ = writeln!(s, "Hey! {i}"); - print(&s); - } - - print("wheeeey!\n"); - - // unsafe { - // riscv::asm::ebreak(); - // } - } -} - -#[export_name = "UserSoft"] -fn user_soft_handler() { - loop { - print("INTERRUPT UserSoft"); - } -} - -#[export_name = "MachineSoft"] -fn machine_soft_handler() { - loop { - print("INTERRUPT MachineSoft"); - } -} - -#[export_name = "UserTimer"] -fn user_timer_handler() { - loop { - print("INTERRUPT UserTimer"); - } -} - -#[export_name = "MachineTimer"] -fn machine_timer_handler() { - loop { - print("INTERRUPT MachineTimer"); - } -} - -#[export_name = "UserExternal"] -fn user_ext_handler() { - loop { - print("INTERRUPT UserExternal"); - } -} - -#[export_name = "MachineExternal"] -fn machine_ext_handler() { - loop { - print("INTERRUPT MachineExternal"); - } -} - -#[export_name = "DefaultHandler"] -fn default_handler() { - loop { - print("INTERRUPT default handler"); - } -} - -#[export_name = "ExceptionHandler"] -fn exception_handler(_trap_frame: &riscv_rt::TrapFrame) -> ! { - riscv::interrupt::free(|| { - print("... caught an exception. Looping forever now.\n"); - }); - loop { - // print(""); - continue; - } -} From e15cee8035b7850ba616cec8170fe6e6ff515dc6 Mon Sep 17 00:00:00 2001 From: Martijn Bastiaan Date: Wed, 3 Apr 2024 12:08:44 +0200 Subject: [PATCH 3/3] Add `--jtag-debug` option to Tasty testsuite --- clash-vexriscv-sim/tests/Tests/Jtag.hs | 64 +++++++++++++++++--------- clash-vexriscv-sim/tests/tests.hs | 6 ++- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/clash-vexriscv-sim/tests/Tests/Jtag.hs b/clash-vexriscv-sim/tests/Tests/Jtag.hs index 8d87b4e..02f2bee 100644 --- a/clash-vexriscv-sim/tests/Tests/Jtag.hs +++ b/clash-vexriscv-sim/tests/Tests/Jtag.hs @@ -8,9 +8,10 @@ module Tests.Jtag where import Prelude import Control.Applicative ((<|>)) -import Control.Monad.Extra (ifM) +import Control.Monad.Extra (ifM, when) import Data.List.Extra (trim) import Data.Maybe (fromJust) +import Data.Proxy import System.Directory (findExecutable) import System.Exit import System.IO @@ -18,9 +19,19 @@ import System.Process import Test.Tasty import Test.Tasty.HUnit +import Test.Tasty.Options import Paths_clash_vexriscv_sim (getDataFileName) +newtype JtagDebug = JtagDebug Bool + +instance IsOption JtagDebug where + defaultValue = JtagDebug False + parseValue = fmap JtagDebug . safeReadBool + optionName = return "jtag-debug" + optionHelp = return "While waiting for outputs of subprocesses, print them to stderr" + optionCLParser = flagCLParser Nothing (JtagDebug True) + cabalListBin :: String -> IO FilePath cabalListBin name = do trim <$> readProcess "cabal" ["-v0", "list-bin", name] "" @@ -48,26 +59,26 @@ getGdb = do Nothing -> fail "Neither gdb-multiarch nor gdb found in PATH" Just x -> pure x -expectLine :: Handle -> String -> Assertion -expectLine h expected = do +expectLine :: Bool -> Handle -> String -> Assertion +expectLine debug h expected = do line <- hGetLine h - -- Uncomment for debugging: - -- hPutStr stderr "> " - -- hPutStrLn stderr line + when debug $ do + hPutStr stderr "> " + hPutStrLn stderr line ifM (pure $ null line) - (expectLine h expected) + (expectLine debug h expected) (expected @?= line) -waitForLine :: Handle -> String -> IO () -waitForLine h expected = do +waitForLine :: Bool -> Handle -> String -> IO () +waitForLine debug h expected = do line <- hGetLine h - -- Uncomment for debugging: - -- hPutStr stderr "> " - -- hPutStrLn stderr line + when debug $ do + hPutStr stderr "> " + hPutStrLn stderr line if line == expected then pure () - else waitForLine h expected + else waitForLine debug h expected -- | Run three processes in parallel: -- @@ -76,8 +87,11 @@ waitForLine h expected = do -- 3. GDB. It connects to the OpenOCD GDB server and bunch of commands. See the -- file produced by 'getGdbCmdPath' for the commands. -- -test :: Assertion -test = do +test :: + -- | Print debug output of subprocesses + Bool -> + Assertion +test debug = do simulateExecPath <- getSimulateExecPath printElfPath <- getPrintElfPath projectRoot <- getProjectRoot @@ -103,25 +117,29 @@ test = do withCreateProcess vexRiscvProc $ \_ (fromJust -> vexRiscvStdOut) _ _ -> do hSetBuffering vexRiscvStdOut LineBuffering - expectLine vexRiscvStdOut "[CPU] a" + expectLine debug vexRiscvStdOut "[CPU] a" -- CPU has started, so we can start OpenOCD withCreateProcess openOcdProc $ \_ _ (fromJust -> openOcdStdErr) _ -> do hSetBuffering openOcdStdErr LineBuffering - waitForLine openOcdStdErr "Halting processor" + waitForLine debug openOcdStdErr "Halting processor" -- OpenOCD has started, so we can start GDB withCreateProcess gdbProc $ \_ _ _ gdbProcHandle -> do - expectLine vexRiscvStdOut "[CPU] a" - expectLine vexRiscvStdOut "[CPU] b" + expectLine debug vexRiscvStdOut "[CPU] a" + expectLine debug vexRiscvStdOut "[CPU] b" gdbExitCode <- waitForProcess gdbProcHandle ExitSuccess @?= gdbExitCode tests :: TestTree -tests = testGroup "JTAG" - [ testCase "Basic GDB commands, breakpoints, and program loading" test - ] +tests = askOption $ \(JtagDebug debug) -> + testGroup "JTAG" + [ testCase "Basic GDB commands, breakpoints, and program loading" (test debug) + ] main :: IO () -main = defaultMain tests +main = + defaultMainWithIngredients + (includingOptions [Option (Proxy :: Proxy JtagDebug)] : defaultIngredients) + tests diff --git a/clash-vexriscv-sim/tests/tests.hs b/clash-vexriscv-sim/tests/tests.hs index bbd108b..bf97a13 100644 --- a/clash-vexriscv-sim/tests/tests.hs +++ b/clash-vexriscv-sim/tests/tests.hs @@ -10,6 +10,7 @@ import qualified Data.List as L import Control.Monad (forM) import Data.Maybe (catMaybes, mapMaybe) +import Data.Proxy import Data.Tuple.Extra (fst3) import Data.Word (Word8) import GHC.Base (when) @@ -20,6 +21,7 @@ import System.IO import System.IO.Temp (withSystemTempFile) import Test.Tasty import Test.Tasty.HUnit (Assertion, testCase, (@?=)) +import Test.Tasty.Options import Utils.ProgramLoad (loadProgramDmem) import Utils.Cpu (cpu) @@ -134,4 +136,6 @@ main = do , Tests.Jtag.tests ] - defaultMain tests + defaultMainWithIngredients + (includingOptions [Option (Proxy :: Proxy Tests.Jtag.JtagDebug)] : defaultIngredients) + tests