clash-prelude-0.7: src/CLaSH/Prelude/Testbench.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_HADDOCK show-extensions #-}
{-|
Copyright : (C) 2013-2015, University of Twente
License : BSD2 (see the file LICENSE)
Maintainer : Christiaan Baaij <christiaan.baaij@gmail.com>
-}
module CLaSH.Prelude.Testbench
( -- * Testbench functions for circuits synchronised to the system slock
assert
, stimuliGenerator
, outputVerifier
-- * Testbench functions for circuits synchronised to arbitrary clocks
, stimuliGenerator'
, outputVerifier'
)
where
import Control.Applicative ((<$>), liftA3)
import Debug.Trace (trace)
import GHC.TypeLits (KnownNat)
import Prelude hiding ((!!))
import CLaSH.Signal (Signal)
import CLaSH.Signal.Explicit (Signal', SClock, register', systemClock)
import CLaSH.Signal.Bundle (unbundle')
import CLaSH.Sized.Index (Index)
import CLaSH.Sized.Vector (Vec, (!!), maxIndex)
{-# INLINE stimuliGenerator #-}
-- | To be used as a one of the functions to create the \"magical\" 'testInput'
-- value, which the CλaSH compilers looks for to create the stimulus generator
-- for the generated VHDL testbench.
--
-- Example:
--
-- @
-- testInput :: 'Signal' Int
-- testInput = 'stimuliGenerator' $('CLaSH.Sized.Vector.v' [(1::Int),3..21])
-- @
--
-- >>> sample testInput
-- [1,3,5,7,9,11,13,15,17,19,21,21,21,...
stimuliGenerator :: forall l a . KnownNat l
=> Vec l a -- ^ Samples to generate
-> Signal a -- ^ Signal of given samples
stimuliGenerator = stimuliGenerator' systemClock
{-# INLINE outputVerifier #-}
-- | To be used as a functions to generate the \"magical\" 'expectedOutput'
-- function, which the CλaSH compilers looks for to create the signal verifier
-- for the generated VHDL testbench.
--
-- Example:
--
-- @
-- expectedOutput :: 'Signal' Int -> 'Signal' Bool
-- expectedOutput = 'outputVerifier' $('CLaSH.Sized.Vector.v' ([70,99,2,3,4,5,7,8,9,10]::[Int]))
-- @
--
-- >>> sample (expectedOutput (fromList ([0..10] ++ [10,10,10])))
-- [
-- expected value: 70, not equal to actual value: 0
-- False,
-- expected value: 99, not equal to actual value: 1
-- False,False,False,False,False,
-- expected value: 7, not equal to actual value: 6
-- False,
-- expected value: 8, not equal to actual value: 7
-- False,
-- expected value: 9, not equal to actual value: 8
-- False,
-- expected value: 10, not equal to actual value: 9
-- False,True,True,...
outputVerifier :: forall l a . (KnownNat l, Eq a, Show a)
=> Vec l a -- ^ Samples to compare with
-> Signal a -- ^ Signal to verify
-> Signal Bool -- ^ Indicator that all samples are verified
outputVerifier = outputVerifier' systemClock
{-# NOINLINE assert #-}
-- | Compares the first two arguments for equality and logs a warning when they
-- are not equal. The second argument is considered the expected value. This
-- function simply returns the third argument unaltered as its result. This
-- function is used by 'coutputVerifier'.
--
--
-- __NB__: This function is /can/ be used in synthesizable designs.
assert :: (Eq a,Show a)
=> Signal' t a -- ^ Checked value
-> Signal' t a -- ^ Expected value
-> Signal' t b -- ^ Return valued
-> Signal' t b
assert = liftA3
(\a' b' c' -> if a' == b' then c'
else trace (concat [ "\nexpected value: "
, show b'
, ", not equal to actual value: "
, show a'
]) c')
{-# INLINABLE stimuliGenerator' #-}
-- | To be used as a one of the functions to create the \"magical\" 'testInput'
-- value, which the CλaSH compilers looks for to create the stimulus generator
-- for the generated VHDL testbench.
--
-- Example:
--
-- @
-- type ClkA = 'CLaSH.Signal.Explicit.Clk' \"A\" 100
--
-- clkA :: 'SClock' ClkA
-- clkA = 'CLaSH.Signal.Explicit.sclock'
--
-- testInput :: 'Signal'' clkA Int
-- testInput = 'stimuliGenerator'' clkA $('CLaSH.Sized.Vector.v' [(1::Int),3..21])
-- @
--
-- >>> sample testInput
-- [1,3,5,7,9,11,13,15,17,19,21,21,21,...
stimuliGenerator' :: forall l clk a . KnownNat l
=> SClock clk -- ^ Clock to which to synchronize the
-- output signal
-> Vec l a -- ^ Samples to generate
-> Signal' clk a -- ^ Signal of given samples
stimuliGenerator' clk samples =
let (r,o) = unbundle' clk (genT <$> register' clk 0 r)
in o
where
genT :: Index l -> (Index l,a)
genT s = (s',samples !! s)
where
maxI = fromInteger (maxIndex samples)
s' = if s < maxI
then s + 1
else s
{-# INLINABLE outputVerifier' #-}
-- | To be used as a functions to generate the \"magical\" 'expectedOutput'
-- function, which the CλaSH compilers looks for to create the signal verifier
-- for the generated VHDL testbench.
--
-- Example:
--
-- @
-- type ClkA = 'CLaSH.Signal.Explicit.Clk' \"A\" 100
--
-- clkA :: 'SClock' ClkA
-- clkA = 'CLaSH.Signal.Explicit.sclock'
--
-- expectedOutput :: 'Signal'' ClkA Int -> 'Signal'' ClkA Bool
-- expectedOutput = 'outputVerifier'' clkA $('CLaSH.Sized.Vector.v' ([70,99,2,3,4,5,7,8,9,10]::[Int]))
-- @
--
-- >>> sample (expectedOutput (fromList ([0..10] ++ [10,10,10])))
-- [
-- expected value: 70, not equal to actual value: 0
-- False,
-- expected value: 99, not equal to actual value: 1
-- False,False,False,False,False,
-- expected value: 7, not equal to actual value: 6
-- False,
-- expected value: 8, not equal to actual value: 7
-- False,
-- expected value: 9, not equal to actual value: 8
-- False,
-- expected value: 10, not equal to actual value: 9
-- False,True,True,...
outputVerifier' :: forall l clk a . (KnownNat l, Eq a, Show a)
=> SClock clk -- ^ Clock to which the input signal is
-- synchronized to
-> Vec l a -- ^ Samples to compare with
-> Signal' clk a -- ^ Signal to verify
-> Signal' clk Bool -- ^ Indicator that all samples are verified
outputVerifier' clk samples i =
let (s,o) = unbundle' clk (genT <$> register' clk 0 s)
(e,f) = unbundle' clk o
in assert i e (register' clk False f)
where
genT :: Index l -> (Index l,(a,Bool))
genT s = (s',(samples !! s,finished))
where
maxI = fromInteger (maxIndex samples)
s' = if s < maxI
then s + 1
else s
finished = s == maxI