    {-|
    Copyright  :  (C) 2013-2016, University of Twente,
                      2017-2022, 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 CPP #-}
    {-# LANGUAGE TypeFamilies #-}

    {-# LANGUAGE Unsafe #-}

    {-# OPTIONS_HADDOCK show-extensions #-}

    {-# OPTIONS_GHC -fplugin=GHC.TypeLits.Normalise #-}
    {-# OPTIONS_GHC -fplugin=GHC.TypeLits.KnownNat.Solver #-}

    module Clash.Explicit.Testbench
      ( -- * Testbench functions for circuits
        assert
      , assertBitVector
      , ignoreFor
      , stimuliGenerator

      , tbClockGen
      , tbEnableGen
      , tbSystemClockGen
      , clockToDiffClock

      , outputVerifier
      , outputVerifier'
      , outputVerifierBitVector
      , outputVerifierBitVector'
      , biTbClockGen
      , unsafeSimSynchronizer
      , outputVerifierWith
      )
    where

    import Control.Exception     (catch, evaluate)
    import Debug.Trace           (trace)
    import GHC.TypeLits          (KnownNat, type (+), type (<=))
    import Prelude               hiding ((!!), length)
    import System.IO.Unsafe      (unsafeDupablePerformIO)

    import Clash.Annotations.Primitive (hasBlackBox)
    import Clash.Class.Num       (satSucc, SaturationMode(SatBound))
    import Clash.Promoted.Nat    (SNat(..))
    import Clash.Promoted.Symbol (SSymbol(..))
    import Clash.Explicit.Signal
      (Clock, Reset, System, Signal, toEnable, fromList, register,
      unbundle, unsafeSynchronizer)
    import Clash.Signal.Internal
      (ClockN (..), DiffClock (..), Reset (..), tbClockGen)
    import Clash.Signal          (mux, KnownDomain, Enable)
    import Clash.Sized.Index     (Index)
    import Clash.Sized.Internal.BitVector
      (BitVector, isLike#)
    import Clash.Sized.Vector    (Vec, (!!), length)
    import Clash.XException      (ShowX (..), XException)

    -- Note that outputVerifier' is used in $setup, while the examples mention
    -- outputVerifier. This is fine, as the examples have explicit type
    -- signatures, turning 'outputVerifier' into 'outputVerifier''.

    {- $setup
    >>> :set -XTemplateHaskell -XDataKinds -XTypeFamilies
    >>> import Clash.Explicit.Prelude
    >>> let testInput clk rst = stimuliGenerator clk rst $(listToVecTH [(1::Int),3..21])
    >>> let expectedOutput clk rst = outputVerifier' clk rst $(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
      :: (KnownDomain dom, Eq a, ShowX a)
      => Clock dom
      -> Reset dom
      -> String
      -- ^ Additional message
      -> Signal dom a
      -- ^ Checked value
      -> Signal dom a
      -- ^ Expected value
      -> Signal dom b
      -- ^ Return value
      -> Signal dom b
    assert :: forall (dom :: Domain) a b.
    (KnownDomain dom, Eq a, ShowX a) =>
    Clock dom
    -> Reset dom
    -> String
    -> Signal dom a
    -> Signal dom a
    -> Signal dom b
    -> Signal dom b
    assert Clock dom
    clk (Reset Signal dom Bool
    _) String
    msg Signal dom a
    checked Signal dom a
    expected Signal dom b
    returned =
      (\a
    c a
    e Integer
    cnt b
    r ->
          if a -> a -> Bool
    forall {a}. Eq a => a -> a -> Bool
    eqX a
    c a
    e
             then b
    r
             else String -> b -> b
    forall a. String -> a -> a
    trace ([String] -> String
    forall (t :: Type -> Type) a. Foldable t => t [a] -> [a]
    concat [ String
    "\ncycle(" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Clock dom -> String
    forall a. Show a => a -> String
    show Clock dom
    clk String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "): "
                                , Integer -> String
    forall a. Show a => a -> String
    show Integer
    cnt
                                , String
    ", "
                                , String
    msg
                                , String
    "\nexpected value: "
                                , a -> String
    forall a. ShowX a => a -> String
    showX a
    e
                                , String
    ", not equal to actual value: "
                                , a -> String
    forall a. ShowX a => a -> String
    showX a
    c
                                ]) b
    r)
      (a -> a -> Integer -> b -> b)
    -> Signal dom a -> Signal dom (a -> Integer -> b -> b)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Signal dom a
    checked Signal dom (a -> Integer -> b -> b)
    -> Signal dom a -> Signal dom (Integer -> b -> b)
    forall a b. Signal dom (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> Signal dom a
    expected Signal dom (Integer -> b -> b)
    -> Signal dom Integer -> Signal dom (b -> b)
    forall a b. Signal dom (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> [Integer] -> Signal dom Integer
    forall a (dom :: Domain). NFDataX a => [a] -> Signal dom a
    fromList [(Integer
    0::Integer)..] Signal dom (b -> b) -> Signal dom b -> Signal dom b
    forall a b. Signal dom (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> Signal dom b
    returned
      where
        eqX :: a -> a -> Bool
    eqX a
    a a
    b = IO Bool -> Bool
    forall a. IO a -> a
    unsafeDupablePerformIO (IO Bool -> (XException -> IO Bool) -> IO Bool
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    catch (Bool -> IO Bool
    forall a. a -> IO a
    evaluate (a
    a a -> a -> Bool
    forall {a}. Eq a => a -> a -> Bool
    == a
    b))
                                                (\(XException
    _ :: XException) -> Bool -> IO Bool
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return Bool
    False))
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE assert #-}
    {-# ANN assert hasBlackBox #-}

    -- | The same as 'assert', but can handle don't care bits in its expected value.
    assertBitVector
      :: (KnownDomain dom, KnownNat n)
      => Clock dom
      -> Reset 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 :: forall (dom :: Domain) (n :: Nat) b.
    (KnownDomain dom, KnownNat n) =>
    Clock dom
    -> Reset dom
    -> String
    -> Signal dom (BitVector n)
    -> Signal dom (BitVector n)
    -> Signal dom b
    -> Signal dom b
    assertBitVector Clock dom
    clk (Reset Signal dom Bool
    _) String
    msg Signal dom (BitVector n)
    checked Signal dom (BitVector n)
    expected Signal dom b
    returned =
      (\BitVector n
    c BitVector n
    e Integer
    cnt b
    r ->
          if BitVector n -> BitVector n -> Bool
    forall {n :: Nat}. KnownNat n => BitVector n -> BitVector n -> Bool
    eqX BitVector n
    c BitVector n
    e
             then b
    r
             else String -> b -> b
    forall a. String -> a -> a
    trace ([String] -> String
    forall (t :: Type -> Type) a. Foldable t => t [a] -> [a]
    concat [ String
    "\ncycle(" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ Clock dom -> String
    forall a. Show a => a -> String
    show Clock dom
    clk String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    "): "
                                , Integer -> String
    forall a. Show a => a -> String
    show Integer
    cnt
                                , String
    ", "
                                , String
    msg
                                , String
    "\nexpected value: "
                                , BitVector n -> String
    forall a. ShowX a => a -> String
    showX BitVector n
    e
                                , String
    ", not equal to actual value: "
                                , BitVector n -> String
    forall a. ShowX a => a -> String
    showX BitVector n
    c
                                ]) b
    r)
      (BitVector n -> BitVector n -> Integer -> b -> b)
    -> Signal dom (BitVector n)
    -> Signal dom (BitVector n -> Integer -> b -> b)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Signal dom (BitVector n)
    checked Signal dom (BitVector n -> Integer -> b -> b)
    -> Signal dom (BitVector n) -> Signal dom (Integer -> b -> b)
    forall a b. Signal dom (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> Signal dom (BitVector n)
    expected Signal dom (Integer -> b -> b)
    -> Signal dom Integer -> Signal dom (b -> b)
    forall a b. Signal dom (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> [Integer] -> Signal dom Integer
    forall a (dom :: Domain). NFDataX a => [a] -> Signal dom a
    fromList [(Integer
    0::Integer)..] Signal dom (b -> b) -> Signal dom b -> Signal dom b
    forall a b. Signal dom (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> Signal dom b
    returned
      where
        eqX :: BitVector n -> BitVector n -> Bool
    eqX BitVector n
    a BitVector n
    b = IO Bool -> Bool
    forall a. IO a -> a
    unsafeDupablePerformIO (IO Bool -> (XException -> IO Bool) -> IO Bool
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    catch (Bool -> IO Bool
    forall a. a -> IO a
    evaluate (BitVector n
    a BitVector n -> BitVector n -> Bool
    forall {n :: Nat}. KnownNat n => BitVector n -> BitVector n -> Bool
    `isLike#` BitVector n
    b))
                                                (\(XException
    _ :: XException) -> Bool -> IO Bool
    forall a. a -> IO a
    forall (m :: Type -> Type) a. Monad m => a -> m a
    return Bool
    False))
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE assertBitVector #-}
    {-# ANN assertBitVector hasBlackBox #-}

    -- |
    --
    -- Example:
    --
    -- @
    -- testInput
    --   :: KnownDomain dom
    --   => Clock dom
    --   -> Reset dom
    --   -> 'Signal' dom Int
    -- testInput clk rst = 'stimuliGenerator' clk rst $('Clash.Sized.Vector.listToVecTH' [(1::Int),3..21])
    -- @
    --
    -- >>> sampleN 14 (testInput systemClockGen resetGen)
    -- [1,1,3,5,7,9,11,13,15,17,19,21,21,21]
    stimuliGenerator
      :: forall l dom   a
       . ( KnownNat l
         , KnownDomain dom )
      => Clock dom
      -- ^ Clock to which to synchronize the output signal
      -> Reset dom
      -> Vec l a
      -- ^ Samples to generate
      -> Signal dom a
      -- ^ Signal of given samples
    stimuliGenerator :: forall (l :: Nat) (dom :: Domain) a.
    (KnownNat l, KnownDomain dom) =>
    Clock dom -> Reset dom -> Vec l a -> Signal dom a
    stimuliGenerator Clock dom
    clk Reset dom
    rst Vec l a
    samples =
        let (Signal dom (Index l)
    r,Signal dom a
    o) = Signal dom (Index l, a) -> Unbundled dom (Index l, a)
    forall a (dom :: Domain).
    Bundle a =>
    Signal dom a -> Unbundled dom a
    forall (dom :: Domain).
    Signal dom (Index l, a) -> Unbundled dom (Index l, a)
    unbundle (Index l -> (Index l, a)
    genT (Index l -> (Index l, a))
    -> Signal dom (Index l) -> Signal dom (Index l, a)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Clock dom
    -> Reset dom
    -> Enable dom
    -> Index l
    -> Signal dom (Index l)
    -> Signal dom (Index l)
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    register Clock dom
    clk Reset dom
    rst (Signal dom Bool -> Enable dom
    forall (dom :: Domain). Signal dom Bool -> Enable dom
    toEnable (Bool -> Signal dom Bool
    forall a. a -> Signal dom a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure Bool
    True)) Index l
    0 Signal dom (Index l)
    r)
        in  Signal dom a
    o
      where
        genT :: Index l -> (Index l,a)
        genT :: Index l -> (Index l, a)
    genT Index l
    s = (Index l
    s',Vec l a
    samples Vec l a -> Index l -> a
    forall (n :: Nat) i a. (KnownNat n, Enum i) => Vec n a -> i -> a
    !! Index l
    s)
          where
            maxI :: Index l
    maxI = Int -> Index l
    forall a. Enum a => Int -> a
    toEnum (Vec l a -> Int
    forall (n :: Nat) a. KnownNat n => Vec n a -> Int
    length Vec l a
    samples Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1)

            s' :: Index l
    s' = if Index l
    s Index l -> Index l -> Bool
    forall a. Ord a => a -> a -> Bool
    < Index l
    maxI
                    then Index l
    s Index l -> Index l -> Index l
    forall a. Num a => a -> a -> a
    + Index l
    1
                    else Index l
    s
    {-# INLINABLE stimuliGenerator #-}

    -- | Same as 'outputVerifier' but used in cases where the test bench domain and
    -- the domain of the circuit under test are the same.
    outputVerifier'
      :: forall l a dom
       . ( KnownNat l
         , KnownDomain dom
         , Eq a
         , ShowX a
         , 1 <= l
         )
      => Clock dom
      -- ^ Clock to which the test bench is synchronized
      -> Reset dom
      -- ^ Reset line of test bench
      -> Vec l a
      -- ^ Samples to compare with
      -> Signal dom a
      -- ^ Signal to verify
      -> Signal dom Bool
      -- ^ Indicator that all samples are verified
    outputVerifier' :: forall (l :: Nat) a (dom :: Domain).
    (KnownNat l, KnownDomain dom, Eq a, ShowX a, 1 <= l) =>
    Clock dom
    -> Reset dom -> Vec l a -> Signal dom a -> Signal dom Bool
    outputVerifier' Clock dom
    clk =
      forall (l :: Nat) a (testDom :: Domain) (circuitDom :: Domain).
    (KnownNat l, KnownDomain testDom, KnownDomain circuitDom, Eq a,
     ShowX a, 1 <= l) =>
    Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l a
    -> Signal circuitDom a
    -> Signal testDom Bool
    outputVerifier @l @a Clock dom
    clk Clock dom
    clk
    {-# INLINE outputVerifier' #-}

    -- | 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. If @testDom@ and
    -- @circuitDom@ refer to the same domain, it can also be synthesized into
    -- hardware.
    --
    -- __NB__: This function uses 'assert'. When simulating this function in
    -- @clashi@, read the [note](#assert-clashi).
    --
    -- Example:
    --
    -- @
    -- expectedOutput
    --   :: Clock dom -> Reset dom
    --   -> 'Signal' dom Int -> 'Signal' dom Bool
    -- expectedOutput clk rst = 'outputVerifier' clk rst $('Clash.Sized.Vector.listToVecTH' ([70,99,2,3,4,5,7,8,9,10]::[Int]))
    -- @
    --
    -- >>> import qualified Data.List as List
    -- >>> sampleN 12 (expectedOutput systemClockGen resetGen (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
      :: forall l a testDom circuitDom
       . ( KnownNat l
         , KnownDomain testDom
         , KnownDomain circuitDom
         , Eq a
         , ShowX a
         , 1 <= l
         )
      => Clock testDom
      -- ^ Clock to which the test bench is synchronized (but not necessarily
      -- the circuit under test)
      -> Clock circuitDom
      -- ^ Clock to which the circuit under test is synchronized
      -> Reset testDom
      -- ^ Reset line of test bench
      -> Vec l a
      -- ^ Samples to compare with
      -> Signal circuitDom a
      -- ^ Signal to verify
      -> Signal testDom Bool
      -- ^ True if all samples are verified
    outputVerifier :: forall (l :: Nat) a (testDom :: Domain) (circuitDom :: Domain).
    (KnownNat l, KnownDomain testDom, KnownDomain circuitDom, Eq a,
     ShowX a, 1 <= l) =>
    Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l a
    -> Signal circuitDom a
    -> Signal testDom Bool
    outputVerifier =
      (Clock testDom
     -> Reset testDom
     -> Signal testDom a
     -> Signal testDom a
     -> Signal testDom Bool
     -> Signal testDom Bool)
    -> Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l a
    -> Signal circuitDom a
    -> Signal testDom Bool
    forall (l :: Nat) a (testDom :: Domain) (circuitDom :: Domain).
    (KnownNat l, KnownDomain testDom, KnownDomain circuitDom, Eq a,
     ShowX a, 1 <= l) =>
    (Clock testDom
     -> Reset testDom
     -> Signal testDom a
     -> Signal testDom a
     -> Signal testDom Bool
     -> Signal testDom Bool)
    -> Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l a
    -> Signal circuitDom a
    -> Signal testDom Bool
    outputVerifierWith (\Clock testDom
    clk Reset testDom
    rst -> Clock testDom
    -> Reset testDom
    -> String
    -> Signal testDom a
    -> Signal testDom a
    -> Signal testDom Bool
    -> Signal testDom Bool
    forall (dom :: Domain) a b.
    (KnownDomain dom, Eq a, ShowX a) =>
    Clock dom
    -> Reset dom
    -> String
    -> Signal dom a
    -> Signal dom a
    -> Signal dom b
    -> Signal dom b
    assert Clock testDom
    clk Reset testDom
    rst String
    "outputVerifier")
    {-# INLINE outputVerifier #-}

    -- | Same as 'outputVerifier'', but can handle don't care bits in its expected
    -- values.
    outputVerifierBitVector'
      :: forall l n dom
       . ( KnownNat l
         , KnownNat n
         , KnownDomain dom
         , 1 <= l
         )
      => Clock dom
      -- ^ Clock to which the input signal is synchronized
      -> Reset dom
      -> 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' :: forall (l :: Nat) (n :: Nat) (dom :: Domain).
    (KnownNat l, KnownNat n, KnownDomain dom, 1 <= l) =>
    Clock dom
    -> Reset dom
    -> Vec l (BitVector n)
    -> Signal dom (BitVector n)
    -> Signal dom Bool
    outputVerifierBitVector' Clock dom
    clk =
      forall (l :: Nat) (n :: Nat) (testDom :: Domain)
           (circuitDom :: Domain).
    (KnownNat l, KnownNat n, KnownDomain testDom,
     KnownDomain circuitDom, 1 <= l) =>
    Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l (BitVector n)
    -> Signal circuitDom (BitVector n)
    -> Signal testDom Bool
    outputVerifierBitVector @l @n Clock dom
    clk Clock dom
    clk
    {-# INLINE outputVerifierBitVector' #-}

    -- | Same as 'outputVerifier', but can handle don't care bits in its
    -- expected values.
    outputVerifierBitVector
      :: forall l n testDom circuitDom
       . ( KnownNat l
         , KnownNat n
         , KnownDomain testDom
         , KnownDomain circuitDom
         , 1 <= l
         )
      => Clock testDom
      -- ^ Clock to which the test bench is synchronized (but not necessarily
      -- the circuit under test)
      -> Clock circuitDom
      -- ^ Clock to which the circuit under test is synchronized
      -> Reset testDom
      -- ^ Reset line of test bench
      -> Vec l (BitVector n)
      -- ^ Samples to compare with
      -> Signal circuitDom (BitVector n)
      -- ^ Signal to verify
      -> Signal testDom Bool
      -- ^ Indicator that all samples are verified
    outputVerifierBitVector :: forall (l :: Nat) (n :: Nat) (testDom :: Domain)
           (circuitDom :: Domain).
    (KnownNat l, KnownNat n, KnownDomain testDom,
     KnownDomain circuitDom, 1 <= l) =>
    Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l (BitVector n)
    -> Signal circuitDom (BitVector n)
    -> Signal testDom Bool
    outputVerifierBitVector =
      (Clock testDom
     -> Reset testDom
     -> Signal testDom (BitVector n)
     -> Signal testDom (BitVector n)
     -> Signal testDom Bool
     -> Signal testDom Bool)
    -> Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l (BitVector n)
    -> Signal circuitDom (BitVector n)
    -> Signal testDom Bool
    forall (l :: Nat) a (testDom :: Domain) (circuitDom :: Domain).
    (KnownNat l, KnownDomain testDom, KnownDomain circuitDom, Eq a,
     ShowX a, 1 <= l) =>
    (Clock testDom
     -> Reset testDom
     -> Signal testDom a
     -> Signal testDom a
     -> Signal testDom Bool
     -> Signal testDom Bool)
    -> Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l a
    -> Signal circuitDom a
    -> Signal testDom Bool
    outputVerifierWith
        (\Clock testDom
    clk Reset testDom
    rst -> Clock testDom
    -> Reset testDom
    -> String
    -> Signal testDom (BitVector n)
    -> Signal testDom (BitVector n)
    -> Signal testDom Bool
    -> Signal testDom Bool
    forall (dom :: Domain) (n :: Nat) b.
    (KnownDomain dom, KnownNat n) =>
    Clock dom
    -> Reset dom
    -> String
    -> Signal dom (BitVector n)
    -> Signal dom (BitVector n)
    -> Signal dom b
    -> Signal dom b
    assertBitVector Clock testDom
    clk Reset testDom
    rst String
    "outputVerifierBitVector")
    {-# INLINE outputVerifierBitVector #-}

    outputVerifierWith
      :: forall l a testDom circuitDom
       . ( KnownNat l
         , KnownDomain testDom
         , KnownDomain circuitDom
         , Eq a
         , ShowX a
         , 1 <= l
         )
      => (    Clock testDom
           -> Reset testDom
           -> Signal testDom a
           -> Signal testDom a
           -> Signal testDom Bool
           -> Signal testDom Bool
          )
      -- ^ The @assert@ function to use
      -> Clock testDom
      -- ^ Clock to which the test bench is synchronized (but not necessarily
      -- the circuit under test)
      -> Clock circuitDom
      -- ^ Clock to which the circuit under test is synchronized
      -> Reset testDom
      -- ^ Reset line of test bench
      -> Vec l a
      -- ^ Samples to compare with
      -> Signal circuitDom a
      -- ^ Signal to verify
      -> Signal testDom Bool
      -- ^ True if all samples are verified
    outputVerifierWith :: forall (l :: Nat) a (testDom :: Domain) (circuitDom :: Domain).
    (KnownNat l, KnownDomain testDom, KnownDomain circuitDom, Eq a,
     ShowX a, 1 <= l) =>
    (Clock testDom
     -> Reset testDom
     -> Signal testDom a
     -> Signal testDom a
     -> Signal testDom Bool
     -> Signal testDom Bool)
    -> Clock testDom
    -> Clock circuitDom
    -> Reset testDom
    -> Vec l a
    -> Signal circuitDom a
    -> Signal testDom Bool
    outputVerifierWith Clock testDom
    -> Reset testDom
    -> Signal testDom a
    -> Signal testDom a
    -> Signal testDom Bool
    -> Signal testDom Bool
    assertF Clock testDom
    clkTest Clock circuitDom
    clkCircuit Reset testDom
    rst Vec l a
    samples Signal circuitDom a
    i0 =
        let i1 :: Signal testDom a
    i1    = Clock circuitDom
    -> Clock testDom -> Signal circuitDom a -> Signal testDom a
    forall (dom1 :: Domain) (dom2 :: Domain) a.
    (KnownDomain dom1, KnownDomain dom2) =>
    Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
    unsafeSimSynchronizer Clock circuitDom
    clkCircuit Clock testDom
    clkTest Signal circuitDom a
    i0
            en :: Enable dom
    en    = Signal dom Bool -> Enable dom
    forall (dom :: Domain). Signal dom Bool -> Enable dom
    toEnable (Bool -> Signal dom Bool
    forall a. a -> Signal dom a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure Bool
    True)
            (Signal testDom (Index l)
    s,Signal testDom (a, Bool)
    o) = Signal testDom (Index l, (a, Bool))
    -> Unbundled testDom (Index l, (a, Bool))
    forall a (dom :: Domain).
    Bundle a =>
    Signal dom a -> Unbundled dom a
    forall (dom :: Domain).
    Signal dom (Index l, (a, Bool))
    -> Unbundled dom (Index l, (a, Bool))
    unbundle (Index l -> (Index l, (a, Bool))
    genT (Index l -> (Index l, (a, Bool)))
    -> Signal testDom (Index l) -> Signal testDom (Index l, (a, Bool))
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Clock testDom
    -> Reset testDom
    -> Enable testDom
    -> Index l
    -> Signal testDom (Index l)
    -> Signal testDom (Index l)
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    register Clock testDom
    clkTest Reset testDom
    rst Enable testDom
    forall {dom :: Domain}. Enable dom
    en Index l
    0 Signal testDom (Index l)
    s)
            (Signal testDom a
    e,Signal testDom Bool
    f) = Signal testDom (a, Bool) -> Unbundled testDom (a, Bool)
    forall a (dom :: Domain).
    Bundle a =>
    Signal dom a -> Unbundled dom a
    forall (dom :: Domain).
    Signal dom (a, Bool) -> Unbundled dom (a, Bool)
    unbundle Signal testDom (a, Bool)
    o
            f' :: Signal testDom Bool
    f'    = Clock testDom
    -> Reset testDom
    -> Enable testDom
    -> Bool
    -> Signal testDom Bool
    -> Signal testDom Bool
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    register Clock testDom
    clkTest Reset testDom
    rst Enable testDom
    forall {dom :: Domain}. Enable dom
    en Bool
    False Signal testDom Bool
    f
            -- Only assert while not finished
        in  Signal testDom Bool
    -> Signal testDom Bool
    -> Signal testDom Bool
    -> Signal testDom Bool
    forall (f :: Type -> Type) a.
    Applicative f =>
    f Bool -> f a -> f a -> f a
    mux Signal testDom Bool
    f' Signal testDom Bool
    f' (Signal testDom Bool -> Signal testDom Bool)
    -> Signal testDom Bool -> Signal testDom Bool
    forall a b. (a -> b) -> a -> b
    $ Clock testDom
    -> Reset testDom
    -> Signal testDom a
    -> Signal testDom a
    -> Signal testDom Bool
    -> Signal testDom Bool
    assertF Clock testDom
    clkTest Reset testDom
    rst Signal testDom a
    i1 Signal testDom a
    e Signal testDom Bool
    f'
      where
        genT :: Index l -> (Index l,(a,Bool))
        genT :: Index l -> (Index l, (a, Bool))
    genT Index l
    s = (Index l
    s',(Vec l a
    samples Vec l a -> Index l -> a
    forall (n :: Nat) i a. (KnownNat n, Enum i) => Vec n a -> i -> a
    !! Index l
    s,Bool
    finished))
          where
            s' :: Index l
    s' = SaturationMode -> Index l -> Index l
    forall a. SaturatingNum a => SaturationMode -> a -> a
    satSucc SaturationMode
    SatBound Index l
    s
            finished :: Bool
    finished = Index l
    s Index l -> Index l -> Bool
    forall {a}. Eq a => a -> a -> Bool
    == Index l
    forall a. Bounded a => a
    maxBound
    {-# INLINABLE outputVerifierWith #-}

    -- | Ignore signal for a number of cycles, while outputting a static value.
    ignoreFor
      :: forall dom  n a
       . KnownDomain dom
      => Clock dom
      -> Reset dom
      -> Enable 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 :: forall (dom :: Domain) (n :: Nat) a.
    KnownDomain dom =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> SNat n
    -> a
    -> Signal dom a
    -> Signal dom a
    ignoreFor Clock dom
    clk Reset dom
    rst Enable dom
    en SNat n
    SNat a
    a Signal dom a
    i =
      Signal dom Bool -> Signal dom a -> Signal dom a -> Signal dom a
    forall (f :: Type -> Type) a.
    Applicative f =>
    f Bool -> f a -> f a -> f a
    mux (Index (n + 1) -> Index (n + 1) -> Bool
    forall {a}. Eq a => a -> a -> Bool
    (==) (Index (n + 1) -> Index (n + 1) -> Bool)
    -> Signal dom (Index (n + 1)) -> Signal dom (Index (n + 1) -> Bool)
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Signal dom (Index (n + 1))
    counter Signal dom (Index (n + 1) -> Bool)
    -> Signal dom (Index (n + 1)) -> Signal dom Bool
    forall a b. Signal dom (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b.
    Applicative f =>
    f (a -> b) -> f a -> f b
    <*> (Index (n + 1) -> Signal dom (Index (n + 1))
    forall a. a -> Signal dom a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure Index (n + 1)
    forall a. Bounded a => a
    maxBound)) Signal dom a
    i (a -> Signal dom a
    forall a. a -> Signal dom a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure a
    a)
     where
      counter :: Signal dom (Index (n+1))
      counter :: Signal dom (Index (n + 1))
    counter = Clock dom
    -> Reset dom
    -> Enable dom
    -> Index (n + 1)
    -> Signal dom (Index (n + 1))
    -> Signal dom (Index (n + 1))
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    register Clock dom
    clk Reset dom
    rst Enable dom
    en Index (n + 1)
    0 (SaturationMode -> Index (n + 1) -> Index (n + 1)
    forall a. SaturatingNum a => SaturationMode -> a -> a
    satSucc SaturationMode
    SatBound (Index (n + 1) -> Index (n + 1))
    -> Signal dom (Index (n + 1)) -> Signal dom (Index (n + 1))
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Signal dom (Index (n + 1))
    counter)

    -- | Same as 'tbClockGen', but returns two clocks on potentially different
    -- domains. To be used in situations where the test circuit potentially operates
    -- on a different clock than the device under test.
    biTbClockGen
      :: forall testDom circuitDom
       . ( KnownDomain testDom
         , KnownDomain circuitDom
         )
      => Signal testDom Bool
      -> (Clock testDom, Clock circuitDom)
    biTbClockGen :: forall (testDom :: Domain) (circuitDom :: Domain).
    (KnownDomain testDom, KnownDomain circuitDom) =>
    Signal testDom Bool -> (Clock testDom, Clock circuitDom)
    biTbClockGen Signal testDom Bool
    done = (Clock testDom
    testClk, Clock circuitDom
    circuitClk)
     where
      testClk :: Clock testDom
    testClk = Signal testDom Bool -> Clock testDom
    forall (testDom :: Domain).
    KnownDomain testDom =>
    Signal testDom Bool -> Clock testDom
    tbClockGen Signal testDom Bool
    done
      circuitClk :: Clock circuitDom
    circuitClk = Signal circuitDom Bool -> Clock circuitDom
    forall (testDom :: Domain).
    KnownDomain testDom =>
    Signal testDom Bool -> Clock testDom
    tbClockGen (Clock testDom
    -> Clock circuitDom
    -> Signal testDom Bool
    -> Signal circuitDom Bool
    forall (dom1 :: Domain) (dom2 :: Domain) a.
    (KnownDomain dom1, KnownDomain dom2) =>
    Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
    unsafeSynchronizer Clock testDom
    testClk Clock circuitDom
    circuitClk Signal testDom Bool
    done)

    -- | Enable signal that's always enabled. Because it has a blackbox definition
    -- this enable signal is opaque to other blackboxes. It will therefore never
    -- be optimized away.
    tbEnableGen :: Enable tag
    tbEnableGen :: forall {dom :: Domain}. Enable dom
    tbEnableGen = Signal tag Bool -> Enable tag
    forall (dom :: Domain). Signal dom Bool -> Enable dom
    toEnable (Bool -> Signal tag Bool
    forall a. a -> Signal tag a
    forall (f :: Type -> Type) a. Applicative f => a -> f a
    pure Bool
    True)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE tbEnableGen #-}
    {-# ANN tbEnableGen hasBlackBox #-}

    -- | Clock generator for the 'System' clock domain.
    --
    -- __NB__: Can be used in the /testBench/ function
    --
    -- === __Example__
    --
    -- @
    -- topEntity :: Vec 2 (Vec 3 (Unsigned 8)) -> Vec 6 (Unsigned 8)
    -- topEntity = concat
    --
    -- testBench :: Signal System Bool
    -- testBench = done
    --   where
    --     testInput      = pure ((1 :> 2 :> 3 :> Nil) :> (4 :> 5 :> 6 :> Nil) :> Nil)
    --     expectedOutput = outputVerifier' ((1:>2:>3:>4:>5:>6:>Nil):>Nil)
    --     done           = exposeClockResetEnable (expectedOutput (topEntity \<\$> testInput)) clk rst
    --     clk            = 'tbSystemClockGen' (not \<\$> done)
    --     rst            = systemResetGen
    -- @
    tbSystemClockGen
      :: Signal System Bool
      -> Clock System
    tbSystemClockGen :: Signal System Bool -> Clock System
    tbSystemClockGen = Signal System Bool -> Clock System
    forall (testDom :: Domain).
    KnownDomain testDom =>
    Signal testDom Bool -> Clock testDom
    tbClockGen

    -- | Convert a single-ended clock to a differential clock
    --
    -- The 'tbClockGen' function generates a single-ended clock. This function will
    -- output the two phases of a differential clock corresponding to that
    -- single-ended clock.
    --
    -- This function is only meant to be used in the /testBench/ function, not to
    -- create a differential output in hardware.
    --
    -- Example:
    --
    -- @
    -- clk = clockToDiffClock $ tbClockGen (not \<\$\> done)
    -- @
    clockToDiffClock ::
      KnownDomain dom =>
      -- | Single-ended input
      Clock dom ->
      -- | Differential output
      DiffClock dom
    clockToDiffClock :: forall (dom :: Domain).
    KnownDomain dom =>
    Clock dom -> DiffClock dom
    clockToDiffClock Clock dom
    clk = Clock dom -> ("n" ::: ClockN dom) -> DiffClock dom
    forall (dom :: Domain).
    ("p" ::: Clock dom) -> ("n" ::: ClockN dom) -> DiffClock dom
    DiffClock Clock dom
    clk (SSymbol dom -> "n" ::: ClockN dom
    forall (dom :: Domain). SSymbol dom -> ClockN dom
    ClockN SSymbol dom
    forall (s :: Domain). KnownSymbol s => SSymbol s
    SSymbol)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE clockToDiffClock #-}
    {-# ANN clockToDiffClock hasBlackBox #-}

    -- | Cross clock domains in a way that is unsuitable for hardware but good
    -- enough for simulation.
    --
    -- It's equal to 'unsafeSynchronizer' but will warn when used outside of a test
    -- bench. 'outputVerifier' uses this function when it needs to cross between
    -- clock domains, which will render it unsuitable for synthesis, but good enough
    -- for simulating the generated HDL.
    unsafeSimSynchronizer
      :: forall dom1 dom2 a
       . ( KnownDomain dom1
         , KnownDomain dom2 )
      => Clock dom1
      -- ^ 'Clock' of the incoming signal
      -> Clock dom2
      -- ^ 'Clock' of the outgoing signal
      -> Signal dom1 a
      -> Signal dom2 a
    unsafeSimSynchronizer :: forall (dom1 :: Domain) (dom2 :: Domain) a.
    (KnownDomain dom1, KnownDomain dom2) =>
    Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
    unsafeSimSynchronizer = Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
    forall (dom1 :: Domain) (dom2 :: Domain) a.
    (KnownDomain dom1, KnownDomain dom2) =>
    Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
    unsafeSynchronizer
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE unsafeSimSynchronizer #-}
    {-# ANN unsafeSimSynchronizer hasBlackBox #-}