content: {-|
  Copyright  :  (C) 2013-2016, University of Twente,
                    2017     , Google Inc.
                    2019     , Myrtle Software Ltd,
                    2021-2023, QBayLogic B.V.
  License    :  BSD2 (see the file LICENSE)
  Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
  -}
  
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE TypeFamilies #-}
  
  {-# LANGUAGE Unsafe #-}
  
  {-# OPTIONS_HADDOCK show-extensions #-}
  
  module Clash.Prelude.Testbench
    ( -- * Testbench functions for circuits
      assert
    , assertBitVector
    , ignoreFor
    , outputVerifier'
    , outputVerifierBitVector'
    , stimuliGenerator
  
    , E.tbClockGen
    , E.tbEnableGen
    , E.tbSystemClockGen
    , E.clockToDiffClock
    )
  where
  
  import GHC.TypeLits                       (KnownNat, type (<=))
  
  import qualified Clash.Explicit.Testbench as E
  import           Clash.Signal
    (HiddenClock, HiddenReset, HiddenClockResetEnable, Signal,
    hideClock, hideReset, hideClockResetEnable)
  import Clash.Promoted.Nat                 (SNat)
  import Clash.Sized.BitVector              (BitVector)
  import Clash.Sized.Vector                 (Vec)
  import Clash.XException                   (ShowX)
  
  {- $setup
  >>> :set -XTemplateHaskell -XDataKinds -XTypeApplications
  >>> :m -Clash.Explicit.Prelude
  >>> :m -Clash.Explicit.Prelude.Safe
  >>> :m -Clash.Explicit.Testbench
  >>> import Clash.Prelude
  >>> import Clash.Prelude.Testbench
  >>> let testInput = stimuliGenerator $(listToVecTH [(1::Int),3..21])
  >>> let expectedOutput = outputVerifier' $(listToVecTH ([70,99,2,3,4,5,7,8,9,10]::[Int]))
  -}
  
  -- | Compares the first two 'Signal's for equality and logs a warning when they
  -- are not equal. The second 'Signal' is considered the expected value. This
  -- function simply returns the third 'Signal' unaltered as its result. This
  -- function is used by 'outputVerifier''.
  --
  -- === Usage in @clashi@ #assert-clashi#
  --
  -- __NB__: When simulating a component that uses 'assert' in @clashi@, usually,
  -- the warnings are only logged the first time the component is simulated.
  -- Issuing @:reload@ in @clashi@ will discard the cached result of the
  -- computation, and warnings will once again be emitted.
  --
  -- __NB__: This function /can/ be used in synthesizable designs.
  assert
    :: (Eq a, ShowX a, HiddenClock dom , HiddenReset dom )
    => String
    -- ^ Additional message
    -> Signal dom a
    -- ^ Checked value
    -> Signal dom a
    -- ^ Expected value
    -> Signal dom b
    -- ^ Return value
    -> Signal dom b
  assert msg actual expected ret =
    hideReset (hideClock E.assert) msg actual expected ret
  {-# INLINE assert #-}
  
  -- | The same as 'assert', but can handle don't care bits in its expected value.
  assertBitVector
    :: (KnownNat n, HiddenClock dom , HiddenReset dom )
    => String
    -- ^ Additional message
    -> Signal dom (BitVector n)
    -- ^ Checked value
    -> Signal dom (BitVector n)
    -- ^ Expected value
    -> Signal dom b
    -- ^ Return value
    -> Signal dom b
  assertBitVector msg actual expected ret =
    hideReset (hideClock E.assertBitVector) msg actual expected ret
  {-# INLINE assertBitVector #-}
  
  -- |
  --
  -- Example:
  --
  -- @
  -- testInput
  --   :: HiddenClockResetEnable dom
  --   => 'Signal' dom Int
  -- testInput = 'stimuliGenerator' $('Clash.Sized.Vector.listToVecTH' [(1::Int),3..21])
  -- @
  --
  -- >>> sampleN @System 13 testInput
  -- [1,1,3,5,7,9,11,13,15,17,19,21,21]
  stimuliGenerator
    :: ( KnownNat l
       , HiddenClock dom
       , HiddenReset dom  )
    => Vec l a
    -- ^ Samples to generate
    -> Signal dom a
    -- ^ Signal of given samples
  stimuliGenerator = hideReset (hideClock E.stimuliGenerator)
  {-# INLINE stimuliGenerator #-}
  
  -- | Compare a signal (coming from a circuit) to a vector of samples. If a
  -- sample from the signal is not equal to the corresponding sample in the
  -- vector, print to stderr and continue testing. This function is
  -- synthesizable in the sense that HDL simulators will run it.
  --
  -- __NB__: This function uses 'assert'. When simulating this function in
  -- @clashi@, read the [note](#assert-clashi).
  --
  -- Example:
  --
  -- @
  -- expectedOutput
  --   :: HiddenClockResetEnable dom
  --   -> 'Signal' dom Int -> 'Signal' dom Bool
  -- expectedOutput = 'outputVerifier'' $('Clash.Sized.Vector.listToVecTH' ([70,99,2,3,4,5,7,8,9,10]::[Int]))
  -- @
  --
  -- >>> import qualified Data.List as List
  -- >>> sampleN @System 12 (expectedOutput (fromList (0:[0..10] List.++ [10,10,10])))
  -- <BLANKLINE>
  -- cycle(<Clock: System>): 0, outputVerifier
  -- expected value: 70, not equal to actual value: 0
  -- [False
  -- cycle(<Clock: System>): 1, outputVerifier
  -- expected value: 70, not equal to actual value: 0
  -- ,False
  -- cycle(<Clock: System>): 2, outputVerifier
  -- expected value: 99, not equal to actual value: 1
  -- ,False,False,False,False,False
  -- cycle(<Clock: System>): 7, outputVerifier
  -- expected value: 7, not equal to actual value: 6
  -- ,False
  -- cycle(<Clock: System>): 8, outputVerifier
  -- expected value: 8, not equal to actual value: 7
  -- ,False
  -- cycle(<Clock: System>): 9, outputVerifier
  -- expected value: 9, not equal to actual value: 8
  -- ,False
  -- cycle(<Clock: System>): 10, outputVerifier
  -- expected value: 10, not equal to actual value: 9
  -- ,False,True]
  --
  -- If you're working with 'BitVector's containing don't care bits you should use 'outputVerifierBitVector''.
  outputVerifier'
    :: ( KnownNat l
       , Eq a
       , ShowX a
       , HiddenClock dom
       , HiddenReset dom
       , 1 <= l
       )
    => Vec l a
    -- ^ Samples to compare with
    -> Signal dom a
    -- ^ Signal to verify
    -> Signal dom Bool
    -- ^ Indicator that all samples are verified
  outputVerifier' = hideReset (hideClock E.outputVerifier')
  {-# INLINE outputVerifier' #-}
  
  
  -- | Same as 'outputVerifier'',
  -- but can handle don't care bits in its expected values.
  outputVerifierBitVector'
    :: ( KnownNat l
       , KnownNat n
       , HiddenClock dom
       , HiddenReset dom
       , 1 <= l
       )
    => Vec l (BitVector n)
    -- ^ Samples to compare with
    -> Signal dom (BitVector n)
    -- ^ Signal to verify
    -> Signal dom Bool
    -- ^ Indicator that all samples are verified
  outputVerifierBitVector' = hideReset (hideClock E.outputVerifierBitVector')
  {-# INLINE outputVerifierBitVector' #-}
  
  -- | Ignore signal for a number of cycles, while outputting a static value.
  ignoreFor
    :: HiddenClockResetEnable dom
    => SNat n
    -- ^ Number of cycles to ignore incoming signal
    -> a
    -- ^ Value function produces when ignoring signal
    -> Signal dom a
    -- ^ Incoming signal
    -> Signal dom a
    -- ^ Either a passthrough of the incoming signal, or the static value
    -- provided as the second argument.
  ignoreFor = hideClockResetEnable E.ignoreFor
  {-# INLINE ignoreFor #-}
  