Skip to content

Commit

Permalink
don't use bracket pattern for program-handles
Browse files Browse the repository at this point in the history
  • Loading branch information
hydrolarus committed Oct 23, 2024
1 parent 538e20b commit 962553d
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 84 deletions.
8 changes: 0 additions & 8 deletions .github/synthesis/debug.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,4 @@
[
{
"top": "boardTestExtended",
"stage": "test"
},
{
"top": "boardTestSimple",
"stage": "test"
},
{
"top": "vexRiscvTest",
"stage": "test"
Expand Down
8 changes: 4 additions & 4 deletions bittide-experiments/src/Bittide/Hitl.hs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ data HitlTestGroup where
, extraXdcFiles :: [String]
, testCases :: [HitlTestCase HwTargetRef a b c]
-- ^ List of test cases
, mPreProc :: (VivadoHandle -> String -> HwTarget -> IO (TestStepResult c))
, mPreProc :: (VivadoHandle -> String -> FilePath -> HwTarget -> IO (TestStepResult c))
-- ^ Pre-processing step. First argument is the name of the test
, mMonitorProc :: Maybe (VivadoHandle -> String -> FilePath -> [(HwTarget, c)] -> IO ExitCode)
-- ^ Optional monitoring process.
Expand Down Expand Up @@ -216,7 +216,7 @@ deriving instance Show (HitlTestCase h a b c)

data CasePreProcessing c
= InheritPreProcess
| CustomPreProcess (VivadoHandle -> HwTarget -> IO (TestStepResult c))
| CustomPreProcess (VivadoHandle -> FilePath -> HwTarget -> IO (TestStepResult c))

instance Show (CasePreProcessing a) where
show InheritPreProcess = "InheritPreProcess"
Expand All @@ -239,8 +239,8 @@ instance MayHavePostProcData a where
instance MayHavePostProcData () where
mGetPPD = Map.fromList . map ((,Nothing) . name)

noPreProcess :: VivadoHandle -> String -> HwTarget -> IO (TestStepResult ())
noPreProcess _ _ _ = pure (TestStepSuccess ())
noPreProcess :: VivadoHandle -> String -> FilePath -> HwTarget -> IO (TestStepResult ())
noPreProcess _ _ _ _ = pure (TestStepSuccess ())

-- | Obtain a list of the hardware targets that are relevant for a given HITL test.
hwTargetRefsFromHitlTestGroup :: HitlTestGroup -> [HwTargetRef]
Expand Down
98 changes: 57 additions & 41 deletions bittide-instances/src/Bittide/Instances/Hitl/Pre/Program.hs
Original file line number Diff line number Diff line change
Expand Up @@ -100,58 +100,74 @@ waitForLine h expected =
-- through code.
--

{-
case_testGdbProgram :: Assertion
case_testGdbProgram = do
data ProcessStdIoHandles = ProcessStdIoHandles
{ stdinHandle :: Handle
, stdoutHandle :: Handle
, stderrHandle :: Handle
}

data RemoteConnectionData = RemoteConnectionData
{ openOcd :: ProcessStdIoHandles
, gdb :: ProcessStdIoHandles
, picocom :: ProcessStdIoHandles
, cleanup :: IO ()
}

startOpenOcd :: IO (ProcessStdIoHandles, IO ())
startOpenOcd = do
startOpenOcdPath <- getOpenOcdStartPath
startPicocomPath <- getPicocomStartPath
uartDev <- getUartDev
let
openOcdProc = (proc startOpenOcdPath []){std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe}

gdbProc <- getGdbProgPath
ocdHandles@(openOcdStdin, openOcdStdout, openOcdStderr, _openOcdPh) <-
createProcess openOcdProc

withAnnotatedGdbProgPath gdbProc $ \gdbProgPath -> do
let
openOcdProc = (proc startOpenOcdPath []){std_err = CreatePipe}
picocomProc = (proc startPicocomPath [uartDev]){std_out = CreatePipe, std_in = CreatePipe}
gdbProc = (proc "gdb" ["--command", gdbProgPath]){std_out = CreatePipe, std_err = CreatePipe}
let
ocdHandles' = ProcessStdIoHandles
{ stdinHandle = fromJust openOcdStdin
, stdoutHandle = fromJust openOcdStdout
, stderrHandle = fromJust openOcdStderr
}

-- Wait until we see "Halting processor", fail if we see an error
waitForHalt s
| "Error:" `isPrefixOf` s = Stop (Error ("Found error in OpenOCD output: " <> s))
| "Halting processor" `isPrefixOf` s = Stop Ok
| otherwise = Continue
pure (ocdHandles', cleanupProcess ocdHandles)

withCreateProcess openOcdProc $ \_ _ (fromJust -> openOcdStdErr) _ -> do
hSetBuffering openOcdStdErr LineBuffering
expectLine openOcdStdErr waitForHalt
startGdb :: IO (ProcessStdIoHandles, IO ())
startGdb = do
let
gdbProc = (proc "gdb" []){std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe}

-- XXX: Picocom doesn't immediately clean up after closing, because it
-- spawns as a child of the shell (start.sh). We could use 'exec' to
-- make sure the intermediate shell doesn't exist, but this causes
-- the whole test program to exit with signal 15 (??????).
withCreateProcess picocomProc $ \maybePicocomStdIn maybePicocomStdOut _ _ -> do
let
picocomStdIn = fromJust maybePicocomStdIn
picocomStdOut = fromJust maybePicocomStdOut
gdbHandles@(gdbStdin, gdbStdout, gdbStderr, _gdbPh) <-
createProcess gdbProc

hSetBuffering picocomStdIn LineBuffering
hSetBuffering picocomStdOut LineBuffering
let
gdbHandles' = ProcessStdIoHandles
{ stdinHandle = fromJust gdbStdin
, stdoutHandle = fromJust gdbStdout
, stderrHandle = fromJust gdbStderr
}

waitForLine picocomStdOut "Terminal ready"
pure (gdbHandles', cleanupProcess gdbHandles)

withCreateProcess gdbProc $ \_ (fromJust -> gdbStdOut) _ _ -> do
-- Wait for GDB to program the FPGA. If successful, we should see
-- "going in echo mode" in the picocom output.
hSetBuffering gdbStdOut LineBuffering
waitForLine picocomStdOut "Going in echo mode!"
startPicocom :: IO (ProcessStdIoHandles, IO ())
startPicocom = do
startPicocomPath <- getPicocomStartPath
uartDev <- getUartDev

let
picocomProc = (proc startPicocomPath [uartDev]){std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe}

picoHandles@(picoStdin, picoStdout, picoStderr, _picoPh) <-
createProcess picocomProc

let
picoHandles' = ProcessStdIoHandles
{ stdinHandle = fromJust picoStdin
, stdoutHandle = fromJust picoStdout
, stderrHandle = fromJust picoStderr
}

-- Wait for GDB to reach its last command - where it will wait indefinitely
waitForLine gdbStdOut "> continue"
pure (picoHandles', cleanupProcess picoHandles)

-- Test UART echo
hPutStrLn picocomStdIn "Hello, UART!"
waitForLine picocomStdOut "Hello, UART!"
-}

runGdbPicocomOpenOcd ::
-- | Path to the GDB script to run
Expand Down
116 changes: 88 additions & 28 deletions bittide-instances/src/Bittide/Instances/Hitl/VexRiscv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# OPTIONS_GHC -fplugin=Protocols.Plugin #-}

-- {-# OPTIONS -fplugin-opt=Protocols.Plugin:debug #-}
Expand Down Expand Up @@ -32,7 +33,8 @@ import Bittide.ProcessingElement
import Bittide.SharedTypes
import Bittide.Wishbone

import Paths_bittide_instances
import Data.List (isPrefixOf)
import Control.Monad (forM_)

import System.IO
import System.Exit
Expand Down Expand Up @@ -187,51 +189,109 @@ Run `verifyHitlVio` beforehand to ensure that the probe is available.
getProbeTestStartTcl :: String
getProbeTestStartTcl = getTestProbeTcl "*vioHitlt/probe_test_start"

monitorFunc :: VivadoHandle -> String -> FilePath -> [(HwTarget, c)] -> IO ExitCode
monitorFunc v _name ilaPath [(hwT, _preData)] = do
runGdbCommands :: Handle -> [String] -> IO ()
runGdbCommands h commands =
forM_ commands $ \command -> do
putStrLn $ "gdb-in: " <> command
hPutStrLn h command

gdbEcho :: String -> String
gdbEcho s = "echo \\n" <> s <> "\\n"

monitorFunc :: VivadoHandle -> String -> FilePath -> [(HwTarget, (ProcessStdIoHandles, ProcessStdIoHandles, ProcessStdIoHandles, IO ()))] -> IO ExitCode
monitorFunc v _name ilaPath [(hwT, (_ocd, pico, gdb, cleanup))] = do
openHwT v hwT
execCmd_ v "set_property" ["PROBES.FILE", embrace ilaPath, "[current_hw_device]"]
refresh_hw_device v []

gdbScript <- getDataFileName "data/gdb/test-gdb-prog"

execCmd_ v "set_property" ["OUTPUT_VALUE", "1", getProbeTestStartTcl]
commit_hw_vio v ["[get_hw_vios]"]

runGdbPicocomOpenOcd gdbScript $ \gdbOut (picocomIn, picocomOut) -> do
-- This is the first thing that will print when the FPGA has been programmed
-- and starts executing the new program.
waitForLine picocomOut "Going in echo mode!"
-- break test
do
putStrLn "Testing whether breakpoints work"

let breakCommands =
[ "break hello::test_success"
, "jump _start"
, gdbEcho "breakpoint reached"
]

runGdbCommands gdb.stdinHandle breakCommands
waitForLine gdb.stdoutHandle "breakpoint reached"

let continueCommands = [ "disable 1", gdbEcho "continuing", "continue" ]
runGdbCommands gdb.stdinHandle continueCommands
waitForLine gdb.stdoutHandle "continuing"

-- Wait for GDB to reach its last command - where it will wait indefinitely
waitForLine gdbOut "> continue"

-- Test UART echo
hPutStrLn picocomIn "Hello, UART!"
waitForLine picocomOut "Hello, UART!"

-- This is the first thing that will print when the FPGA has been programmed
-- and starts executing the new program.
waitForLine pico.stdoutHandle "Going in echo mode!"

-- Test UART echo
hPutStrLn pico.stdinHandle "Hello, UART!"
waitForLine pico.stdoutHandle "Hello, UART!"


execCmd_ v "set_property" ["OUTPUT_VALUE", "0", getProbeTestStartTcl]
commit_hw_vio v ["[get_hw_vios]"]

cleanup

pure $ ExitSuccess
monitorFunc _v _name _ilaPath _ = error "VexRiscv monitor func should only run with one hardware target"

preProcessFunc :: VivadoHandle -> String -> HwTarget -> IO (TestStepResult ())
preProcessFunc _v _name _hwT = do
pure $ TestStepSuccess ()
preProcessFunc ::
VivadoHandle ->
String ->
FilePath ->
HwTarget ->
IO (TestStepResult (ProcessStdIoHandles, ProcessStdIoHandles, ProcessStdIoHandles, IO ()))
preProcessFunc v _name ilaPath hwT = do
openHwT v hwT
execCmd_ v "set_property" ["PROBES.FILE", embrace ilaPath, "[current_hw_device]"]
refresh_hw_device v []

execCmd_ v "set_property" ["OUTPUT_VALUE", "1", getProbeTestStartTcl]
commit_hw_vio v ["[get_hw_vios]"]

(ocd, ocdClean) <- startOpenOcd

-- make sure OpenOCD is started properly
let
-- Wait until we see "Halting processor", fail if we see an error
waitForHalt s
| "Error:" `isPrefixOf` s = Stop (Error ("Found error in OpenOCD output: " <> s))
| "Halting processor" `isPrefixOf` s = Stop Ok
| otherwise = Continue

hSetBuffering ocd.stderrHandle LineBuffering
expectLine ocd.stderrHandle waitForHalt

-- gdbScript <- getDataFileName "data/gdb/test-gdb-prog"
-- make sure PicoCom is started properly
(pico, picoClean) <- startPicocom

hSetBuffering pico.stdinHandle LineBuffering
hSetBuffering pico.stdoutHandle LineBuffering

waitForLine pico.stdoutHandle "Terminal ready"

-- program the FPGA
(gdb, gdbClean) <- startGdb

hSetBuffering gdb.stdinHandle LineBuffering

let loadCommands =
[ "file \"./_build/cargo/firmware-binaries/riscv32imc-unknown-none-elf/debug/hello\""
, "target extended-remote :3333"
, "load"
, gdbEcho "load done"
]

-- runGdbPicocomOpenOcd gdbScript $ \gdbOut (picocomIn, picocomOut) -> do
-- -- This is the first thing that will print when the FPGA has been programmed
-- -- and starts executing the new program.
-- waitForLine picocomOut "Going in echo mode!"
runGdbCommands gdb.stdinHandle loadCommands

-- -- Wait for GDB to reach its last command - where it will wait indefinitely
-- waitForLine gdbOut "> continue"
waitForLine gdb.stdoutHandle "load done"

-- -- Test UART echo
-- hPutStrLn picocomIn "Hello, UART!"
-- waitForLine picocomOut "Hello, UART!"
-- pure ()
pure $ TestStepSuccess (ocd, pico, gdb, ocdClean >> picoClean >> gdbClean)
9 changes: 6 additions & 3 deletions bittide-shake/src/Clash/Shake/Vivado.hs
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ runHitlTestCase ::
-- | The HITL test case to run
HitlTestCase HwTarget a b c ->
-- | Pre-process function for the test group
(VivadoHandle -> String -> HwTarget -> IO (TestStepResult c)) ->
(VivadoHandle -> String -> FilePath -> HwTarget -> IO (TestStepResult c)) ->
-- | Monitor function
Maybe (VivadoHandle -> String -> FilePath -> [(HwTarget, c)] -> IO ExitCode) ->
-- | Path to the generated probes file
Expand Down Expand Up @@ -912,12 +912,12 @@ runHitlTestCase v testCase@HitlTestCase{..} preProcessFunc monitorFunc probesFil
putStrLn $
"Running test-group pre-process function for "
<> name <> " ('" <> prettyShow hwT <> "')"
preProcessFunc v name hwT
preProcessFunc v name probesFilePath hwT
CustomPreProcess f -> do
putStrLn $
"Running case pre-process function for "
<> name <> " ('" <> prettyShow hwT <> "')"
f v hwT
f v probesFilePath hwT


case testRunData of
Expand All @@ -940,8 +940,11 @@ runHitlTestCase v testCase@HitlTestCase{..} preProcessFunc monitorFunc probesFil

testCaseExitCode0 <- case monitorFunc of
Just fn -> do
putStrLn $ "Running custom monitor function for test " <> name
fn v name probesFilePath validTests
Nothing -> do
putStrLn $ "Running default monitor function for test " <> name

forM_ validTests $ \(hwT, _testData) -> do
-- Assert HitlVio start probe
openHwT v hwT
Expand Down

0 comments on commit 962553d

Please sign in to comment.