Skip to content

Commit

Permalink
clash-ffi: fix example (#2445)
Browse files Browse the repository at this point in the history
* Add missing SimAction arguments

* Fix FFI example termination

* Fix `ffi:example` CI

It did not check the exit codes, continuing after an error and
ultimately reporting success.

`ffi:example` does not profit from having the `build` job's artifact
available, so we remove that dependency. Now `ffi:example` can run
earlier in the CI pipeline.

`ffi:interface-tests` is moved to public runners as it runs in a single
minute.

---------

Co-authored-by: Felix Klein <felix@qbaylogic.com>
Co-authored-by: Peter Lebbing <peter@digitalbrains.com>
  • Loading branch information
3 people authored Apr 7, 2023
1 parent 29ee170 commit 117e2ba
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 33 deletions.
39 changes: 28 additions & 11 deletions .ci/gitlab/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ prelude:doctests:
script:
- ./dist-newstyle/build/*/*/clash-prelude-*/t/doctests/build/doctests/doctests -j${THREADS}

ffi:interface-tests:
extends: .test-nocache
script:
- ./dist-newstyle/build/*/*/clash-ffi-*/x/ffi-interface-tests/build/ffi-interface-tests/ffi-interface-tests --smallcheck-max-count 2000

# Tests run on local fast machines:

# Normally, this job is small. But it is flaky on GHC 9.2; it sometimes fails
Expand Down Expand Up @@ -133,18 +138,30 @@ suite:cores:
- local
- vivado-2022.1-standard

ffi:interface-tests:
extends: .test-cache-local
ffi:example:
extends: .common-local
stage: test
needs: []
before_script:
- unset SNAPCRAFT_LOGIN_FILE
- unset HACKAGE_PASSWORD
- export THREADS=$(./.ci/effective_cpus.sh)
- export CABAL_JOBS=$(./.ci/effective_cpus.sh)
- export clash_lib_datadir=$(pwd)/clash-lib/
- export clash_cosim_datadir=$(pwd)/clash-cosim/
- export MASKBINS="$(mktemp -d)"
- PATH="$MASKBINS:$PATH"
- export
- tar -xf cache.tar.zst -C / || true
# The iverilog on CI cannot run the example, we only test it builds
- ln -s /bin/true "$MASKBINS/iverilog"
- ln -s /bin/true "$MASKBINS/vvp"
- ls -al "$MASKBINS"
- .ci/setup.sh
script:
- ./dist-newstyle/build/*/*/clash-ffi-*/x/ffi-interface-tests/build/ffi-interface-tests/ffi-interface-tests --smallcheck-max-count 2000

# Disabled for now. The test is faulty and so is the tested code. This will be
# fixed later.
#ffi:example:
# extends: .test-cache-local
# script:
# - cabal build clash # ensure clash has been built (avoids some legacy cabal issue)
# - cd clash-ffi/example && ./run-iverilog.sh
- cd clash-ffi/example && ./run-iverilog.sh
after_script:
- tar -cf - /root/.cabal | zstd -T${THREADS} -3 > cache.tar.zst

# Tests run on local fast machines with Vivado installed. We only run these at night
# to save resources - as Vivado is quite slow to execute.
Expand Down
36 changes: 17 additions & 19 deletions clash-ffi/example/Simulate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import Data.Coerce (Coercible)
import Data.Typeable (Typeable)
import Data.Bits (complement)
import Data.List (intercalate, zip5)
import Control.Monad (when, void)
import Control.Exception (SomeException, try)
import Control.Monad (void)
import Control.Monad.IO.Class (liftIO)
import Foreign.C.String (newCString)
import Foreign.Marshal.Alloc (free)
Expand All @@ -23,6 +24,7 @@ import Clash.FFI.Monad
import Clash.FFI.VPI.Info
import Clash.FFI.VPI.IO
import Clash.FFI.VPI.Callback
import Clash.FFI.VPI.Control
import Clash.FFI.VPI.Module
import Clash.FFI.VPI.Object
import Clash.FFI.VPI.Port
Expand Down Expand Up @@ -106,16 +108,6 @@ ffiMain = runSimAction $ do
putStrLn " STEP ; CLK ; RST ; ENB ; OPC ; RESULT"
putStrLn "------;------;------;------;----------------------;----------------------"

void $ registerCallback
CallbackInfo
{ cbReason = EndOfSimulation
, cbRoutine = const $ do
runSimAction (putStrLn "" >> putStrLn "[ Simulation done ]")
return 0
, cbIndex = 0
, cbData = B.empty
}

nextCB ReadWriteSynch 0 assignInputs

where
Expand All @@ -130,7 +122,7 @@ ffiMain = runSimAction $ do
4 -> "<=>" -- mixed input-output
_ -> "x" -- no direction

assignInputs :: (?state :: State) => SimAction
assignInputs :: (?state :: State) => SimAction ()
assignInputs = do
SimTime time <- receiveTime Sim $ Just top

Expand Down Expand Up @@ -171,7 +163,7 @@ assignInputs = do
sendValue port (BitVectorVal SNat $ pack v) $ InertialDelay $ SimTime 0
return $ Just v

readOutputs :: (?state :: State) => SimAction
readOutputs :: (?state :: State) => SimAction ()
readOutputs = do
SimTime time <- receiveTime Sim $ Just top
receiveValue VectorFmt dataOut >>= \case
Expand All @@ -182,9 +174,15 @@ readOutputs = do
}
_ -> return ()

when (steps > 0) $ do
if (steps > 0) then do
let ?state = ?state { steps = steps - 1 }
nextCB ReadWriteSynch 1 assignInputs
else do
putStrLn ""
putStrLn "[ Simulation done ]"

liftIO $ void $ try @SomeException $ runSimAction
$ controlSimulator $ Finish NoDiagnostics

where
State{..} = ?state
Expand Down Expand Up @@ -228,8 +226,8 @@ updates = Updates 0 Nothing Nothing Nothing Nothing Nothing
nextCB ::
(Maybe Object -> Time -> CallbackReason) ->
Int64 ->
SimAction ->
SimAction
SimAction () ->
SimAction ()
nextCB reason time action =
void $ registerCallback
CallbackInfo
Expand All @@ -248,11 +246,11 @@ getByName m name = do
liftIO $ free ref
return obj

putStr :: String -> SimAction
putStr :: String -> SimAction ()
putStr = simPutStr . B.pack

putStrLn :: String -> SimAction
putStrLn :: String -> SimAction ()
putStrLn = simPutStrLn . B.pack

print :: Show a => a -> SimAction
print :: Show a => a -> SimAction ()
print = simPutStrLn . B.pack . show
2 changes: 2 additions & 0 deletions clash-ffi/example/cabal.project
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
packages: . .. ../../clash-ghc ../../clash-lib ../../clash-prelude

write-ghc-environment-files: always
7 changes: 4 additions & 3 deletions clash-ffi/example/run-iverilog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ EXAMPLES=../../examples

###############################

${CABAL} build clash-ffi-example
${CLASH} --verilog -i${EXAMPLES} ${EXAMPLES}/Calculator.hs
${IVERILOG} verilog/Calculator.topEntity/topEntity.v -o Calculator.vvp
${CABAL} build clash-ffi-example || exit $?
${CLASH} --verilog -i${EXAMPLES} ${EXAMPLES}/Calculator.hs || exit $?
${IVERILOG} verilog/Calculator.topEntity/topEntity.v -o Calculator.vvp \
|| exit $?
echo ""
echo "Running Icarus Verilog VVP runtime engine:"
echo ""
Expand Down
37 changes: 37 additions & 0 deletions clash-ffi/example/run-vsim.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/bin/sh

# This is just a minimalistic script for demonstrating the process of
# running the clash-ffi example using the ModelSim / QuestaSim runtime
# engine. The script is not designed to work in any possible system
# environment and may not work immediately for you. It is intended to
# serve as an easy starter instead. Adapt it to your needs if it's not
# working out-of-the-box for you.

###############################

# Adjust these variables if the tools are not in your PATH already

# Cabal
# https://www.haskell.org/cabal
CABAL=cabal
# Clash
# https://github.com/clash-lang/clash-compiler
CLASH="${CABAL} run clash --"
# ModelSim / QuestaSim binaries
VLIB=vlib
VLOG=vlog
VSIM=vsim
# Clash examples folder
# https://github.com/clash-lang/clash-compiler/tree/master/examples
EXAMPLES=../../examples

###############################

${CABAL} build clash-ffi-example || exit $?
${CLASH} --verilog -i${EXAMPLES} ${EXAMPLES}/Calculator.hs || exit $?
${VLIB} work || exit $?
${VLOG} verilog/Calculator.topEntity/topEntity.v || exit $?
echo ""
echo "Running Simulation Runtime Engine:"
echo ""
${VSIM} -no_autoacc -c -do "onfinish exit; run -all" topEntity -pli lib/libclash-ffi-example.vpl

0 comments on commit 117e2ba

Please sign in to comment.