    {-|
    Copyright  :  (C) 2013-2016, University of Twente,
                      2016-2019, Myrtle Software,
                      2017-2022, Google Inc.
                      2020     , Ben Gamari,
                      2021-2023, QBayLogic B.V.
    License    :  BSD2 (see the file LICENSE)
    Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>

    Clash has synchronous 'Signal's in the form of:

    @
    'Signal' (dom :: 'GHC.TypeLits.Symbol') a
    @

    Where /a/ is the type of the value of the 'Signal', for example /Int/ or /Bool/,
    and /dom/ is the /clock-/ (and /reset-/) domain to which the memory elements
    manipulating these 'Signal's belong.

    The type-parameter, /dom/, is of the kind 'Domain' - a simple string. That
    string refers to a single /synthesis domain/. A synthesis domain describes the
    behavior of certain aspects of memory elements in it. More specifically, a
    domain looks like:

    @
    'DomainConfiguration'
      { _name:: 'GHC.TypeLits.Symbol'
      -- ^ Domain name
      , _period :: 'GHC.TypeLits.Nat'
      -- ^ Clock period in \/ps\/
      , _edge :: 'ActiveEdge'
      -- ^ Active edge of the clock
      , _reset :: 'ResetKind'
      -- ^ Whether resets are synchronous (edge-sensitive) or asynchronous (level-sensitive)
      , _init :: 'InitBehavior'
      -- ^ Whether the initial (or "power up") value of memory elements is
      -- unknown/undefined, or configurable to a specific value
      , _polarity :: 'ResetPolarity'
      -- ^ Whether resets are active high or active low
      }
    @

    Check the documentation of each of the types to see the various options Clash
    provides. In order to specify a domain, an instance of 'KnownDomain' should be
    made. Clash provides a standard implementation, called 'System', that is
    configured as follows:

    @
    instance KnownDomain 'System' where
      type KnownConf 'System' = 'DomainConfiguration 'System' 10000 'Rising 'Asynchronous 'Defined 'ActiveHigh
      knownDomain = 'SDomainConfiguration' SSymbol SNat 'SRising' 'SAsynchronous' 'SDefined' 'SActiveHigh'
    @

    In words, \"System\" is a synthesis domain with a clock running with a period
    of 10000 /ps/ (100 MHz). Memory elements update their state on the rising edge
    of the clock, can be reset asynchronously with regards to the clock, and have
    defined power up values if applicable.

    In order to create a new domain, you don't have to instantiate it explicitly.
    Instead, you can have 'createDomain' create a domain for you. You can also use
    the same function to subclass existing domains.

    * __NB__: \"Bad things\"™  happen when you actually use a clock period of @0@,
    so do __not__ do that!
    * __NB__: You should be judicious using a clock with period of @1@ as you can
    never create a clock that goes any faster!
    * __NB__: For the best compatibility make sure your period is divisible by 2,
    because some VHDL simulators don't support fractions of picoseconds.
    * __NB__: Whether 'System' has good defaults depends on your target platform.
    Check out 'IntelSystem' and 'XilinxSystem' too!

    === Explicit clocks and resets, and meta-stability #metastability#

    When using multiple clocks and/or reset lines there are ways to accidentally
    introduce situations that are prone to
    <https://en.wikipedia.org/wiki/Metastability_in_electronics metastability>.
    These bugs are incredibly hard to debug as they often cannot be simulated, so
    it's best to prevent them in the first place. This section outlines the
    situations in which metastability arises and how to prevent it.

    Two types of resets exist: synchronous and asynchronous resets. These reset
    types are encoded in a synthesis domain. For the following examples we assume
    the following exist:

    @
    'DomainConfiguration' \"SyncExample\" _period _edge 'Synchronous' _init
    'DomainConfiguration' \"AsyncExample\" _period _edge 'Asynchronous' _init
    @

    See the previous section on how to use domains.

    We now go over the clock and reset line combinations and explain when they
    can potentially introduce situations prone to meta-stability:

        *   /Reset situation 1/:

            @
            f :: 'Reset' \"SyncExample\" -> 'Reset' \"SyncExample\" -> ..
            f x y = ..
            @

            There are no problems here, because although /x/ and /y/ can have
            different values, components to these reset lines are reset
            /synchronously/, and there is no metastability situation.

        *   /Reset situation 2/:

            @
            g :: 'Reset' \"AsyncExample\" -> 'Reset' \"AsyncExample\" -> ..
            g x y = ..
            @

            This situation can be prone to metastability, because although /x/ and
            /y/ belong to the same /domain/ according to their domain, there is no
            guarantee that they actually originate from the same source. This means
            that one component can enter its reset state asynchronously to another
            component, inducing metastability in the other component.

        *   /Clock situation/:

            @
            k :: 'Clock' dom -> 'Clock' dom -> ..
            k x y = ..
            @

            The situation above is potentially prone to metastability, because
            even though /x/ and /y/ belong to the same /domain/ according to their
            domain, there is no guarantee that they actually originate from the same
            source. They could hence be connected to completely unrelated clock
            sources, and components can then induce metastable states in others.

    -}

    {-# LANGUAGE CPP #-}
    {-# LANGUAGE ExplicitNamespaces #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE GADTs #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE RankNTypes #-}

    {-# LANGUAGE Trustworthy #-}

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

    {-# OPTIONS_HADDOCK show-extensions #-}

    module Clash.Explicit.Signal
      ( -- * Synchronous signal
        Signal
      , BiSignalIn
      , BiSignalOut
      , BiSignalDefault(..)
        -- * Domain
      , Domain
      , KnownDomain(..)
      , KnownConfiguration
      , ActiveEdge(..)
      , SActiveEdge(..)
      , InitBehavior(..)
      , SInitBehavior(..)
      , ResetKind(..)
      , SResetKind(..)
      , ResetPolarity(..)
      , SResetPolarity(..)
      , DomainConfiguration(..)
      , SDomainConfiguration(..)
      -- ** Configuration type families
      , DomainPeriod
      , DomainActiveEdge
      , DomainResetKind
      , DomainInitBehavior
      , DomainResetPolarity
        -- *** Convenience types #conveniencetypes#
        -- **** Simplifying
        -- $conveniencetypes

      , HasSynchronousReset
      , HasAsynchronousReset
      , HasDefinedInitialValues
        -- ** Default domains
      , System
      , XilinxSystem
      , IntelSystem
      , vSystem
      , vIntelSystem
      , vXilinxSystem
        -- ** Domain utilities
      , VDomainConfiguration(..)
      , vDomain
      , createDomain
      , knownVDomain
      , clockPeriod
      , activeEdge
      , resetKind
      , initBehavior
      , resetPolarity
        -- ** Enabling
      , Enable
      , toEnable
      , fromEnable
      , enableGen
        -- * Clock
      , Clock
      , DiffClock
      , periodToHz
      , hzToPeriod
        -- ** Synchronization primitive
      , unsafeSynchronizer
      , veryUnsafeSynchronizer
        -- * Reset
      , Reset
      , unsafeToReset
      , unsafeFromReset
      , unsafeToActiveHigh
      , unsafeToActiveLow
      , unsafeFromActiveHigh
      , unsafeFromActiveLow
        -- * Basic circuit functions
      , andEnable
      , dflipflop
      , delay
      , delayMaybe
      , delayEn
      , register
      , regMaybe
      , regEn
      , mux
        -- * Simulation and testbench functions
      , clockGen
      , resetGen
      , resetGenN
      , systemClockGen
      , systemResetGen
        -- * Boolean connectives
      , (.&&.), (.||.)
        -- * Product/Signal isomorphism
      , Bundle(..)
      , EmptyTuple(..)
      , TaggedEmptyTuple(..)
        -- * Simulation functions (not synthesizable)
      , simulate
      , simulateB
      , simulateWithReset
      , simulateWithResetN
      , runUntil
        -- ** lazy versions
      , simulate_lazy
      , simulateB_lazy
        -- ** Automaton
      , signalAutomaton
        -- * List \<-\> Signal conversion (not synthesizable)
      , sample
      , sampleN
      , sampleWithReset
      , sampleWithResetN
      , fromList
      , fromListWithReset
        -- ** lazy versions
      , sample_lazy
      , sampleN_lazy
      , fromList_lazy
        -- * QuickCheck combinators
      , testFor
        -- * Type classes
        -- ** 'Eq'-like
      , (.==.), (./=.)
        -- ** 'Ord'-like
      , (.<.), (.<=.), (.>=.), (.>.)
        -- * Bisignal functions
      , veryUnsafeToBiSignalIn
      , readFromBiSignal
      , writeToBiSignal
      , mergeBiSignalOuts

      -- * Deprecated
      , unsafeFromHighPolarity
      , unsafeFromLowPolarity
      , unsafeToHighPolarity
      , unsafeToLowPolarity
      )
    where

    import           Data.Bifunctor                 (bimap)
    import           Data.Int                       (Int64)
    import           Data.List                      (uncons)
    import           Data.Maybe                     (isJust)
    import           GHC.TypeLits                   (type (<=))

    import           Clash.Annotations.Primitive    (hasBlackBox)
    import           Clash.Promoted.Nat             (SNat(..), snatToNum)
    import           Clash.Signal.Bundle
      (Bundle (..), EmptyTuple(..), TaggedEmptyTuple(..), vecBundle#)
    import           Clash.Signal.BiSignal
    import           Clash.Signal.Internal
    import           Clash.Signal.Internal.Ambiguous
      (knownVDomain, clockPeriod, activeEdge, resetKind, initBehavior, resetPolarity)
    import qualified Clash.Sized.Vector
    import           Clash.XException
      (NFDataX, deepErrorX, fromJustX, seqX, ShowX(..))

    {- $setup
    >>> :set -XDataKinds -XTypeApplications -XFlexibleInstances -XMultiParamTypeClasses -XTypeFamilies
    >>> :set -fno-warn-deprecations
    >>> :m -Prelude
    >>> import Clash.Explicit.Prelude
    >>> import Clash.Promoted.Nat (SNat(..))
    >>> import qualified Data.List as L
    >>> :{
    instance KnownDomain "Dom2" where
      type KnownConf "Dom2" = 'DomainConfiguration "Dom2" 2 'Rising 'Asynchronous 'Defined 'ActiveHigh
      knownDomain = SDomainConfiguration SSymbol SNat SRising SAsynchronous SDefined SActiveHigh
    :}

    >>> :{
    instance KnownDomain "Dom7" where
      type KnownConf "Dom7" = 'DomainConfiguration "Dom7" 7 'Rising 'Asynchronous 'Defined 'ActiveHigh
      knownDomain = SDomainConfiguration SSymbol SNat SRising SAsynchronous SDefined SActiveHigh
    :}

    >>> type Dom2 = "Dom2"
    >>> type Dom7 = "Dom7"
    >>> let clk2 = clockGen @Dom2
    >>> let clk7 = clockGen @Dom7
    >>> let en2 = enableGen @Dom2
    >>> let en7 = enableGen @Dom7
    >>> let oversampling clkA clkB enA enB dflt = delay clkB enB dflt . unsafeSynchronizer clkA clkB . delay clkA enA dflt
    >>> let almostId clkA clkB enA enB dflt = delay clkB enB dflt . unsafeSynchronizer clkA clkB . delay clkA enA dflt . unsafeSynchronizer clkB clkA . delay clkB enB dflt
    >>> let oscillate clk rst en = let s = register clk rst en False (not <$> s) in s
    >>> let count clk rst en = let s = regEn clk rst en 0 (oscillate clk rst en) (s + 1) in s
    >>> :{
    sometimes1 clk rst en = s where
      s = register clk rst en Nothing (switch <$> s)
      switch Nothing = Just 1
      switch _       = Nothing
    :}

    >>> :{
    countSometimes clk rst en = s where
      s = regMaybe clk rst en 0 (plusM (pure <$> s) (sometimes1 clk rst en))
      plusM = liftA2 (liftA2 (+))
    :}

    -}

    {- $conveniencetypes

    If you want to write part of your Clash design as domain-polymorphic functions,
    it can be practical to define a design-wide constraint synonym that captures the
    characteristics of the clock domains of the design. Such a constraint synonym
    can be used as a constraint on all domain-polymorphic functions in the design,
    regardless of whether they actually need the constraints from this section.

    @
    type DesignDomain dom =
      ( 'HasSynchronousReset' dom
      , 'HasDefinedInitialValues' dom
      )

    type DesignDomainHidden dom =
      ( DesignDomain dom
      , t'Clash.Signal.HiddenClockResetEnable' dom
      )

    myFunc ::
      DesignDomainHidden dom =>
      'Signal' dom [...]
    @

    This way, you don't have to think about which constraints the function you're
    writing has exactly, and the constraint is succinct.
    -}

    -- **Clock
    -- | Clock generator for the 'System' clock domain.
    --
    -- __NB__: Should only be used for simulation, and __not__ for the /testBench/
    -- function. For the /testBench/ function, used 'Clash.Explicit.Testbench.tbSystemClockGen'
    systemClockGen
      :: Clock System
    systemClockGen :: Clock System
    systemClockGen = Clock System
    forall (dom :: Domain). KnownDomain dom => Clock dom
    clockGen

    -- | Reset generator for use in simulation, for the 'System' clock domain.
    -- Asserts the reset for a single cycle.
    --
    -- __NB__: While this can be used in the @testBench@ function, it cannot be
    -- synthesized to hardware.
    --
    -- === __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'
    -- @
    systemResetGen ::Reset System
    systemResetGen :: Reset System
    systemResetGen = Reset System
    forall (dom :: Domain). KnownDomain dom => Reset dom
    resetGen

    -- ** Synchronization primitive
    -- | The 'unsafeSynchronizer' function is a primitive that must be used to
    -- connect one clock domain to the other, and will be synthesized to a (bundle
    -- of) wire(s) in the eventual circuit. This function should only be used as
    -- part of a proper synchronization component, such as the following dual
    -- flip-flop synchronizer:
    --
    -- @
    -- dualFlipFlop
    --   :: Clock domA
    --   -> Clock domB
    --   -> Enable domA
    --   -> Enable domB
    --   -> Bit
    --   -> Signal domA Bit
    --   -> Signal domB Bit
    -- dualFlipFlop clkA clkB enA enB dflt =
    --   'delay' clkB enB dflt . 'delay' clkB enB dflt . 'unsafeSynchronizer' clkA clkB
    -- @
    --
    -- The 'unsafeSynchronizer' works in such a way that, given 2 clocks:
    --
    -- @
    -- createDomain vSystem{vName=\"Dom7\", vPeriod=7}
    --
    -- clk7 :: 'Clock' Dom7
    -- clk7 = 'clockGen'
    --
    -- en7 :: 'Enable' Dom7
    -- en7 = 'enableGen'
    -- @
    --
    -- and
    --
    -- @
    -- createDomain vSystem{vName=\"Dom2\", vPeriod=2}
    --
    -- clk2 :: 'Clock' Dom2
    -- clk2 = 'clockGen'
    --
    -- en2 :: 'Enable' Dom2
    -- en2 = 'enableGen'
    -- @
    --
    -- Oversampling followed by compression is the identity function plus 2 initial
    -- values:
    --
    -- @
    -- 'delay' clkB enB dflt $
    -- 'unsafeSynchronizer' clkA clkB $
    -- 'delay' clkA enA dflt $
    -- 'unsafeSynchronizer' clkB clkA $
    -- 'delay' clkB enB s
    --
    -- ==
    --
    -- dflt :- dflt :- s
    -- @
    --
    -- Something we can easily observe:
    --
    -- @
    -- oversampling clkA clkB enA enB dflt =
    --   'delay' clkB enB dflt
    --     . 'unsafeSynchronizer' clkA clkB
    --     . 'delay' clkA enA dflt
    -- almostId clkA clkB enA enB dflt =
    --   'delay' clkB enB dflt
    --     . 'unsafeSynchronizer' clkA clkB
    --     . 'delay' clkA enA dflt
    --     . 'unsafeSynchronizer' clkB clkA
    --     . 'delay' clkB enB dflt
    -- @
    --
    -- >>> sampleN 37 (oversampling clk7 clk2 en7 en2 0 (fromList [(1::Int)..10]))
    -- [0,0,1,1,1,2,2,2,2,3,3,3,4,4,4,4,5,5,5,6,6,6,6,7,7,7,8,8,8,8,9,9,9,10,10,10,10]
    -- >>> sampleN 12 (almostId clk2 clk7 en2 en7 0 (fromList [(1::Int)..10]))
    -- [0,0,1,2,3,4,5,6,7,8,9,10]
    unsafeSynchronizer
      :: 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
    unsafeSynchronizer :: forall (dom1 :: Domain) (dom2 :: Domain) a.
    (KnownDomain dom1, KnownDomain dom2) =>
    Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
    unsafeSynchronizer Clock dom1
    clk1 Clock dom2
    clk2 =
      [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go (Clock dom1 -> Clock dom2 -> [ClockAB]
    forall (domA :: Domain) (domB :: Domain).
    (KnownDomain domA, KnownDomain domB) =>
    Clock domA -> Clock domB -> [ClockAB]
    clockTicks Clock dom1
    clk1 Clock dom2
    clk2)
     where
      go :: [ClockAB] -> Signal dom1 a -> Signal dom2 a
      go :: [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go [] Signal dom1 a
    _ = [Char] -> Signal dom2 a
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "unsafeSynchronizer.go: `ticks` should have been an infinite list"
      go (ClockAB
    tick:[ClockAB]
    ticks) ass :: Signal dom1 a
    ass@(~(a
    a :- Signal dom1 a
    as)) =
        case ClockAB
    tick of
          ClockAB
    ClockA  -> [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go [ClockAB]
    ticks Signal dom1 a
    as
          ClockAB
    ClockB  -> a
    a a -> Signal dom2 a -> Signal dom2 a
    forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
    :- [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go [ClockAB]
    ticks Signal dom1 a
    ass
          ClockAB
    ClockAB -> [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go (ClockAB
    ClockBClockAB -> [ClockAB] -> [ClockAB]
    forall a. a -> [a] -> [a]
    :ClockAB
    ClockAClockAB -> [ClockAB] -> [ClockAB]
    forall a. a -> [a] -> [a]
    :[ClockAB]
    ticks) Signal dom1 a
    ass
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE unsafeSynchronizer #-}
    {-# ANN unsafeSynchronizer hasBlackBox #-}

    -- | Same as 'unsafeSynchronizer', but with manually supplied clock periods.
    --
    -- Note: this unsafeSynchronizer is defined to be consistent with the vhdl and verilog
    -- implementations however as only synchronous signals are represented in Clash this
    -- cannot be done precisely and can lead to odd behavior. For example,
    --
    -- @
    -- sample $ unsafeSynchronizer \@Dom2 \@Dom7 . unsafeSynchronizer \@Dom7 \@Dom2 $ fromList [0..10]
    -- > [0,4,4,4,7,7,7,7,11,11,11..
    -- @
    --
    -- is quite different from the identity,
    --
    -- @
    -- sample $ fromList [0..10]
    -- > [0,1,2,3,4,5,6,7,8,9,10..
    -- @
    --
    -- with values appearing from the "future".
    veryUnsafeSynchronizer
      :: Either Int (Signal dom1 Int)
      -- ^ Period of clock belonging to @dom1@. 'Left' if clock has a static period,
      -- 'Right' if periods are dynamic.
      -> Either Int (Signal dom2 Int)
      -- ^ Period of clock belonging to @dom2@. 'Left' if clock has a static period,
      -- 'Right' if periods are dynamic.
      -> Signal dom1 a
      -> Signal dom2 a
    veryUnsafeSynchronizer :: forall (dom1 :: Domain) (dom2 :: Domain) a.
    Either Int (Signal dom1 Int)
    -> Either Int (Signal dom2 Int) -> Signal dom1 a -> Signal dom2 a
    veryUnsafeSynchronizer Either Int (Signal dom1 Int)
    t1e Either Int (Signal dom2 Int)
    t2e =
      [ClockAB] -> Signal dom1 a -> Signal dom2 a
    forall (dom1 :: Domain) a (dom2 :: Domain).
    [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go (Either Int64 (Signal dom1 Int64)
    -> Either Int64 (Signal dom2 Int64) -> [ClockAB]
    forall (domA :: Domain) (domB :: Domain).
    Either Int64 (Signal domA Int64)
    -> Either Int64 (Signal domB Int64) -> [ClockAB]
    clockTicksEither (Either Int (Signal dom1 Int) -> Either Int64 (Signal dom1 Int64)
    forall (dom :: Domain).
    Either Int (Signal dom Int) -> Either Int64 (Signal dom Int64)
    toInt64 Either Int (Signal dom1 Int)
    t1e) (Either Int (Signal dom2 Int) -> Either Int64 (Signal dom2 Int64)
    forall (dom :: Domain).
    Either Int (Signal dom Int) -> Either Int64 (Signal dom Int64)
    toInt64 Either Int (Signal dom2 Int)
    t2e))
     where
      -- TODO: deprecate 'veryUnsafeSynchronizer' or change its type signature to use
      --       'Int64' to prevent issues down the road if/when we switch to represent
      --       clock periods using femtoseconds.
      toInt64 ::
        forall dom .
        Either Int (Signal dom Int) ->
        Either Int64 (Signal dom Int64)
      toInt64 :: forall (dom :: Domain).
    Either Int (Signal dom Int) -> Either Int64 (Signal dom Int64)
    toInt64 = (Int -> Int64)
    -> (Signal dom Int -> Signal dom Int64)
    -> Either Int (Signal dom Int)
    -> Either Int64 (Signal dom Int64)
    forall a b c d. (a -> b) -> (c -> d) -> Either a c -> Either b d
    forall (p :: Type -> Type -> Type) a b c d.
    Bifunctor p =>
    (a -> b) -> (c -> d) -> p a c -> p b d
    bimap Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral ((Int -> Int64) -> Signal dom Int -> Signal dom Int64
    forall a b. (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral)

      go :: [ClockAB] -> Signal dom1 a -> Signal dom2 a
      go :: forall (dom1 :: Domain) a (dom2 :: Domain).
    [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go [] Signal dom1 a
    _ = [Char] -> Signal dom2 a
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "veryUnsafeSynchronizer.go: `ticks` should have been an infinite list"
      go (ClockAB
    tick:[ClockAB]
    ticks) ass :: Signal dom1 a
    ass@(~(a
    a :- Signal dom1 a
    as)) =
        case ClockAB
    tick of
          ClockAB
    ClockA  -> [ClockAB] -> Signal dom1 a -> Signal dom2 a
    forall (dom1 :: Domain) a (dom2 :: Domain).
    [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go [ClockAB]
    ticks Signal dom1 a
    as
          ClockAB
    ClockB  -> a
    a a -> Signal dom2 a -> Signal dom2 a
    forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
    :- [ClockAB] -> Signal dom1 a -> Signal dom2 a
    forall (dom1 :: Domain) a (dom2 :: Domain).
    [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go [ClockAB]
    ticks Signal dom1 a
    ass
          ClockAB
    ClockAB -> [ClockAB] -> Signal dom1 a -> Signal dom2 a
    forall (dom1 :: Domain) a (dom2 :: Domain).
    [ClockAB] -> Signal dom1 a -> Signal dom2 a
    go (ClockAB
    ClockBClockAB -> [ClockAB] -> [ClockAB]
    forall a. a -> [a] -> [a]
    :ClockAB
    ClockAClockAB -> [ClockAB] -> [ClockAB]
    forall a. a -> [a] -> [a]
    :[ClockAB]
    ticks) Signal dom1 a
    ass
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE veryUnsafeSynchronizer #-}
    {-# ANN veryUnsafeSynchronizer hasBlackBox #-}

    -- * Basic circuit functions

    -- | Merge enable signal with signal of bools by applying the boolean AND
    -- operation.
    andEnable
      :: Enable dom
      -> Signal dom Bool
      -> Enable dom
    andEnable :: forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
    andEnable Enable dom
    e0 Signal dom Bool
    e1 =
      Signal dom Bool -> Enable dom
    forall (dom :: Domain). Signal dom Bool -> Enable dom
    toEnable (Enable dom -> Signal dom Bool
    forall (dom :: Domain). Enable dom -> Signal dom Bool
    fromEnable Enable dom
    e0 Signal dom Bool -> Signal dom Bool -> Signal dom Bool
    forall (f :: Type -> Type).
    Applicative f =>
    f Bool -> f Bool -> f Bool
    .&&. Signal dom Bool
    e1)
    {-# INLINE andEnable #-}

    -- | Special version of 'delay' that doesn't take enable signals of any kind.
    -- Initial value will be undefined.
    dflipflop
      :: ( KnownDomain dom
         , NFDataX a )
      => Clock dom
      -> Signal dom a
      -> Signal dom a
    dflipflop :: forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom -> Signal dom a -> Signal dom a
    dflipflop = \Clock dom
    clk Signal dom a
    i ->
      Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    delay#
        Clock dom
    clk
        (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))
        ([Char] -> a
    forall a. (NFDataX a, HasCallStack) => [Char] -> a
    deepErrorX [Char]
    "First value of dflipflop undefined")
        Signal dom a
    i
    {-# INLINE dflipflop #-}

    -- | \"@'delay' clk s@\" delays the values in 'Signal' /s/ for once cycle, the
    -- value at time 0 is /dflt/.
    --
    -- >>> sampleN 3 (delay systemClockGen enableGen 0 (fromList [1,2,3,4]))
    -- [0,1,2]
    delay
      :: ( KnownDomain dom
         , NFDataX a )
      => Clock dom
      -- ^ Clock
      -> Enable dom
      -- ^ Global enable
      -> a
      -- ^ Initial value
      -> Signal dom a
      -> Signal dom a
    delay :: forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    delay = Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    delay#
    {-# INLINE delay #-}

    -- | Version of 'delay' that only updates when its third argument is a 'Just'
    -- value.
    --
    -- >>> let input = fromList [Just 1, Just 2, Nothing, Nothing, Just 5, Just 6, Just (7::Int)]
    -- >>> sampleN 7 (delayMaybe systemClockGen enableGen 0 input)
    -- [0,1,2,2,2,5,6]
    delayMaybe
      :: ( KnownDomain dom
         , NFDataX a )
      => Clock dom
      -- ^ Clock
      -> Enable dom
      -- ^ Global enable
      -> a
      -- ^ Initial value
      -> Signal dom (Maybe a)
      -> Signal dom a
    delayMaybe :: forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Enable dom -> a -> Signal dom (Maybe a) -> Signal dom a
    delayMaybe = \Clock dom
    clk Enable dom
    gen a
    dflt Signal dom (Maybe a)
    i ->
      Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    delay# Clock dom
    clk (Enable dom -> Signal dom Bool -> Enable dom
    forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
    andEnable Enable dom
    gen (Maybe a -> Bool
    forall a. Maybe a -> Bool
    isJust (Maybe a -> Bool) -> Signal dom (Maybe a) -> Signal dom Bool
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Signal dom (Maybe a)
    i)) a
    dflt (Maybe a -> a
    forall a. (HasCallStack, NFDataX a) => Maybe a -> a
    fromJustX (Maybe a -> a) -> Signal dom (Maybe a) -> Signal dom a
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    <$> Signal dom (Maybe a)
    i)
    {-# INLINE delayMaybe #-}

    -- | Version of 'delay' that only updates when its third argument is asserted.
    --
    -- >>> let input = fromList [1,2,3,4,5,6,7::Int]
    -- >>> let enable = fromList [True,True,False,False,True,True,True]
    -- >>> sampleN 7 (delayEn systemClockGen enableGen 0 enable input)
    -- [0,1,2,2,2,5,6]
    delayEn
      :: ( KnownDomain dom
         , NFDataX a )
      => Clock dom
      -- ^ Clock
      -> Enable dom
      -- ^ Global enable
      -> a
      -- ^ Initial value
      -> Signal dom Bool
      -- ^ Enable
      -> Signal dom a
      -> Signal dom a
    delayEn :: forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Enable dom
    -> a
    -> Signal dom Bool
    -> Signal dom a
    -> Signal dom a
    delayEn = \Clock dom
    clk Enable dom
    gen a
    dflt Signal dom Bool
    en Signal dom a
    i ->
      Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
    delay# Clock dom
    clk (Enable dom -> Signal dom Bool -> Enable dom
    forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
    andEnable Enable dom
    gen Signal dom Bool
    en) a
    dflt Signal dom a
    i
    {-# INLINE delayEn #-}

    -- | \"@'register' clk rst en i s@\" delays the values in 'Signal' /s/ for one
    -- cycle, and sets the value to @i@ the moment the reset becomes 'False'.
    --
    -- >>> sampleN 5 (register systemClockGen resetGen enableGen 8 (fromList [1,1,2,3,4]))
    -- [8,8,1,2,3]
    register
      :: ( KnownDomain dom
         , NFDataX a )
      => Clock dom
      -- ^ clock
      -> Reset dom
      -- ^ Reset, 'register' outputs the reset value when the reset is active
      -> Enable dom
      -- ^ Global enable
      -> a
      -- ^ Reset value. If the domain has initial values enabled, the reset value
      -- will also be the initial value.
      -> Signal dom a
      -> Signal dom a
    register :: 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
    gen a
    initial Signal dom a
    i ->
      Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> a
    -> Signal dom a
    -> Signal dom a
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> a
    -> Signal dom a
    -> Signal dom a
    register# Clock dom
    clk Reset dom
    rst Enable dom
    gen a
    initial a
    initial Signal dom a
    i
    {-# INLINE register #-}

    -- | Version of 'register' that only updates its content when its fourth
    -- argument is a 'Just' value. So given:
    --
    -- @
    -- sometimes1 clk rst en = s where
    --   s = 'register' clk rst en Nothing (switch '<$>' s)
    --
    --   switch Nothing = Just 1
    --   switch _       = Nothing
    --
    -- countSometimes clk rst en = s where
    --   s     = 'regMaybe' clk rst en 0 (plusM ('pure' '<$>' s) (sometimes1 clk rst en))
    --   plusM = liftA2 (liftA2 (+))
    -- @
    --
    -- We get:
    --
    -- >>> sampleN 9 (sometimes1 systemClockGen resetGen enableGen)
    -- [Nothing,Nothing,Just 1,Nothing,Just 1,Nothing,Just 1,Nothing,Just 1]
    -- >>> sampleN 9 (count systemClockGen resetGen enableGen)
    -- [0,0,0,1,1,2,2,3,3]
    regMaybe
      :: ( KnownDomain dom
         , NFDataX a )
      => Clock dom
      -- ^ Clock
      -> Reset dom
      -- ^ Reset, 'regMaybe' outputs the reset value when the reset value is active
      -> Enable dom
      -- ^ Global enable
      -> a
      -- ^ Reset value. If the domain has initial values enabled, the reset value
      -- will also be the initial value.
      -> Signal dom (Maybe a)
      -> Signal dom a
    regMaybe :: forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> Signal dom (Maybe a)
    -> Signal dom a
    regMaybe = \Clock dom
    clk Reset dom
    rst Enable dom
    en a
    initial Signal dom (Maybe a)
    iM ->
      Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> a
    -> Signal dom a
    -> Signal dom a
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> a
    -> Signal dom a
    -> Signal dom a
    register# Clock dom
    clk Reset dom
    rst (Enable dom -> Signal dom Bool -> Enable dom
    forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
    andEnable Enable dom
    en ((Maybe a -> Bool) -> Signal dom (Maybe a) -> Signal dom Bool
    forall a b. (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Maybe a -> Bool
    forall a. Maybe a -> Bool
    isJust Signal dom (Maybe a)
    iM)) a
    initial a
    initial ((Maybe a -> a) -> Signal dom (Maybe a) -> Signal dom a
    forall a b. (a -> b) -> Signal dom a -> Signal dom b
    forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
    fmap Maybe a -> a
    forall a. (HasCallStack, NFDataX a) => Maybe a -> a
    fromJustX Signal dom (Maybe a)
    iM)
    {-# INLINE regMaybe #-}

    -- | Version of 'register' that only updates its content when its fourth
    -- argument is asserted. So given:
    --
    -- @
    -- oscillate clk rst en = let s = 'register' clk rst en False (not \<$\> s) in s
    -- count clk rst en     = let s = 'regEn clk rst en 0 (oscillate clk rst en) (s + 1) in s
    -- @
    --
    -- We get:
    --
    -- >>> sampleN 9 (oscillate systemClockGen resetGen enableGen)
    -- [False,False,True,False,True,False,True,False,True]
    -- >>> sampleN 9 (count systemClockGen resetGen enableGen)
    -- [0,0,0,1,1,2,2,3,3]
    regEn
      :: ( KnownDomain dom
         , NFDataX a
         )
      => Clock dom
      -- ^ Clock
      -> Reset dom
      -- ^ Reset, 'regEn' outputs the reset value when the reset value is active
      -> Enable dom
      -- ^ Global enable
      -> a
      -- ^ Reset value. If the domain has initial values enabled, the reset value
      -- will also be the initial value.
      -> Signal dom Bool
      -- ^ Enable signal
      -> Signal dom a
      -> Signal dom a
    regEn :: forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> Signal dom Bool
    -> Signal dom a
    -> Signal dom a
    regEn = \Clock dom
    clk Reset dom
    rst Enable dom
    gen a
    initial Signal dom Bool
    en Signal dom a
    i ->
      Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> a
    -> Signal dom a
    -> Signal dom a
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> a
    -> Signal dom a
    -> Signal dom a
    register# Clock dom
    clk Reset dom
    rst (Enable dom -> Signal dom Bool -> Enable dom
    forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
    andEnable Enable dom
    gen Signal dom Bool
    en) a
    initial a
    initial Signal dom a
    i
    {-# INLINE regEn #-}

    -- * Simulation functions

    -- | Same as 'simulate', but with the reset line asserted for /n/ cycles. Similar
    -- to 'simulate', 'simulateWithReset' will drop the output values produced while
    -- the reset is asserted. While the reset is asserted, the first value from
    -- @[a]@ is fed to the circuit.
    simulateWithReset
      :: forall dom a b m
       . ( KnownDomain dom
         , NFDataX a
         , NFDataX b
         , 1 <= m )
      => SNat m
      -- ^ Number of cycles to assert the reset
      -> a
      -- ^ Reset value
      -> ( KnownDomain dom
        => Clock dom
        -> Reset dom
        -> Enable dom
        -> Signal dom a
        -> Signal dom b )
      -- ^ Circuit to simulate
      -> [a]
      -> [b]
    simulateWithReset :: forall (dom :: Domain) a b (m :: Natural).
    (KnownDomain dom, NFDataX a, NFDataX b, 1 <= m) =>
    SNat m
    -> a
    -> (KnownDomain dom =>
        Clock dom
        -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b)
    -> [a]
    -> [b]
    simulateWithReset SNat m
    m a
    resetVal KnownDomain dom =>
    Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
    f [a]
    as =
      Int -> [b] -> [b]
    forall a. Int -> [a] -> [a]
    drop (SNat m -> Int
    forall a (n :: Natural). Num a => SNat n -> a
    snatToNum SNat m
    m) [b]
    out
     where
      inp :: [a]
    inp = Int -> a -> [a]
    forall a. Int -> a -> [a]
    replicate (SNat m -> Int
    forall a (n :: Natural). Num a => SNat n -> a
    snatToNum SNat m
    m) a
    resetVal [a] -> [a] -> [a]
    forall a. [a] -> [a] -> [a]
    ++ [a]
    as
      rst :: Reset dom
    rst = forall (dom :: Domain) (n :: Natural).
    (KnownDomain dom, 1 <= n) =>
    SNat n -> Reset dom
    resetGenN @dom SNat m
    m
      clk :: Clock dom
    clk = Clock dom
    forall (dom :: Domain). KnownDomain dom => Clock dom
    clockGen
      en :: Enable dom
    en  = Enable dom
    forall (dom :: Domain). Enable dom
    enableGen
      out :: [b]
    out = (Signal dom a -> Signal dom b) -> [a] -> [b]
    forall a b (dom1 :: Domain) (dom2 :: Domain).
    (NFDataX a, NFDataX b) =>
    (Signal dom1 a -> Signal dom2 b) -> [a] -> [b]
    simulate (Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
    KnownDomain dom =>
    Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
    f Clock dom
    clk Reset dom
    rst Enable dom
    forall (dom :: Domain). Enable dom
    en) [a]
    inp
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE simulateWithReset #-}

    -- | Same as 'simulateWithReset', but only sample the first /Int/ output values.
    simulateWithResetN
      :: ( KnownDomain dom
         , NFDataX a
         , NFDataX b
         , 1 <= m )
      => SNat m
      -- ^ Number of cycles to assert the reset
      -> a
      -- ^ Reset value
      -> Int
      -- ^ Number of cycles to simulate (excluding cycle spent in reset)
      -> ( KnownDomain dom
        => Clock dom
        -> Reset dom
        -> Enable dom
        -> Signal dom a
        -> Signal dom b )
      -- ^ Circuit to simulate
      -> [a]
      -> [b]
    simulateWithResetN :: forall (dom :: Domain) a b (m :: Natural).
    (KnownDomain dom, NFDataX a, NFDataX b, 1 <= m) =>
    SNat m
    -> a
    -> Int
    -> (KnownDomain dom =>
        Clock dom
        -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b)
    -> [a]
    -> [b]
    simulateWithResetN SNat m
    nReset a
    resetVal Int
    nSamples KnownDomain dom =>
    Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
    f [a]
    as =
      Int -> [b] -> [b]
    forall a. Int -> [a] -> [a]
    take Int
    nSamples (SNat m
    -> a
    -> (KnownDomain dom =>
        Clock dom
        -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b)
    -> [a]
    -> [b]
    forall (dom :: Domain) a b (m :: Natural).
    (KnownDomain dom, NFDataX a, NFDataX b, 1 <= m) =>
    SNat m
    -> a
    -> (KnownDomain dom =>
        Clock dom
        -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b)
    -> [a]
    -> [b]
    simulateWithReset SNat m
    nReset a
    resetVal Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
    KnownDomain dom =>
    Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
    f [a]
    as)
    {-# INLINE simulateWithResetN #-}

    -- | Simulate a (@'Unbundled' a -> 'Unbundled' b@) function given a list of
    -- samples of type /a/
    --
    -- >>> simulateB (unbundle . register systemClockGen resetGen enableGen (8,8) . bundle) [(1,1), (1,1), (2,2), (3,3)] :: [(Int,Int)]
    -- [(8,8),(8,8),(1,1),(2,2),(3,3)...
    -- ...
    --
    -- __NB__: This function is not synthesizable
    simulateB
      :: (Bundle a, Bundle b, NFDataX a, NFDataX b)
      => (Unbundled dom1 a -> Unbundled dom2 b)
      -- ^ The function we want to simulate
      -> [a]
      -- ^ Input samples
      -> [b]
    simulateB :: forall a b (dom1 :: Domain) (dom2 :: Domain).
    (Bundle a, Bundle b, NFDataX a, NFDataX b) =>
    (Unbundled dom1 a -> Unbundled dom2 b) -> [a] -> [b]
    simulateB Unbundled dom1 a -> Unbundled dom2 b
    f = (Signal dom1 a -> Signal dom2 b) -> [a] -> [b]
    forall a b (dom1 :: Domain) (dom2 :: Domain).
    (NFDataX a, NFDataX b) =>
    (Signal dom1 a -> Signal dom2 b) -> [a] -> [b]
    simulate (Unbundled dom2 b -> Signal dom2 b
    forall a (dom :: Domain).
    Bundle a =>
    Unbundled dom a -> Signal dom a
    forall (dom :: Domain). Unbundled dom b -> Signal dom b
    bundle (Unbundled dom2 b -> Signal dom2 b)
    -> (Signal dom1 a -> Unbundled dom2 b)
    -> Signal dom1 a
    -> Signal dom2 b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Unbundled dom1 a -> Unbundled dom2 b
    f (Unbundled dom1 a -> Unbundled dom2 b)
    -> (Signal dom1 a -> Unbundled dom1 a)
    -> Signal dom1 a
    -> Unbundled dom2 b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Signal dom1 a -> Unbundled dom1 a
    forall a (dom :: Domain).
    Bundle a =>
    Signal dom a -> Unbundled dom a
    forall (dom :: Domain). Signal dom a -> Unbundled dom a
    unbundle)

    -- | /Lazily/ simulate a (@'Unbundled' a -> 'Unbundled' b@) function given a
    -- list of samples of type /a/
    --
    -- >>> simulateB (unbundle . register systemClockGen resetGen enableGen (8,8) . bundle) [(1,1), (1,1), (2,2), (3,3)] :: [(Int,Int)]
    -- [(8,8),(8,8),(1,1),(2,2),(3,3)...
    -- ...
    --
    -- __NB__: This function is not synthesizable
    simulateB_lazy
      :: (Bundle a, Bundle b)
      => (Unbundled dom1 a -> Unbundled dom2 b)
      -- ^ The function we want to simulate
      -> [a]
      -- ^ Input samples
      -> [b]
    simulateB_lazy :: forall a b (dom1 :: Domain) (dom2 :: Domain).
    (Bundle a, Bundle b) =>
    (Unbundled dom1 a -> Unbundled dom2 b) -> [a] -> [b]
    simulateB_lazy Unbundled dom1 a -> Unbundled dom2 b
    f = (Signal dom1 a -> Signal dom2 b) -> [a] -> [b]
    forall (dom1 :: Domain) a (dom2 :: Domain) b.
    (Signal dom1 a -> Signal dom2 b) -> [a] -> [b]
    simulate_lazy (Unbundled dom2 b -> Signal dom2 b
    forall a (dom :: Domain).
    Bundle a =>
    Unbundled dom a -> Signal dom a
    forall (dom :: Domain). Unbundled dom b -> Signal dom b
    bundle (Unbundled dom2 b -> Signal dom2 b)
    -> (Signal dom1 a -> Unbundled dom2 b)
    -> Signal dom1 a
    -> Signal dom2 b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Unbundled dom1 a -> Unbundled dom2 b
    f (Unbundled dom1 a -> Unbundled dom2 b)
    -> (Signal dom1 a -> Unbundled dom1 a)
    -> Signal dom1 a
    -> Unbundled dom2 b
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Signal dom1 a -> Unbundled dom1 a
    forall a (dom :: Domain).
    Bundle a =>
    Signal dom a -> Unbundled dom a
    forall (dom :: Domain). Signal dom a -> Unbundled dom a
    unbundle)

    -- | Like 'fromList', but resets on reset and has a defined reset value.
    --
    -- >>> let rst = unsafeFromActiveHigh (fromList [True, True, False, False, True, False])
    -- >>> let res = fromListWithReset @System rst Nothing [Just 'a', Just 'b', Just 'c']
    -- >>> sampleN 6 res
    -- [Nothing,Nothing,Just 'a',Just 'b',Nothing,Just 'a']
    --
    -- __NB__: This function is not synthesizable
    fromListWithReset
      :: forall dom a
       . (KnownDomain dom, NFDataX a)
      => Reset dom
      -> a
      -> [a]
      -> Signal dom a
    fromListWithReset :: forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a) =>
    Reset dom -> a -> [a] -> Signal dom a
    fromListWithReset Reset dom
    rst a
    resetValue [a]
    vals =
      Signal dom Bool -> [a] -> Signal dom a
    go (Reset dom -> Signal dom Bool
    forall (dom :: Domain).
    KnownDomain dom =>
    Reset dom -> Signal dom Bool
    unsafeToActiveHigh Reset dom
    rst) [a]
    vals
     where
      go :: Signal dom Bool -> [a] -> Signal dom a
    go (Bool
    r :- Signal dom Bool
    rs) [a]
    _ | Bool
    r = a
    resetValue a -> Signal dom a -> Signal dom a
    forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
    :- Signal dom Bool -> [a] -> Signal dom a
    go Signal dom Bool
    rs [a]
    vals
      go (Bool
    _ :- Signal dom Bool
    rs) [] = [Char] -> a
    forall a. (NFDataX a, HasCallStack) => [Char] -> a
    deepErrorX [Char]
    "fromListWithReset: input ran out" a -> Signal dom a -> Signal dom a
    forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
    :- Signal dom Bool -> [a] -> Signal dom a
    go Signal dom Bool
    rs []
      go (Bool
    _ :- Signal dom Bool
    rs) (a
    a : [a]
    as) = a
    a a -> Signal dom a -> Signal dom a
    forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
    :- Signal dom Bool -> [a] -> Signal dom a
    go Signal dom Bool
    rs [a]
    as

    -- | Get a list of samples from a 'Signal', while asserting the reset line
    -- for /n/ clock cycles. 'sampleWithReset' does not return the first /n/ cycles,
    -- i.e., when the reset is asserted.
    --
    -- __NB__: This function is not synthesizable
    sampleWithReset
      :: forall dom a m
       . ( KnownDomain dom
         , NFDataX a
         , 1 <= m )
      => SNat m
      -- ^ Number of cycles to assert the reset
      -> (KnownDomain dom
          => Clock dom
          -> Reset dom
          -> Enable dom
          -> Signal dom a)
      -- ^ 'Signal' to sample
      -> [a]
    sampleWithReset :: forall (dom :: Domain) a (m :: Natural).
    (KnownDomain dom, NFDataX a, 1 <= m) =>
    SNat m
    -> (KnownDomain dom =>
        Clock dom -> Reset dom -> Enable dom -> Signal dom a)
    -> [a]
    sampleWithReset SNat m
    nReset KnownDomain dom =>
    Clock dom -> Reset dom -> Enable dom -> Signal dom a
    f0 =
      let f1 :: Signal dom a
    f1 = Clock dom -> Reset dom -> Enable dom -> Signal dom a
    KnownDomain dom =>
    Clock dom -> Reset dom -> Enable dom -> Signal dom a
    f0 Clock dom
    forall (dom :: Domain). KnownDomain dom => Clock dom
    clockGen (forall (dom :: Domain) (n :: Natural).
    (KnownDomain dom, 1 <= n) =>
    SNat n -> Reset dom
    resetGenN @dom SNat m
    nReset) Enable dom
    forall (dom :: Domain). Enable dom
    enableGen in
      Int -> [a] -> [a]
    forall a. Int -> [a] -> [a]
    drop (SNat m -> Int
    forall a (n :: Natural). Num a => SNat n -> a
    snatToNum SNat m
    nReset) (Signal dom a -> [a]
    forall (f :: Type -> Type) a. (Foldable f, NFDataX a) => f a -> [a]
    sample Signal dom a
    f1)
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE sampleWithReset #-}

    -- | Get a fine list of /m/ samples from a 'Signal', while asserting the reset line
    -- for /n/ clock cycles. 'sampleWithReset' does not return the first /n/ cycles,
    -- i.e., while the reset is asserted.
    --
    -- __NB__: This function is not synthesizable
    sampleWithResetN
      :: forall dom a m
       . ( KnownDomain dom
         , NFDataX a
         , 1 <= m )
      => SNat m
      -- ^ Number of cycles to assert the reset
      -> Int
      -- ^ Number of samples to produce
      -> (KnownDomain dom
          => Clock dom
          -> Reset dom
          -> Enable dom
          -> Signal dom a)
      -- ^ 'Signal' to sample
      -> [a]
    sampleWithResetN :: forall (dom :: Domain) a (m :: Natural).
    (KnownDomain dom, NFDataX a, 1 <= m) =>
    SNat m
    -> Int
    -> (KnownDomain dom =>
        Clock dom -> Reset dom -> Enable dom -> Signal dom a)
    -> [a]
    sampleWithResetN SNat m
    nReset Int
    nSamples KnownDomain dom =>
    Clock dom -> Reset dom -> Enable dom -> Signal dom a
    f =
      Int -> [a] -> [a]
    forall a. Int -> [a] -> [a]
    take Int
    nSamples (SNat m
    -> (KnownDomain dom =>
        Clock dom -> Reset dom -> Enable dom -> Signal dom a)
    -> [a]
    forall (dom :: Domain) a (m :: Natural).
    (KnownDomain dom, NFDataX a, 1 <= m) =>
    SNat m
    -> (KnownDomain dom =>
        Clock dom -> Reset dom -> Enable dom -> Signal dom a)
    -> [a]
    sampleWithReset SNat m
    nReset Clock dom -> Reset dom -> Enable dom -> Signal dom a
    KnownDomain dom =>
    Clock dom -> Reset dom -> Enable dom -> Signal dom a
    f)

    -- | Simulate a component until it matches a condition
    --
    -- It prints a message of the form
    --
    -- > Signal sampled for N cycles until value X
    --
    -- __NB__: This function is not synthesizable
    --
    -- === __Example with test bench__
    --
    -- A common usage is with a test bench using
    -- 'Clash.Explicit.Testbench.outputVerifier'.
    --
    -- __NB__: Since this uses 'Clash.Explicit.Testbench.assert', when using
    -- @clashi@, read the note at "Clash.Explicit.Testbench#assert-clashi".
    --
    -- @
    -- import Clash.Prelude
    -- import Clash.Explicit.Testbench
    --
    -- topEntity
    --   :: 'Signal' 'System' Int
    --   -> 'Signal' 'System' Int
    -- topEntity = id
    --
    -- testBench
    --   :: 'Signal' 'System' Bool
    -- testBench = done
    --  where
    --   testInput = 'Clash.Explicit.Testbench.stimuliGenerator' clk rst $('Clash.Sized.Vector.listToVecTH' [1 :: Int .. 10])
    --   expectedOutput =
    --     'Clash.Explicit.Testbench.outputVerifier'' clk rst $('Clash.Sized.Vector.listToVecTH' $ [1 :: Int .. 9] '<>' [42])
    --   done = expectedOutput $ topEntity testInput
    --   clk = 'Clash.Explicit.Testbench.tbSystemClockGen' (not \<$\> done)
    --   rst = 'systemResetGen'
    -- @
    --
    -- @
    -- > runUntil id testBench
    --
    --
    -- cycle(\<Clock: System\>): 10, outputVerifier
    -- expected value: 42, not equal to actual value: 10
    -- Signal sampled for 11 cycles until value True
    -- @
    --
    -- When you need to verify multiple test benches, the following invocations come
    -- in handy:
    --
    -- @
    -- > 'mapM_' (runUntil id) [ testBenchA, testBenchB ]
    -- @
    --
    -- or when the test benches are in different clock domains:
    --
    -- @
    -- testBenchA :: Signal DomA Bool
    -- testBenchB :: Signal DomB Bool
    -- @
    --
    -- @
    -- > 'sequence_' [ runUntil id testBenchA, runUntil id testBenchB ]
    -- @
    runUntil
      :: forall dom a
       . (KnownDomain dom, NFDataX a, ShowX a)
      => (a -> Bool)
      -- ^ Condition checking function, should return @True@ to finish run
      -> Signal dom a
      -- ^ 'Signal' we want to sample for the condition
      -> IO ()
    runUntil :: forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a, ShowX a) =>
    (a -> Bool) -> Signal dom a -> IO ()
    runUntil a -> Bool
    check Signal dom a
    s =
      -- Ensure invocations of 'trace' are printed before the result message
      a
    value a -> IO () -> IO ()
    forall a b. a -> b -> b
    `seqX`
      [Char] -> IO ()
    putStrLn [Char]
    msg
     where
      msg :: [Char]
    msg =   ([Char]
    "Signal sampled for " [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++) ([Char] -> [Char]) -> ([Char] -> [Char]) -> [Char] -> [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> [Char] -> [Char]
    forall a. Show a => a -> [Char] -> [Char]
    shows Int
    nSamples
            ([Char] -> [Char]) -> ([Char] -> [Char]) -> [Char] -> [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ([Char]
    " cycles until value " [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++) ([Char] -> [Char]) -> [Char] -> [Char]
    forall a b. (a -> b) -> a -> b
    $ a -> [Char]
    forall a. ShowX a => a -> [Char]
    showX a
    value
      ([a]
    before, [a]
    after) = (a -> Bool) -> [a] -> ([a], [a])
    forall a. (a -> Bool) -> [a] -> ([a], [a])
    break a -> Bool
    check ([a] -> ([a], [a])) -> [a] -> ([a], [a])
    forall a b. (a -> b) -> a -> b
    $ Signal dom a -> [a]
    forall (f :: Type -> Type) a. (Foldable f, NFDataX a) => f a -> [a]
    sample Signal dom a
    s
      nSamples :: Int
    nSamples = [a] -> Int
    forall a. [a] -> Int
    forall (t :: Type -> Type) a. Foldable t => t a -> Int
    length [a]
    before
      value :: a
    value = a -> ((a, [a]) -> a) -> Maybe (a, [a]) -> a
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe ([Char] -> a
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "impossible") (a, [a]) -> a
    forall a b. (a, b) -> a
    fst ([a] -> Maybe (a, [a])
    forall a. [a] -> Maybe (a, [a])
    uncons [a]
    after)

    {-# RULES "sequenceAVecSignal" Clash.Sized.Vector.traverse# (\x -> x) = vecBundle# #-}