{-|
Copyright  :  (C) 2013-2016, University of Twente,
                  2016-2019, Myrtle Software Ltd,
                  2017     , Google Inc.
License    :  BSD2 (see the file LICENSE)
Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>

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

@
'Signal' (dom :: 'Domain') 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 :: 'Domain'
  -- ^ Domain name
  , _period :: '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 an implementation 'System' with some common options
chosen:

@
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/. Memory elements respond to the rising edge of the clock,
asynchronously to changes in their resets, 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__: Whether 'System' has good defaults depends on your target platform.
Check out 'IntelSystem' and 'XilinxSystem' too!
-}

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}

{-# LANGUAGE Trustworthy #-}

#if __GLASGOW_HASKELL__ < 806
{-# LANGUAGE TypeInType #-}
#endif

{-# OPTIONS_HADDOCK show-extensions #-}

module Clash.Signal
  ( -- * Synchronous signals
    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
    -- ** Default domains
  , System
  , XilinxSystem
  , IntelSystem
  , vSystem
  , vIntelSystem
  , vXilinxSystem
    -- ** Domain utilities
  , VDomainConfiguration(..)
  , vDomain
  , createDomain
  , knownVDomain
  , clockPeriod
  , activeEdge
  , resetKind
  , initBehavior
  , resetPolarity
    -- * Clock
  , Clock
  , periodToHz
  , hzToPeriod
#ifdef CLASH_MULTIPLE_HIDDEN
    -- ** Synchronization primitive
  , unsafeSynchronizer
#endif
    -- * Reset
  , Reset
  , unsafeToReset
  , unsafeFromReset
  , unsafeToHighPolarity
  , unsafeToLowPolarity
  , unsafeFromHighPolarity
  , unsafeFromLowPolarity
#ifdef CLASH_MULTIPLE_HIDDEN
  , convertReset
#endif
  , resetSynchronizer
  , holdReset
    -- ** Enabling
  , Enable
  , toEnable
  , fromEnable
  , S.enableGen
    -- * Hidden clocks and resets
    -- $hiddenclockandreset

    -- ** Hidden clock
  , HiddenClock
  , hideClock
  , exposeClock
  , withClock
#ifdef CLASH_MULTIPLE_HIDDEN
  , exposeSpecificClock
  , withSpecificClock
#endif
  , hasClock
    -- ** Hidden reset
  , HiddenReset
  , hideReset
  , exposeReset
  , withReset
#ifdef CLASH_MULTIPLE_HIDDEN
  , exposeSpecificReset
  , withSpecificReset
#endif
  , hasReset
    -- ** Hidden enable
  , HiddenEnable
  , hideEnable
  , exposeEnable
  , withEnable
#ifdef CLASH_MULTIPLE_HIDDEN
  , exposeSpecificEnable
  , withSpecificEnable
#endif
  , hasEnable
    -- ** Hidden clock, reset, and enable
  , HiddenClockResetEnable
  , hideClockResetEnable
  , exposeClockResetEnable
  , withClockResetEnable
#ifdef CLASH_MULTIPLE_HIDDEN
  , exposeSpecificClockResetEnable
  , withSpecificClockResetEnable
#endif
  , SystemClockResetEnable
    -- * Basic circuit functions
  , 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
  , simulateN
  , simulateWithReset
  , simulateWithResetN
    -- ** lazy versions
  , simulate_lazy
  , simulateB_lazy
    -- * 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
  )
where
import           GHC.TypeLits          (type (<=))
import           Data.Proxy            (Proxy(..))
import           Prelude
import           Test.QuickCheck       (Property, property)


#ifdef CLASH_MULTIPLE_HIDDEN
import           GHC.TypeLits          (AppendSymbol)
import           Clash.Class.HasDomain (WithSingleDomain)
#endif

import           Clash.Class.HasDomain (WithSpecificDomain)
import qualified Clash.Explicit.Signal as E
import           Clash.Explicit.Signal
  (resetSynchronizer, systemClockGen, systemResetGen)
import qualified Clash.Explicit.Signal as S
import           Clash.Hidden
import           Clash.Promoted.Nat    (SNat (..), snatToNum)
import           Clash.Signal.Bundle
  (Bundle (..), EmptyTuple(..), TaggedEmptyTuple(..))
import           Clash.Signal.BiSignal --(BisignalIn, BisignalOut, )
import           Clash.Signal.Internal hiding
  (sample, sample_lazy, sampleN, sampleN_lazy, simulate, simulate_lazy, testFor)
import           Clash.Signal.Internal.Ambiguous
  (knownVDomain, clockPeriod, activeEdge, resetKind, initBehavior, resetPolarity)
import           Clash.XException      (NFDataX)

{- $setup
>>> :set -XFlexibleContexts -XTypeApplications
>>> import Clash.Promoted.Nat (SNat(..))
>>> import Clash.XException (printX)
>>> import Control.Applicative (liftA2)
>>> let oscillate = register False (not <$> oscillate)
>>> let count = regEn 0 oscillate (count + 1)
>>> :{
sometimes1 = s where
  s = register Nothing (switch <$> s)
  switch Nothing = Just 1
  switch _       = Nothing
:}

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

-}

-- * Hidden clock and reset arguments

{- $hiddenclockandreset #hiddenclockandreset#
Clocks and resets are by default implicitly routed to their components. You can
see from the type of a component whether it has hidden clock or reset
arguments:

It has a hidden clock when it has a:

@
f :: 'HiddenClock' dom => ...
@

Constraint.

Or it has a hidden reset when it has a:

@
g :: 'HiddenReset' dom polarity => ...
@

Constraint.

Or it has both a hidden clock argument and a hidden reset argument when it
has a:

@
h :: 'HiddenClockReset' dom  => ..
@

Constraint.

Given a component with an explicit clock and reset arguments, you can turn them
into hidden arguments using 'hideClock' and 'hideReset'. So given a:

@
f :: Clock dom -> Reset dom -> Signal dom a -> ...
@

You hide the clock and reset arguments by:

@
-- g :: 'HiddenClockReset' dom  => Signal dom a -> ...
g = 'hideClockReset' f
@

Or, alternatively, by:

@
-- h :: HiddenClockResetEnable dom  => Signal dom a -> ...
h = f 'hasClock' 'hasReset'
@

=== Assigning explicit clock and reset arguments to hidden clocks and resets

Given a component:

@
f :: HiddenClockResetEnable dom
  => Signal dom Int
  -> Signal dom Int
@

which has hidden clock and routed reset arguments, we expose those hidden
arguments so that we can explicitly apply them:

@
-- g :: Clock dom -> Reset dom -> Signal dom Int -> Signal dom Int
g = 'exposeClockResetEnable' f
@

or, alternatively, by:

@
-- h :: Clock dom -> Reset dom -> Signal dom Int -> Signal dom Int
h clk rst = withClock clk rst f
@

Similarly, there are 'exposeClock' and 'exposeReset' to connect just expose
the hidden clock or the hidden reset argument.

You will need to explicitly apply clocks and resets when you want to use
components such as PPLs and 'resetSynchronizer':

@
topEntity
  :: Clock System
  -> Reset System
  -> Enable System
  -> Signal System Int
  -> Signal System Int
topEntity clk rst =
  let (pllOut,pllStable) = 'Clash.Intel.ClockGen.altpll' (SSymbol \@\"altpll50\") clk rst
      rstSync            = 'resetSynchronizer' pllOut ('unsafeToAsyncReset' pllStable)
  in  'exposeClockResetEnable' f pllOut rstSync
@

or, using the alternative method:

@
topEntity2
  :: Clock System
  -> Reset System
  -> Signal System Int
  -> Signal System Int
topEntity2 clk rst =
  let (pllOut,pllStable) = 'Clash.Intel.ClockGen.altpll' (SSymbol \@\"altpll50\") clk rst
      rstSync            = 'resetSynchronizer' pllOut ('unsafeToAsyncReset' pllStable)
  in  'withClockReset' pllOut rstSync f
@

-}

#ifdef CLASH_MULTIPLE_HIDDEN
type HiddenClockName dom = AppendSymbol dom "_clk"
type HiddenResetName dom = AppendSymbol dom "_rst"
type HiddenEnableName dom = AppendSymbol dom "_en"
#else
type HiddenClockName (dom :: Domain) = "clock"
type HiddenResetName (dom :: Domain) = "reset"
type HiddenEnableName (dom :: Domain) = "enable"
#endif

-- | A /constraint/ that indicates the component has a hidden 'Clock'
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
type HiddenClock dom =
  ( Hidden (HiddenClockName dom) (Clock dom)
  , KnownDomain dom )

-- | A /constraint/ that indicates the component needs a 'Reset'
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
type HiddenReset dom =
  ( Hidden (HiddenResetName dom) (Reset dom)
  , KnownDomain dom )

-- | A /constraint/ that indicates the component needs a 'Enable'
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
type HiddenEnable dom =
  ( Hidden (HiddenEnableName dom) (Enable dom)
  , KnownDomain dom )

-- | A /constraint/ that indicates the component needs a 'Clock', a 'Reset',
-- and an 'Enable' belonging to the same dom.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
type HiddenClockResetEnable dom  =
  ( HiddenClock dom
  , HiddenReset dom
  , HiddenEnable dom
  )

-- | A /constraint/ that indicates the component needs a 'Clock', a 'Reset',
-- and an 'Enable' belonging to the 'System' dom.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
type SystemClockResetEnable =
  ( Hidden (HiddenClockName System) (Clock System)
  , Hidden (HiddenResetName System) (Reset System)
  , Hidden (HiddenEnableName System) (Enable System)
  )

-- | Expose a hidden 'Clock' argument of a component, so it can be applied
-- explicitly.
--
#ifdef CLASH_MULTIPLE_HIDDEN
-- This function can only be used on components with a single
-- domain. For example, this function will refuse when:
--
-- @
-- r ~ HiddenClock dom => Signal dom1 a -> Signal dom2 a
-- @
--
-- But will work when:
--
-- @
-- r ~ HiddenClock dom => Signal dom a -> Signal dom a
-- @
--
-- If you want to expose a clock of a component working on multiple domains
-- (such as the first example), use 'exposeSpecificClock'.
--
#endif
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- Usage with a /polymorphic/ domain:
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = exposeClock reg clockGen
-- >>> sampleN @System 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Force exposeClock to work on System (hence 'sampleN' not needing an explicit
-- domain later):
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = exposeClock @System reg clockGen
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
exposeClock
  :: forall dom  r
   .
#ifdef CLASH_MULTIPLE_HIDDEN
     WithSingleDomain dom r =>
#endif
     (HiddenClock dom => r)
  -- ^ The component with a hidden clock
  -> (KnownDomain dom => Clock dom -> r)
  -- ^ The component with its clock argument exposed
exposeClock :: (HiddenClock dom => r) -> KnownDomain dom => Clock dom -> r
exposeClock = \f :: HiddenClock dom => r
f clk :: Clock dom
clk -> (HiddenClock dom => Proxy dom -> r) -> Clock dom -> Proxy dom -> r
forall (dom :: Domain) r.
WithSpecificDomain dom r =>
(HiddenClock dom => r) -> KnownDomain dom => Clock dom -> r
exposeSpecificClock (r -> Proxy dom -> r
forall a b. a -> b -> a
const r
HiddenClock dom => r
f) Clock dom
clk (Proxy dom
forall k (t :: k). Proxy t
Proxy @dom)
{-# INLINE exposeClock #-}

-- | Expose a hidden 'Clock' argument of a component, so it can be applied
-- explicitly. This function can be used on components with multiple domains.
-- As opposed to 'exposeClock', callers should explicitly state what the clock
-- domain is. See the examples for more information.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- 'exposeSpecificClock' can only be used when it can find the specified domain
-- in /r/:
--
-- >>> reg = register @System 5 (reg + 1)
-- >>> sig = exposeSpecificClock @System reg clockGen
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Type variables work too, if they are in scope. For example:
--
-- @
-- reg = 'register' @@dom 5 (reg + 1)
-- sig = exposeSpecificClock @@dom reg 'clockGen'
-- @
--
exposeSpecificClock
   :: forall dom  r
   . WithSpecificDomain dom r
  => (HiddenClock dom => r)
  -- ^ The component with a hidden clock
  -> (KnownDomain dom => Clock dom -> r)
  -- ^ The component with its clock argument exposed
exposeSpecificClock :: (HiddenClock dom => r) -> KnownDomain dom => Clock dom -> r
exposeSpecificClock = \f :: HiddenClock dom => r
f clk :: Clock dom
clk -> (Hidden (HiddenClockName dom) (Clock dom) => r) -> Clock dom -> r
forall (x :: Domain) a r. (Hidden x a => r) -> a -> r
expose @(HiddenClockName dom) Hidden (HiddenClockName dom) (Clock dom) => r
HiddenClock dom => r
f Clock dom
clk
{-# INLINE exposeSpecificClock #-}

-- | Hide the 'Clock' argument of a component, so it can be routed implicitly.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
hideClock
  :: forall dom r
   . HiddenClock dom
  => (Clock dom -> r)
  -- ^ Function whose clock argument you want to hide
  -> r
hideClock :: (Clock dom -> r) -> r
hideClock = \f :: Clock dom -> r
f -> Clock dom -> r
f (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
{-# INLINE hideClock #-}

-- | Connect an explicit 'Clock' to a function with a hidden 'Clock'.
--
#ifdef CLASH_MULTIPLE_HIDDEN
-- This function can only be used on components with a single domain. For
-- example, this function will refuse when:
--
-- @
-- r ~ HiddenClock dom => Signal dom1 a -> Signal dom2 a
-- @
--
-- But will work when:
--
-- @
-- r ~ HiddenClock dom => Signal dom a -> Signal dom a
-- @
--
-- If you want to connect a clock to a component working on multiple domains
-- (such as the first example), use 'withSpecificClock'.
--
#endif
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- Usage with a _polymorphic_ domain:
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = withClock clockGen reg
-- >>> sampleN @System 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Force withClock to work on signal (hence 'sampleN' not needing an explicit
-- domain later):
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = withClock @System clockGen reg
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
withClock
  :: forall dom r
   .
#ifdef CLASH_MULTIPLE_HIDDEN
     WithSingleDomain dom r =>
#endif
     KnownDomain dom
  => Clock dom
  -- ^ The 'Clock' we want to connect
  -> (HiddenClock dom => r)
  -- ^ The function with a hidden 'Clock' argument
  -> r
withClock :: Clock dom -> (HiddenClock dom => r) -> r
withClock clk :: Clock dom
clk f :: HiddenClock dom => r
f = Clock dom -> (HiddenClock dom => Proxy dom -> r) -> Proxy dom -> r
forall (dom :: Domain) r.
(KnownDomain dom, WithSpecificDomain dom r) =>
Clock dom -> (HiddenClock dom => r) -> r
withSpecificClock Clock dom
clk (r -> Proxy dom -> r
forall a b. a -> b -> a
const r
HiddenClock dom => r
f) (Proxy dom
forall k (t :: k). Proxy t
Proxy @dom)
{-# INLINE withClock #-}

-- | Connect an explicit 'Clock' to a function with a hidden 'Clock'. This
-- function can be used on components with multiple domains. As opposed to
-- 'exposeClock', callers should explicitly state what the clock domain is. See
-- the examples for more information.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- 'withSpecificClock' can only be used when it can find the specified domain
-- in /r/:
--
-- >>> reg = register @System 5 (reg + 1)
-- >>> sig = withClock @System clockGen reg
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Type variables work too, if they are in scope. For example:
--
-- @
-- reg = 'register' @@dom 5 (reg + 1)
-- sig = withClock @@dom 'clockGen' reg
-- @
--
withSpecificClock
  :: forall dom r
   . (KnownDomain dom, WithSpecificDomain dom r)
  => Clock dom
  -- ^ The 'Clock' we want to connect
  -> (HiddenClock dom => r)
  -- ^ The function with a hidden 'Clock' argument
  -> r
withSpecificClock :: Clock dom -> (HiddenClock dom => r) -> r
withSpecificClock = \clk :: Clock dom
clk f :: HiddenClock dom => r
f -> (Hidden (HiddenClockName dom) (Clock dom) => r) -> Clock dom -> r
forall (x :: Domain) a r. (Hidden x a => r) -> a -> r
expose @(HiddenClockName dom) Hidden (HiddenClockName dom) (Clock dom) => r
HiddenClock dom => r
f Clock dom
clk
{-# INLINE withSpecificClock #-}

-- | Connect a hidden 'Clock' to an argument where a normal 'Clock' argument
-- was expected.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
hasClock
  :: forall dom
   . HiddenClock dom
  => Clock dom
hasClock :: Clock dom
hasClock = forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom)
{-# INLINE hasClock #-}

-- | Expose a hidden 'Reset' argument of a component, so it can be applied
-- explicitly.
--
#ifdef CLASH_MULTIPLE_HIDDEN
-- This function can only be used on components with a single domain. For
-- example, this function will refuse when:
--
-- @
-- r ~ HiddenReset dom => Signal dom1 a -> Signal dom2 a
-- @
--
-- But will work when:
--
-- @
-- r ~ HiddenReset dom => Signal dom a -> Signal dom a
-- @
--
-- If you want to expose a reset of a component working on multiple domains
-- (such as the first example), use 'exposeSpecificReset'.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
#endif
-- === __Example__
-- Usage with a /polymorphic/ domain:
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = exposeReset reg resetGen
-- >>> sampleN @System 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Force exposeReset to work on System (hence 'sampleN' not needing an explicit
-- domain later):
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = exposeReset @System reg resetGen
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
exposeReset
  :: forall dom r
   .
#ifdef CLASH_MULTIPLE_HIDDEN
     WithSingleDomain dom r =>
#endif
     (HiddenReset dom => r)
  -- ^ The component with a hidden reset
  -> (KnownDomain dom => Reset dom -> r)
  -- ^ The component with its reset argument exposed
exposeReset :: (HiddenReset dom => r) -> KnownDomain dom => Reset dom -> r
exposeReset = \f :: HiddenReset dom => r
f rst :: Reset dom
rst -> (HiddenReset dom => Proxy dom -> r) -> Reset dom -> Proxy dom -> r
forall (dom :: Domain) r.
WithSpecificDomain dom r =>
(HiddenReset dom => r) -> KnownDomain dom => Reset dom -> r
exposeSpecificReset (r -> Proxy dom -> r
forall a b. a -> b -> a
const r
HiddenReset dom => r
f) Reset dom
rst (Proxy dom
forall k (t :: k). Proxy t
Proxy @dom)
{-# INLINE exposeReset #-}

-- | Expose a hidden 'Reset' argument of a component, so it can be applied
-- explicitly. This function can be used on components with multiple domains.
-- As opposed to 'exposeReset', callers should explicitly state what the reset
-- domain is. See the examples for more information.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- 'exposeSpecificReset' can only be used when it can find the specified domain
-- in /r/:
--
-- >>> reg = register @System 5 (reg + 1)
-- >>> sig = exposeSpecificReset @System reg resetGen
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Type variables work too, if they are in scope. For example:
--
-- @
-- reg = 'register' @@dom 5 (reg + 1)
-- sig = exposeSpecificReset @@dom reg 'resetGen'
-- @
--
exposeSpecificReset
  :: forall dom r
   . WithSpecificDomain dom r
  => (HiddenReset dom => r)
  -- ^ The component with a hidden reset
  -> (KnownDomain dom => Reset dom -> r)
  -- ^ The component with its reset argument exposed
exposeSpecificReset :: (HiddenReset dom => r) -> KnownDomain dom => Reset dom -> r
exposeSpecificReset = \f :: HiddenReset dom => r
f rst :: Reset dom
rst -> (Hidden (HiddenResetName dom) (Reset dom) => r) -> Reset dom -> r
forall (x :: Domain) a r. (Hidden x a => r) -> a -> r
expose @(HiddenResetName dom) Hidden (HiddenResetName dom) (Reset dom) => r
HiddenReset dom => r
f Reset dom
rst
{-# INLINE exposeSpecificReset #-}

-- | Hide the 'Reset' argument of a component, so it can be routed implicitly.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
hideReset
  :: forall dom r
   . HiddenReset dom
  => (Reset dom -> r)
  -- ^ Component whose reset argument you want to hide
  -> r
hideReset :: (Reset dom -> r) -> r
hideReset = \f :: Reset dom -> r
f -> Reset dom -> r
f (forall a. Hidden (HiddenResetName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenResetName dom))
{-# INLINE hideReset #-}

-- | Connect an explicit 'Reset' to a function with a hidden 'Reset'.
--
#ifdef CLASH_MULTIPLE_HIDDEN
-- This function can only be used on components with a single domain. For
-- example, this function will refuse when:
--
-- @
-- r ~ HiddenReset dom => Signal dom1 a -> Signal dom2 a
-- @
--
-- But will work when:
--
-- @
-- r ~ HiddenReset dom => Signal dom a -> Signal dom a
-- @
--
-- If you want to connect a reset to a component working on multiple domains
-- (such as the first example), use 'withSpecificReset'.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
#endif
-- === __Example__
-- Usage with a _polymorphic_ domain:
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = withReset resetGen reg
-- >>> sampleN @System 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Force withReset to work on signal (hence 'sampleN' not needing an explicit
-- domain later):
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = withReset @System resetGen reg
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
withReset
  :: forall dom r
   .
#ifdef CLASH_MULTIPLE_HIDDEN
     WithSingleDomain dom r =>
#endif
     KnownDomain dom
  => Reset dom
  -- ^ The 'Reset' we want to connect
  -> (HiddenReset dom => r)
  -- ^ The function with a hidden 'Reset' argument
  -> r
withReset :: Reset dom -> (HiddenReset dom => r) -> r
withReset = \rst :: Reset dom
rst f :: HiddenReset dom => r
f -> (Hidden (HiddenResetName dom) (Reset dom) => r) -> Reset dom -> r
forall (x :: Domain) a r. (Hidden x a => r) -> a -> r
expose @(HiddenResetName dom) Hidden (HiddenResetName dom) (Reset dom) => r
HiddenReset dom => r
f Reset dom
rst
{-# INLINE withReset #-}

-- | Connect an explicit 'Reset' to a function with a hidden 'Reset'. This
-- function can be used on components with multiple domains. As opposed to
-- 'exposeReset', callers should explicitly state what the reset domain is. See
-- the examples for more information.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- 'withSpecificReset' can only be used when it can find the specified domain
-- in /r/:
--
-- >>> reg = register @System 5 (reg + 1)
-- >>> sig = withReset @System resetGen reg
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Type variables work too, if they are in scope. For example:
--
-- @
-- reg = 'register' @@dom 5 (reg + 1)
-- sig = withReset @@dom 'resetGen' reg
-- @
--
withSpecificReset
  :: forall dom r
   . (KnownDomain dom, WithSpecificDomain dom r)
  => Reset dom
  -- ^ The 'Reset' we want to connect
  -> (HiddenReset dom => r)
  -- ^ The function with a hidden 'Reset' argument
  -> r
withSpecificReset :: Reset dom -> (HiddenReset dom => r) -> r
withSpecificReset = \rst :: Reset dom
rst f :: HiddenReset dom => r
f -> (Hidden (HiddenResetName dom) (Reset dom) => r) -> Reset dom -> r
forall (x :: Domain) a r. (Hidden x a => r) -> a -> r
expose @(HiddenResetName dom) Hidden (HiddenResetName dom) (Reset dom) => r
HiddenReset dom => r
f Reset dom
rst
{-# INLINE withSpecificReset #-}

-- | Connect a hidden 'Reset' to an argument where a normal 'Reset' argument
-- was expected.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
hasReset
  :: forall dom
   . HiddenReset dom
  => Reset dom
hasReset :: Reset dom
hasReset = forall a. Hidden (HiddenResetName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenResetName dom)
{-# INLINE hasReset #-}

-- | Expose a hidden 'Enable' argument of a component, so it can be applied
-- explicitly.
--
#ifdef CLASH_MULTIPLE_HIDDEN
-- This function can only be used on components with a single domain. For
-- example, this function will refuse when:
--
-- @
-- r ~ HiddenEnable dom => Signal dom1 a -> Signal dom2 a
-- @
--
-- But will work when:
--
-- @
-- r ~ HiddenEnable dom => Signal dom a -> Signal dom a
-- @
--
-- If you want to expose a enable of a component working on multiple domains
-- (such as the first example), use 'exposeSpecificEnable'.
--
#endif
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- Usage with a /polymorphic/ domain:
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = exposeEnable reg enableGen
-- >>> sampleN @System 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Force exposeEnable to work on System (hence 'sampleN' not needing an explicit
-- domain later):
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = exposeEnable @System reg enableGen
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
exposeEnable
  :: forall dom  r .
#ifdef CLASH_MULTIPLE_HIDDEN
     WithSingleDomain dom r =>
#endif
     (HiddenEnable dom => r)
  -- ^ The component with a hidden reset
  -> (KnownDomain dom => Enable dom -> r)
  -- ^ The component with its reset argument exposed
exposeEnable :: (HiddenEnable dom => r) -> KnownDomain dom => Enable dom -> r
exposeEnable = \f :: HiddenEnable dom => r
f gen :: Enable dom
gen -> (HiddenEnable dom => Proxy dom -> r)
-> Enable dom -> Proxy dom -> r
forall (dom :: Domain) r.
WithSpecificDomain dom r =>
(HiddenEnable dom => r) -> KnownDomain dom => Enable dom -> r
exposeSpecificEnable (r -> Proxy dom -> r
forall a b. a -> b -> a
const r
HiddenEnable dom => r
f) Enable dom
gen (Proxy dom
forall k (t :: k). Proxy t
Proxy @dom)
{-# INLINE exposeEnable #-}

-- | Expose a hidden 'Enable' argument of a component, so it can be applied
-- explicitly. This function can be used on components with multiple domains.
-- As opposed to 'exposeEnable', callers should explicitly state what the enable
-- domain is. See the examples for more information.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- 'exposeSpecificEnable' can only be used when it can find the specified domain
-- in /r/:
--
-- >>> reg = register @System 5 (reg + 1)
-- >>> sig = exposeSpecificEnable @System reg enableGen
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Type variables work too, if they are in scope. For example:
--
-- @
-- reg = 'register' @@dom 5 (reg + 1)
-- sig = exposeSpecificEnable @@dom reg 'enableGen'
-- @
--
exposeSpecificEnable
  :: forall dom r
   . WithSpecificDomain dom r
  => (HiddenEnable dom => r)
  -- ^ The component with a hidden reset
  -> (KnownDomain dom => Enable dom -> r)
  -- ^ The component with its reset argument exposed
exposeSpecificEnable :: (HiddenEnable dom => r) -> KnownDomain dom => Enable dom -> r
exposeSpecificEnable = \f :: HiddenEnable dom => r
f gen :: Enable dom
gen -> (Hidden (HiddenEnableName dom) (Enable dom) => r)
-> Enable dom -> r
forall (x :: Domain) a r. (Hidden x a => r) -> a -> r
expose @(HiddenEnableName dom) Hidden (HiddenEnableName dom) (Enable dom) => r
HiddenEnable dom => r
f Enable dom
gen
{-# INLINE exposeSpecificEnable #-}

-- | Hide the 'Enable' argument of a component, so it can be routed implicitly.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
hideEnable
  :: forall dom r
   . HiddenEnable dom
  => (Enable dom -> r)
  -- ^ Component whose reset argument you want to hide
  -> r
hideEnable :: (Enable dom -> r) -> r
hideEnable = \f :: Enable dom -> r
f -> Enable dom -> r
f (forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom))
{-# INLINE hideEnable #-}

-- | Connect an explicit 'Enable' to a function with a hidden 'Enable'.
--
#ifdef CLASH_MULTIPLE_HIDDEN
-- This function can only be used on components with a single domain. For
-- example, this function will refuse when:
--
-- @
-- r ~ HiddenEnable dom => Signal dom1 a -> Signal dom2 a
-- @
--
-- But will work when:
--
-- @
-- r ~ HiddenEnable dom => Signal dom a -> Signal dom a
-- @
--
-- If you want to connect a enable to a component working on multiple domains
-- (such as the first example), use 'withSpecificEnable'.
--
#endif
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- Usage with a _polymorphic_ domain:
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = withEnable enableGen reg
-- >>> sampleN @System 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Force withEnable to work on signal (hence 'sampleN' not needing an explicit
-- domain later):
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = withEnable @System enableGen reg
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
withEnable
  :: forall dom r
   . KnownDomain dom
#ifdef CLASH_MULTIPLE_HIDDEN
  => WithSingleDomain dom r
#endif
  => Enable dom
  -- ^ The 'Enable' we want to connect
  -> (HiddenEnable dom => r)
  -- ^ The function with a hidden 'Enable' argument
  -> r
withEnable :: Enable dom -> (HiddenEnable dom => r) -> r
withEnable = \gen :: Enable dom
gen f :: HiddenEnable dom => r
f -> (Hidden (HiddenEnableName dom) (Enable dom) => r)
-> Enable dom -> r
forall (x :: Domain) a r. (Hidden x a => r) -> a -> r
expose @(HiddenEnableName dom) Hidden (HiddenEnableName dom) (Enable dom) => r
HiddenEnable dom => r
f Enable dom
gen
{-# INLINE withEnable #-}

-- | Connect an explicit 'Reset' to a function with a hidden 'Enable'. This
-- function can be used on components with multiple domains. As opposed to
-- 'exposeEnable', callers should explicitly state what the enable domain is. See
-- the examples for more information.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- 'withSpecificEnable' can only be used when it can find the specified domain
-- in /r/:
--
-- >>> reg = register @System 5 (reg + 1)
-- >>> sig = withEnable @System enableGen reg
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Type variables work too, if they are in scope. For example:
--
-- @
-- reg = 'register' @@dom 5 (reg + 1)
-- sig = withEnable @@dom 'enableGen' reg
-- @
--
withSpecificEnable
  :: forall dom r
   . (KnownDomain dom, WithSpecificDomain dom r)
  => Enable dom
  -- ^ The 'Enable' we want to connect
  -> (HiddenEnable dom => r)
  -- ^ The function with a hidden 'Enable' argument
  -> r
withSpecificEnable :: Enable dom -> (HiddenEnable dom => r) -> r
withSpecificEnable = \gen :: Enable dom
gen f :: HiddenEnable dom => r
f -> (Hidden (HiddenEnableName dom) (Enable dom) => r)
-> Enable dom -> r
forall (x :: Domain) a r. (Hidden x a => r) -> a -> r
expose @(HiddenEnableName dom) Hidden (HiddenEnableName dom) (Enable dom) => r
HiddenEnable dom => r
f Enable dom
gen
{-# INLINE withSpecificEnable #-}

-- | Connect a hidden 'Enable' to an argument where a normal 'Enable' argument
-- was expected.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
hasEnable
  :: forall dom
   . HiddenEnable dom
  => Enable dom
hasEnable :: Enable dom
hasEnable = forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom)
{-# INLINE hasEnable #-}


-- | Expose a hidden 'Clock', 'Reset', and 'Enable' argument of a component, so
-- it can be applied explicitly.
--
#ifdef CLASH_MULTIPLE_HIDDEN
-- This function can only be used on components with a single domain. For
-- example, this function will refuse when:
--
-- @
-- r ~ HiddenClockResetEnable dom => Signal dom1 a -> Signal dom2 a
-- @
--
-- But will work when:
--
-- @
-- r ~ HiddenClockResetEnable dom => Signal dom a -> Signal dom a
-- @
--
-- If you want to expose a clock, reset, and enable of a component working on
-- multiple domains (such as the first example), use 'exposeSpecificClockResetEnable'.
--
#endif
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- Usage with a /polymorphic/ domain:
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = exposeClockResetEnable reg clockGen resetGen enableGen
-- >>> sampleN @System 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Force exposeClockResetEnable to work on System (hence 'sampleN' not needing an
-- explicit domain later):
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = exposeClockResetEnable @System reg clockGen resetGen enableGen
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Usage in a testbench context:
--
-- @
-- 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
-- @
exposeClockResetEnable
  :: forall dom r .
#ifdef CLASH_MULTIPLE_HIDDEN
     WithSingleDomain dom r =>
#endif
     (HiddenClockResetEnable dom => r)
  -- ^ The component with hidden clock, reset, and enable arguments
  -> (KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r)
  -- ^ The component with its clock, reset, and enable arguments exposed
exposeClockResetEnable :: (HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable =
  \f :: HiddenClockResetEnable dom => r
f clk :: Clock dom
clk rst :: Reset dom
rst en :: Enable dom
en ->
    (HiddenClock dom => Reset dom -> Enable dom -> r)
-> Clock dom -> Reset dom -> Enable dom -> r
forall (dom :: Domain) r.
WithSpecificDomain dom r =>
(HiddenClock dom => r) -> KnownDomain dom => Clock dom -> r
exposeSpecificClock ((HiddenReset dom => Enable dom -> r)
-> KnownDomain dom => Reset dom -> Enable dom -> r
forall (dom :: Domain) r.
WithSpecificDomain dom r =>
(HiddenReset dom => r) -> KnownDomain dom => Reset dom -> r
exposeSpecificReset ((HiddenEnable dom => r) -> KnownDomain dom => Enable dom -> r
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenEnable dom => r) -> KnownDomain dom => Enable dom -> r
exposeEnable HiddenEnable dom => r
HiddenClockResetEnable dom => r
f)) Clock dom
clk Reset dom
rst Enable dom
en
{-# INLINE exposeClockResetEnable #-}

#ifdef CLASH_MULTIPLE_HIDDEN
-- | Expose a hidden 'Clock', 'Reset', and 'Enable' argument of a component, so
-- it can be applied explicitly. This function can be used on components with
-- multiple domains. As opposed to 'exposeClockResetEnable', callers should
-- explicitly state what the enable domain is. See the examples for more
-- information.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- 'exposeSpecificClockResetEnable' can only be used when it can find the
-- specified domain in /r/:
--
-- >>> reg = register @System 5 (reg + 1)
-- >>> sig = exposeSpecificClockResetEnable @System reg clockGen resetGen enableGen
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Type variables work too, if they are in scope. For example:
--
-- @
-- reg = 'register' @@dom 5 (reg + 1)
-- sig = exposeSpecificClockResetEnable @@dom reg 'clockGen' 'resetGen' 'enableGen'
-- @
--
exposeSpecificClockResetEnable
  :: forall dom r
   . WithSpecificDomain dom r
  => (HiddenClockResetEnable dom => r)
  -- ^ The component with hidden clock, reset, and enable arguments
  -> (KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r)
  -- ^ The component with its clock, reset, and enable arguments exposed
exposeSpecificClockResetEnable :: (HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeSpecificClockResetEnable =
  \f :: HiddenClockResetEnable dom => r
f clk :: Clock dom
clk rst :: Reset dom
rst en :: Enable dom
en ->
    (HiddenClock dom => Reset dom -> Enable dom -> r)
-> Clock dom -> Reset dom -> Enable dom -> r
forall (dom :: Domain) r.
WithSpecificDomain dom r =>
(HiddenClock dom => r) -> KnownDomain dom => Clock dom -> r
exposeSpecificClock ((HiddenReset dom => Enable dom -> r)
-> KnownDomain dom => Reset dom -> Enable dom -> r
forall (dom :: Domain) r.
WithSpecificDomain dom r =>
(HiddenReset dom => r) -> KnownDomain dom => Reset dom -> r
exposeSpecificReset ((HiddenEnable dom => r) -> KnownDomain dom => Enable dom -> r
forall (dom :: Domain) r.
WithSpecificDomain dom r =>
(HiddenEnable dom => r) -> KnownDomain dom => Enable dom -> r
exposeSpecificEnable HiddenEnable dom => r
HiddenClockResetEnable dom => r
f)) Clock dom
clk Reset dom
rst Enable dom
en
{-# INLINE exposeSpecificClockResetEnable #-}
#endif

-- -- | Hide the 'Clock' and 'Reset' arguments of a component, so they can be
-- -- routed implicitly
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
hideClockResetEnable
  :: forall dom r
   . HiddenClockResetEnable dom
  => (KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r)
  -- ^ Component whose clock, reset, and enable argument you want to hide
  -> r
hideClockResetEnable :: (KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r) -> r
hideClockResetEnable =
  \f :: KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
f ->
    Clock dom -> Reset dom -> Enable dom -> r
KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
f
      (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
      (forall a. Hidden (HiddenResetName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenResetName dom))
      (forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom))
{-# INLINE hideClockResetEnable #-}

-- | Connect an explicit 'Clock', 'Reset', and 'Enable' to a function with a
-- hidden 'Clock', 'Reset', and 'Enable'.
--
#ifdef CLASH_MULTIPLE_HIDDEN
-- This function can only be used on components with a single domain. For
-- example, this function will refuse when:
--
-- @
-- r ~ HiddenClockResetEnable dom => Signal dom1 a -> Signal dom2 a
-- @
--
-- But will work when:
--
-- @
-- r ~ HiddenClockResetEnable dom => Signal dom a -> Signal dom a
-- @
--
-- If you want to connect a enable to a component working on multiple domains
-- (such as the first example), use 'withSpecificClockResetEnable'.
--
#endif
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- Usage with a _polymorphic_ domain:
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = withClockResetEnable clockGen resetGen enableGen reg
-- >>> sampleN @System 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Force withClockResetEnable to work on signal (hence 'sampleN' not needing
-- an explicit domain later):
--
-- >>> reg = register 5 (reg + 1)
-- >>> sig = withClockResetEnable @System clockGen resetGen enableGen reg
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
withClockResetEnable
  :: forall dom r
   . KnownDomain dom
#ifdef CLASH_MULTIPLE_HIDDEN
  => WithSingleDomain dom r
#endif
  => Clock dom
  -- ^ The 'Clock' we want to connect
  -> Reset dom
  -- ^ The 'Reset' we want to connect
  -> Enable dom
  -- ^ The 'Enable' we want to connect
  -> (HiddenClockResetEnable dom => r)
  -- ^ The function with a hidden 'Clock', hidden 'Reset', and hidden
  -- 'Enable' argument
  -> r
withClockResetEnable :: Clock dom
-> Reset dom
-> Enable dom
-> (HiddenClockResetEnable dom => r)
-> r
withClockResetEnable =
  \clk :: Clock dom
clk rst :: Reset dom
rst en :: Enable dom
en f :: HiddenClockResetEnable dom => r
f -> Clock dom
-> Reset dom
-> Enable dom
-> (HiddenClockResetEnable dom => Proxy dom -> r)
-> Proxy dom
-> r
forall (dom :: Domain) r.
(KnownDomain dom, WithSpecificDomain dom r) =>
Clock dom
-> Reset dom
-> Enable dom
-> (HiddenClockResetEnable dom => r)
-> r
withSpecificClockResetEnable Clock dom
clk Reset dom
rst Enable dom
en (r -> Proxy dom -> r
forall a b. a -> b -> a
const r
HiddenClockResetEnable dom => r
f) (Proxy dom
forall k (t :: k). Proxy t
Proxy @dom)
{-# INLINE withClockResetEnable #-}

-- | Connect an explicit 'Clock', 'Reset', and 'Enable' to a function with a
-- hidden 'Clock', 'Reset', and 'Enable'. This function can be used on components
-- with multiple domains. As opposed to 'exposeClockResetEnable', callers should
-- explicitly state what the enable domain is. See the examples for more
-- information.
--
-- <Clash-Signal.html#hiddenclockandreset Click here to read more about hidden clocks, resets, and enables>
--
-- === __Example__
-- 'withSpecificClockResetEnable' can only be used when it can find the
-- specified domain in /r/:
--
-- >>> reg = register @System 5 (reg + 1)
-- >>> sig = withClockResetEnable @System clockGen resetGen enableGen reg
-- >>> sampleN 10 sig
-- [5,5,6,7,8,9,10,11,12,13]
--
-- Type variables work too, if they are in scope. For example:
--
-- @
-- reg = 'register' @@dom 5 (reg + 1)
-- sig = withClockResetEnable @@dom 'clockGen' 'resetGen' 'enableGen' reg
-- @
--
withSpecificClockResetEnable
  :: forall dom r
   . (KnownDomain dom, WithSpecificDomain dom r)
  => Clock dom
  -- ^ The 'Clock' we want to connect
  -> Reset dom
  -- ^ The 'Reset' we want to connect
  -> Enable dom
  -- ^ The 'Enable' we want to connect
  -> (HiddenClockResetEnable dom => r)
  -- ^ The function with a hidden 'Clock', hidden 'Reset', and hidden
  -- 'Enable' argument
  -> r
withSpecificClockResetEnable :: Clock dom
-> Reset dom
-> Enable dom
-> (HiddenClockResetEnable dom => r)
-> r
withSpecificClockResetEnable =
  \clk :: Clock dom
clk rst :: Reset dom
rst en :: Enable dom
en f :: HiddenClockResetEnable dom => r
f -> Clock dom -> (HiddenClock dom => r) -> r
forall (dom :: Domain) r.
(KnownDomain dom, WithSpecificDomain dom r) =>
Clock dom -> (HiddenClock dom => r) -> r
withSpecificClock Clock dom
clk (Reset dom -> (HiddenReset dom => r) -> r
forall (dom :: Domain) r.
(KnownDomain dom, WithSpecificDomain dom r) =>
Reset dom -> (HiddenReset dom => r) -> r
withSpecificReset Reset dom
rst (Enable dom -> (HiddenEnable dom => r) -> r
forall (dom :: Domain) r.
(KnownDomain dom, WithSpecificDomain dom r) =>
Enable dom -> (HiddenEnable dom => r) -> r
withSpecificEnable Enable dom
en HiddenEnable dom => r
HiddenClockResetEnable dom => r
f))
{-# INLINE withSpecificClockResetEnable #-}

-- * Basic circuit functions

-- | Special version of 'delay' that doesn't take enable signals of any kind.
-- Initial value will be undefined.
dflipflop
  :: forall dom a
   . ( HiddenClock dom
     , NFDataX a )
  => Signal dom a
  -> Signal dom a
dflipflop :: Signal dom a -> Signal dom a
dflipflop =
  Clock dom -> Signal dom a -> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom -> Signal dom a -> Signal dom a
E.dflipflop (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
{-# INLINE dflipflop #-}

-- | 'delay' @s@ delays the values in 'Signal' @s@ for once cycle, the value
-- at time 0 is /dflt/.
--
-- >>> sampleN @System 3 (delay 0 (fromList [1,2,3,4]))
-- [0,1,2]
delay
  :: forall dom a
   . ( NFDataX a
     , HiddenClock dom
     , HiddenEnable dom  )
  => a
  -- ^ Initial value
  -> Signal dom a
  -- ^ Signal to delay
  -> Signal dom a
delay :: a -> Signal dom a -> Signal dom a
delay dflt :: a
dflt i :: 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#
    (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
    (forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom))
    a
dflt
    Signal dom a
i
{-# INLINE delay #-}

-- | Version of 'delay' that only updates when its second argument is a 'Just'
-- value.
--
-- >>> let input = fromList [Just 1, Just 2, Nothing, Nothing, Just 5, Just 6, Just (7::Int)]
-- >>> sampleN @System 7 (delayMaybe 0 input)
-- [0,1,2,2,2,5,6]
delayMaybe
  :: forall dom a
   . ( NFDataX a
     , HiddenClock dom
     , HiddenEnable dom  )
  => a
  -- ^ Initial value
  -> Signal dom (Maybe a)
  -> Signal dom a
delayMaybe :: a -> Signal dom (Maybe a) -> Signal dom a
delayMaybe dflt :: a
dflt i :: Signal dom (Maybe a)
i =
  Clock dom
-> Enable dom -> a -> Signal dom (Maybe a) -> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Enable dom -> a -> Signal dom (Maybe a) -> Signal dom a
E.delayMaybe
    (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
    (forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom))
    a
dflt
    Signal dom (Maybe a)
i
{-# INLINE delayMaybe #-}

-- | Version of 'delay' that only updates when its second 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 @System 7 (delayEn 0 enable input)
-- [0,1,2,2,2,5,6]
delayEn
  :: forall dom a
   . ( NFDataX a
     , HiddenClock dom
     , HiddenEnable dom  )
  => a
  -- ^ Initial value
  -> Signal dom Bool
  -- ^ Enable
  -> Signal dom a
  -> Signal dom a
delayEn :: a -> Signal dom Bool -> Signal dom a -> Signal dom a
delayEn dflt :: a
dflt en :: Signal dom Bool
en i :: Signal dom a
i =
  Clock dom
-> Enable dom
-> a
-> Signal dom Bool
-> Signal dom a
-> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Enable dom
-> a
-> Signal dom Bool
-> Signal dom a
-> Signal dom a
E.delayEn
    (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
    (forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom))
    a
dflt
    Signal dom Bool
en
    Signal dom a
i
{-# INLINE delayEn #-}

-- | 'register' @i s@ delays the values in 'Signal' @s@ for one cycle, and sets
-- the value at time 0 to @i@
--
-- >>> sampleN @System 5 (register 8 (fromList [1,1,2,3,4]))
-- [8,8,1,2,3]
register
  :: forall dom a
   . ( HiddenClockResetEnable dom
     , NFDataX a )
  => a
  -- ^ Reset value
  --
  -- 'register' outputs the reset value when the reset value is active
  -> Signal dom a
  -> Signal dom a
register :: a -> Signal dom a -> Signal dom a
register i :: a
i s :: Signal dom a
s =
  Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
E.register
    (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
    (forall a. Hidden (HiddenResetName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenResetName dom))
    (forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom))
    a
i
    Signal dom a
s
{-# INLINE register #-}
infixr 3 `register`

-- | Version of 'register' that only updates its content when its second
-- argument is a 'Just' value. So given:
--
-- @
-- sometimes1 = s where
--   s = 'register' Nothing (switch '<$>' s)
--
--   switch Nothing = Just 1
--   switch _       = Nothing
--
-- countSometimes = s where
--   s     = 'regMaybe' 0 (plusM ('pure' '<$>' s) sometimes1)
--   plusM = 'liftA2' (liftA2 (+))
-- @
--
-- We get:
--
-- >>> sampleN @System 9 sometimes1
-- [Nothing,Nothing,Just 1,Nothing,Just 1,Nothing,Just 1,Nothing,Just 1]
-- >>> sampleN @System 9 countSometimes
-- [0,0,0,1,1,2,2,3,3]
regMaybe
  :: forall dom a
   . ( HiddenClockResetEnable dom
     , NFDataX a )
  => a
  -- ^ Reset value. 'regMaybe' outputs the reset value when the reset is active.
  -> Signal dom (Maybe a)
  -> Signal dom a
regMaybe :: a -> Signal dom (Maybe a) -> Signal dom a
regMaybe initial :: a
initial iM :: Signal dom (Maybe a)
iM =
  Clock dom
-> Reset dom
-> Enable dom
-> a
-> Signal dom (Maybe a)
-> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom
-> Enable dom
-> a
-> Signal dom (Maybe a)
-> Signal dom a
E.regMaybe
    (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
    (forall a. Hidden (HiddenResetName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenResetName dom))
    (forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom))
    a
initial
    Signal dom (Maybe a)
iM
{-# INLINE regMaybe #-}
infixr 3 `regMaybe`

-- | Version of 'register' that only updates its content when its second argument
-- is asserted. So given:
--
-- @
-- oscillate = 'register' False ('not' '<$>' oscillate)
-- count     = 'regEn' 0 oscillate (count + 1)
-- @
--
-- We get:
--
-- >>> sampleN @System 9 oscillate
-- [False,False,True,False,True,False,True,False,True]
-- >>> sampleN @System 9 count
-- [0,0,0,1,1,2,2,3,3]
regEn
  :: forall dom a
   . ( HiddenClockResetEnable dom
     , NFDataX a )
  => a
  -- ^ Reset value
  --
  -- 'regEn' outputs the reset value when the reset value is active
  -> Signal dom Bool
  -> Signal dom a
  -> Signal dom a
regEn :: a -> Signal dom Bool -> Signal dom a -> Signal dom a
regEn initial :: a
initial en :: Signal dom Bool
en i :: Signal dom a
i =
  Clock dom
-> Reset dom
-> Enable dom
-> a
-> Signal dom Bool
-> Signal dom a
-> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom
-> Enable dom
-> a
-> Signal dom Bool
-> Signal dom a
-> Signal dom a
E.regEn
    (forall a. Hidden (HiddenClockName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenClockName dom))
    (forall a. Hidden (HiddenResetName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenResetName dom))
    (forall a. Hidden (HiddenEnableName dom) a => a
forall (x :: Domain) a. Hidden x a => a
fromLabel @(HiddenEnableName dom))
    a
initial
    Signal dom Bool
en
    Signal dom a
i
{-# INLINE regEn #-}

-- * Signal -> List conversion

-- | Get an infinite list of samples from a 'Clash.Signal.Signal'
--
-- The elements in the list correspond to the values of the 'Signal'
-- at consecutive clock cycles
--
-- > sample s == [s0, s1, s2, s3, ...
--
-- If the given component has not yet been given a clock, reset, or enable
-- line, 'sample' will supply them. The reset will be asserted for a single
-- cycle. 'sample' will not drop the value produced by the circuit while
-- the reset was asserted. If you want this, or if you want more than a
-- single cycle reset, consider using 'sampleWithReset'.
--
-- __NB__: This function is not synthesizable
sample
  :: forall dom a
   . ( KnownDomain dom
     , NFDataX a )
  => (HiddenClockResetEnable dom  => Signal dom a)
  -- ^ 'Signal' we want to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
sample :: (HiddenClockResetEnable dom => Signal dom a) -> [a]
sample s :: HiddenClockResetEnable dom => Signal dom a
s =
  Signal dom a -> [a]
forall (f :: Type -> Type) a. (Foldable f, NFDataX a) => f a -> [a]
S.sample ((HiddenClockResetEnable dom => Signal dom a)
-> Clock dom -> Reset dom -> Enable dom -> Signal dom a
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable @dom HiddenClockResetEnable dom => Signal dom a
s Clock dom
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen Reset dom
forall (dom :: Domain). KnownDomain dom => Reset dom
resetGen Enable dom
forall (dom :: Domain). Enable dom
enableGen)
{-# NOINLINE sample #-}

-- | Get a list of /n/ samples from a 'Signal'
--
-- The elements in the list correspond to the values of the 'Signal'
-- at consecutive clock cycles
--
-- > sampleN @System 3 s == [s0, s1, s2]
--
-- If the given component has not yet been given a clock, reset, or enable
-- line, 'sampleN' will supply them. The reset will be asserted for a single
-- cycle. 'sampleN' will not drop the value produced by the circuit while
-- the reset was asserted. If you want this, or if you want more than a
-- single cycle reset, consider using 'sampleWithResetN'.
--
-- __NB__: This function is not synthesizable
sampleN
  :: forall dom a
   . ( KnownDomain dom
     , NFDataX a )
  => Int
  -- ^ Number of samples to produce
  -> (HiddenClockResetEnable dom => Signal dom a)
  -- ^ 'Signal' to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
sampleN :: Int -> (HiddenClockResetEnable dom => Signal dom a) -> [a]
sampleN n :: Int
n s0 :: HiddenClockResetEnable dom => Signal dom a
s0 =
  let s1 :: Signal dom a
s1 = (HiddenClockResetEnable dom => Signal dom a)
-> Clock dom -> Reset dom -> Enable dom -> Signal dom a
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable @dom HiddenClockResetEnable dom => Signal dom a
s0 Clock dom
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen Reset dom
forall (dom :: Domain). KnownDomain dom => Reset dom
resetGen Enable dom
forall (dom :: Domain). Enable dom
enableGen in
  Int -> Signal dom a -> [a]
forall (f :: Type -> Type) a.
(Foldable f, NFDataX a) =>
Int -> f a -> [a]
S.sampleN Int
n Signal dom a
s1
{-# NOINLINE sampleN #-}

-- | 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
  -> (HiddenClockResetEnable dom => Signal dom a)
  -- ^ 'Signal' to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
sampleWithReset :: SNat m -> (HiddenClockResetEnable dom => Signal dom a) -> [a]
sampleWithReset nReset :: SNat m
nReset f0 :: HiddenClockResetEnable dom => Signal dom a
f0 =
  let f1 :: Signal dom a
f1 = (HiddenClockResetEnable dom => Signal dom a)
-> Clock dom -> Reset dom -> Enable dom -> Signal dom a
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable HiddenClockResetEnable dom => Signal dom a
f0 Clock dom
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen (SNat m -> Reset dom
forall (dom :: Domain) (n :: Nat).
(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 :: Nat). 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]
S.sample Signal dom a
f1)
{-# NOINLINE 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
  -> (HiddenClockResetEnable dom => Signal dom a)
  -- ^ 'Signal' to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
sampleWithResetN :: SNat m
-> Int -> (HiddenClockResetEnable dom => Signal dom a) -> [a]
sampleWithResetN nReset :: SNat m
nReset nSamples :: Int
nSamples f :: HiddenClockResetEnable dom => Signal dom a
f =
  Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
nSamples (SNat m -> (HiddenClockResetEnable dom => Signal dom a) -> [a]
forall (dom :: Domain) a (m :: Nat).
(KnownDomain dom, NFDataX a, 1 <= m) =>
SNat m -> (HiddenClockResetEnable dom => Signal dom a) -> [a]
sampleWithReset SNat m
nReset HiddenClockResetEnable dom => Signal dom a
f)

-- | /Lazily/ get an infinite list of samples from a 'Clash.Signal.Signal'
--
-- The elements in the list correspond to the values of the 'Signal'
-- at consecutive clock cycles
--
-- > sample s == [s0, s1, s2, s3, ...
--
-- If the given component has not yet been given a clock, reset, or enable
-- line, 'sample_lazy' will supply them. The reset will be asserted for a
-- single cycle. 'sample_lazy' will not drop the value produced by the
-- circuit while the reset was asserted.
--
-- __NB__: This function is not synthesizable
sample_lazy
  :: forall dom a
   . KnownDomain dom
  => (HiddenClockResetEnable dom  => Signal dom a)
  -- ^ 'Signal' we want to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
sample_lazy :: (HiddenClockResetEnable dom => Signal dom a) -> [a]
sample_lazy s :: HiddenClockResetEnable dom => Signal dom a
s =
  Signal dom a -> [a]
forall (f :: Type -> Type) a. Foldable f => f a -> [a]
S.sample_lazy ((HiddenClockResetEnable dom => Signal dom a)
-> Clock dom -> Reset dom -> Enable dom -> Signal dom a
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable @dom HiddenClockResetEnable dom => Signal dom a
s Clock dom
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen Reset dom
forall (dom :: Domain). KnownDomain dom => Reset dom
resetGen Enable dom
forall (dom :: Domain). Enable dom
enableGen)
{-# NOINLINE sample_lazy #-}

-- | Lazily get a list of /n/ samples from a 'Signal'
--
-- The elements in the list correspond to the values of the 'Signal'
-- at consecutive clock cycles
--
-- > sampleN @System 3 s == [s0, s1, s2]
--
-- If the given component has not yet been given a clock, reset, or enable
-- line, 'sampleN_lazy' will supply them. The reset will be asserted for a
-- single cycle. 'sampleN_lazy' will not drop the value produced by the
-- circuit while the reset was asserted.
--
-- __NB__: This function is not synthesizable
sampleN_lazy
  :: forall dom a
   . KnownDomain dom
  => Int
  -> (HiddenClockResetEnable dom  => Signal dom a)
  -- ^ 'Signal' we want to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
sampleN_lazy :: Int -> (HiddenClockResetEnable dom => Signal dom a) -> [a]
sampleN_lazy n :: Int
n s :: HiddenClockResetEnable dom => Signal dom a
s =
  Int -> Signal dom a -> [a]
forall (f :: Type -> Type) a. Foldable f => Int -> f a -> [a]
S.sampleN_lazy Int
n ((HiddenClockResetEnable dom => Signal dom a)
-> Clock dom -> Reset dom -> Enable dom -> Signal dom a
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable @dom HiddenClockResetEnable dom => Signal dom a
s Clock dom
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen Reset dom
forall (dom :: Domain). KnownDomain dom => Reset dom
resetGen Enable dom
forall (dom :: Domain). Enable dom
enableGen)
{-# NOINLINE sampleN_lazy #-}

-- * Simulation functions

-- | Simulate a (@'Signal' a -> 'Signal' b@) function given a list of samples
-- of type /a/
--
-- >>> simulate @System (register 8) [1, 2, 3]
-- [8,1,2,3...
-- ...
--
-- Where 'System' denotes the /domain/ to simulate on. The reset line is
-- asserted for a single cycle. The first value is therefore supplied twice to
-- the circuit: once while reset is high, and once directly after. The first
-- /output/ value (the value produced while the reset is asserted) is dropped.
--
-- If you only want to simulate a finite number of samples, see 'simulateN'. If
-- you need the reset line to be asserted for more than one cycle or if you
-- need a custom reset value, see 'simulateWithReset' and 'simulateWithResetN'.
--
-- __NB__: This function is not synthesizable
simulate
  :: forall dom a b
   . ( KnownDomain dom
     , NFDataX a
     , NFDataX b )
  => (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
  -- ^ Circuit to simulate, whose source potentially has a hidden clock, reset,
  -- and/or enable.
  -> [a]
  -> [b]
simulate :: (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a] -> [b]
simulate f :: HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f as :: [a]
as = SNat 1
-> a
-> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a]
-> [b]
forall (dom :: Domain) a b (m :: Nat).
(KnownDomain dom, NFDataX a, NFDataX b, 1 <= m) =>
SNat m
-> a
-> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a]
-> [b]
simulateWithReset (KnownNat 1 => SNat 1
forall (n :: Nat). KnownNat n => SNat n
SNat @1) ([a] -> a
forall a. [a] -> a
head [a]
as) HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f [a]
as
{-# INLINE simulate #-}

-- | Same as 'simulate', but only sample the first /Int/ output values.
--
-- __NB__: This function is not synthesizable
simulateN
  :: forall dom a b
   . ( KnownDomain dom
     , NFDataX a
     , NFDataX b )
  => Int
  -- ^ Number of cycles to simulate (excluding cycle spent in reset)
  -> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
  -- ^ 'Signal' we want to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
  -> [b]
simulateN :: Int
-> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a]
-> [b]
simulateN n :: Int
n f :: HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f as :: [a]
as = SNat 1
-> a
-> Int
-> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a]
-> [b]
forall (dom :: Domain) a b (m :: Nat).
(KnownDomain dom, NFDataX a, NFDataX b, 1 <= m) =>
SNat m
-> a
-> Int
-> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a]
-> [b]
simulateWithResetN (KnownNat 1 => SNat 1
forall (n :: Nat). KnownNat n => SNat n
SNat @1) ([a] -> a
forall a. [a] -> a
head [a]
as) Int
n HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f [a]
as
{-# INLINE simulateN #-}

-- | 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 reset value /a/ is
-- supplied 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
  -> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
  -- ^ 'Signal' we want to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
  -> [b]
simulateWithReset :: SNat m
-> a
-> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a]
-> [b]
simulateWithReset n :: SNat m
n resetVal :: a
resetVal f :: HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f as :: [a]
as =
  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 :: Nat).
(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]
S.simulateWithReset SNat m
n a
resetVal ((HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> KnownDomain dom =>
   Clock dom
   -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f) [a]
as
{-# INLINE simulateWithReset #-}

-- | Same as 'simulateWithReset', but only sample the first /Int/ output values.
simulateWithResetN
  :: 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
  -> Int
  -- ^ Number of cycles to simulate (excluding cycles spent in reset)
  -> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
  -- ^ 'Signal' we want to sample, whose source potentially has a hidden clock
  -- (and reset)
  -> [a]
  -> [b]
simulateWithResetN :: SNat m
-> a
-> Int
-> (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a]
-> [b]
simulateWithResetN nReset :: SNat m
nReset resetVal :: a
resetVal nSamples :: Int
nSamples f :: HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f as :: [a]
as =
  SNat m
-> a
-> Int
-> (KnownDomain dom =>
    Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b)
-> [a]
-> [b]
forall (dom :: Domain) a b (m :: Nat).
(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]
S.simulateWithResetN SNat m
nReset a
resetVal Int
nSamples ((HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> KnownDomain dom =>
   Clock dom
   -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f) [a]
as
{-# INLINE simulateWithResetN #-}


-- | /Lazily/ simulate a (@'Signal' a -> 'Signal' b@) function given a list of
-- samples of type /a/
--
-- >>> simulate @System (register 8) [1, 2, 3]
-- [8,1,2,3...
-- ...
--
-- __NB__: This function is not synthesizable
simulate_lazy
  :: forall dom a b
   . KnownDomain dom
  => (HiddenClockResetEnable dom  =>
      Signal dom a -> Signal dom b)
  -- ^ Function we want to simulate, whose components potentially have a hidden
  -- clock (and reset)
  -> [a]
  -> [b]
simulate_lazy :: (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> [a] -> [b]
simulate_lazy f0 :: HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f0 =
  let f1 :: Signal dom a -> Signal dom b
f1 = (HiddenClockResetEnable dom => Signal dom a -> Signal dom b)
-> Clock dom
-> Reset dom
-> Enable dom
-> Signal dom a
-> Signal dom b
forall (dom :: Domain) r.
WithSingleDomain dom r =>
(HiddenClockResetEnable dom => r)
-> KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r
exposeClockResetEnable @dom HiddenClockResetEnable dom => Signal dom a -> Signal dom b
f0 Clock dom
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen Reset dom
forall (dom :: Domain). KnownDomain dom => Reset dom
resetGen Enable dom
forall (dom :: Domain). Enable dom
enableGen in
  [b] -> [b]
forall a. [a] -> [a]
tail ([b] -> [b]) -> ([a] -> [b]) -> [a] -> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Signal dom a -> Signal dom b) -> [a] -> [b]
forall (dom1 :: Domain) a (dom2 :: Domain) b.
(Signal dom1 a -> Signal dom2 b) -> [a] -> [b]
S.simulate_lazy Signal dom a -> Signal dom b
f1 ([a] -> [b]) -> ([a] -> [a]) -> [a] -> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. [a] -> [a]
dup1
{-# NOINLINE simulate_lazy #-}

-- | Simulate a (@'Unbundled' a -> 'Unbundled' b@) function given a list of
-- samples of type @a@
--
-- >>> simulateB @System (unbundle . register (8,8) . bundle) [(1,1), (2,2), (3,3)] :: [(Int,Int)]
-- [(8,8),(1,1),(2,2),(3,3)...
-- ...
--
-- __NB__: This function is not synthesizable
simulateB
  :: forall dom a b
   . ( KnownDomain dom
     , Bundle a
     , Bundle b
     , NFDataX a
     , NFDataX b
     )
  => (HiddenClockResetEnable dom  =>
      Unbundled dom a -> Unbundled dom b)
  -- ^ Function we want to simulate, whose components potentially have a hidden
  -- clock (and reset)
  -> [a]
  -> [b]
simulateB :: (HiddenClockResetEnable dom => Unbundled dom a -> Unbundled dom b)
-> [a] -> [b]
simulateB f0 :: HiddenClockResetEnable dom => Unbundled dom a -> Unbundled dom b
f0 =
  [b] -> [b]
forall a. [a] -> [a]
tail ([b] -> [b]) -> ([a] -> [b]) -> [a] -> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Unbundled dom a -> Unbundled dom b) -> [a] -> [b]
forall a b (dom1 :: Domain) (dom2 :: Domain).
(Bundle a, Bundle b, NFDataX a, NFDataX b) =>
(Unbundled dom1 a -> Unbundled dom2 b) -> [a] -> [b]
S.simulateB Unbundled dom a -> Unbundled dom b
f1 ([a] -> [b]) -> ([a] -> [a]) -> [a] -> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. [a] -> [a]
dup1
 where
  f1 :: Unbundled dom a -> Unbundled dom b
f1 =
    Clock dom
-> Reset dom
-> Enable dom
-> (HiddenClockResetEnable dom =>
    Proxy dom -> Unbundled dom a -> Unbundled dom b)
-> Proxy dom
-> Unbundled dom a
-> Unbundled dom b
forall (dom :: Domain) r.
(KnownDomain dom, WithSpecificDomain dom r) =>
Clock dom
-> Reset dom
-> Enable dom
-> (HiddenClockResetEnable dom => r)
-> r
withSpecificClockResetEnable
      @dom
      Clock dom
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen
      Reset dom
forall (dom :: Domain). KnownDomain dom => Reset dom
resetGen
      Enable dom
forall (dom :: Domain). Enable dom
enableGen
      ((Unbundled dom a -> Unbundled dom b)
-> Proxy dom -> Unbundled dom a -> Unbundled dom b
forall a b. a -> b -> a
const HiddenClockResetEnable dom => Unbundled dom a -> Unbundled dom b
Unbundled dom a -> Unbundled dom b
f0)
      (Proxy dom
forall k (t :: k). Proxy t
Proxy @dom)
{-# NOINLINE simulateB #-}

-- | /Lazily/ simulate a (@'Unbundled' a -> 'Unbundled' b@) function given a
-- list of samples of type @a@
--
-- >>> simulateB @System (unbundle . register (8,8) . bundle) [(1,1), (2,2), (3,3)] :: [(Int,Int)]
-- [(8,8),(1,1),(2,2),(3,3)...
-- ...
--
-- __NB__: This function is not synthesizable
simulateB_lazy
  :: forall dom a b
   . ( KnownDomain dom
     , Bundle a
     , Bundle b )
  => (HiddenClockResetEnable dom  =>
      Unbundled dom a -> Unbundled dom b)
  -- ^ Function we want to simulate, whose components potentially have a hidden
  -- clock (and reset)
  -> [a]
  -> [b]
simulateB_lazy :: (HiddenClockResetEnable dom => Unbundled dom a -> Unbundled dom b)
-> [a] -> [b]
simulateB_lazy f0 :: HiddenClockResetEnable dom => Unbundled dom a -> Unbundled dom b
f0 =
  [b] -> [b]
forall a. [a] -> [a]
tail ([b] -> [b]) -> ([a] -> [b]) -> [a] -> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Unbundled dom a -> Unbundled dom b) -> [a] -> [b]
forall a b (dom1 :: Domain) (dom2 :: Domain).
(Bundle a, Bundle b) =>
(Unbundled dom1 a -> Unbundled dom2 b) -> [a] -> [b]
S.simulateB_lazy Unbundled dom a -> Unbundled dom b
f1 ([a] -> [b]) -> ([a] -> [a]) -> [a] -> [b]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. [a] -> [a]
dup1
 where
  f1 :: Unbundled dom a -> Unbundled dom b
f1 =
    Clock dom
-> Reset dom
-> Enable dom
-> (HiddenClockResetEnable dom =>
    Proxy dom -> Unbundled dom a -> Unbundled dom b)
-> Proxy dom
-> Unbundled dom a
-> Unbundled dom b
forall (dom :: Domain) r.
(KnownDomain dom, WithSpecificDomain dom r) =>
Clock dom
-> Reset dom
-> Enable dom
-> (HiddenClockResetEnable dom => r)
-> r
withSpecificClockResetEnable
      @dom
      Clock dom
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen
      Reset dom
forall (dom :: Domain). KnownDomain dom => Reset dom
resetGen
      Enable dom
forall (dom :: Domain). Enable dom
enableGen
      ((Unbundled dom a -> Unbundled dom b)
-> Proxy dom -> Unbundled dom a -> Unbundled dom b
forall a b. a -> b -> a
const HiddenClockResetEnable dom => Unbundled dom a -> Unbundled dom b
Unbundled dom a -> Unbundled dom b
f0)
      (Proxy dom
forall k (t :: k). Proxy t
Proxy @dom)
{-# NOINLINE simulateB_lazy #-}

dup1 :: [a] -> [a]
dup1 :: [a] -> [a]
dup1 (x :: a
x:xs :: [a]
xs) = a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:a
xa -> [a] -> [a]
forall a. a -> [a] -> [a]
:[a]
xs
dup1 _      = [Char] -> [a]
forall a. HasCallStack => [Char] -> a
error "empty list"

-- * QuickCheck combinators

-- |  @testFor n s@ tests the signal /s/ for /n/ cycles.
--
-- __NB__: This function is not synthesizable
testFor
  :: KnownDomain dom
  => Int
  -- ^ The number of cycles we want to test for
  -> (HiddenClockResetEnable dom  => Signal dom Bool)
  -- ^ 'Signal' we want to evaluate, whose source potentially has a hidden clock
  -- (and reset)
  -> Property
testFor :: Int -> (HiddenClockResetEnable dom => Signal dom Bool) -> Property
testFor n :: Int
n s :: HiddenClockResetEnable dom => Signal dom Bool
s = Bool -> Property
forall prop. Testable prop => prop -> Property
property ([Bool] -> Bool
forall (t :: Type -> Type). Foldable t => t Bool -> Bool
and (Int -> (HiddenClockResetEnable dom => Signal dom Bool) -> [Bool]
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Int -> (HiddenClockResetEnable dom => Signal dom a) -> [a]
Clash.Signal.sampleN Int
n HiddenClockResetEnable dom => Signal dom Bool
s))

#ifdef CLASH_MULTIPLE_HIDDEN
-- ** Synchronization primitive
-- | Implicit version of 'Clash.Explicit.Signal.unsafeSynchronizer'.
unsafeSynchronizer
  :: forall dom1 dom2 a
   . ( HiddenClock dom1
     , HiddenClock dom2 )
  => Signal dom1 a
  -> Signal dom2 a
unsafeSynchronizer :: Signal dom1 a -> Signal dom2 a
unsafeSynchronizer =
  (Clock dom2 -> Signal dom1 a -> Signal dom2 a)
-> Signal dom1 a -> Signal dom2 a
forall (dom :: Domain) r. HiddenClock dom => (Clock dom -> r) -> r
hideClock ((Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a)
-> Clock dom2 -> Signal dom1 a -> Signal dom2 a
forall (dom :: Domain) r. HiddenClock dom => (Clock dom -> r) -> r
hideClock 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
S.unsafeSynchronizer)
#endif

-- | Hold reset for a number of cycles relative to an implicit reset signal.
--
-- Example:
--
-- >>> sampleN @System 8 (unsafeToHighPolarity (holdReset (SNat @2)))
-- [True,True,True,False,False,False,False,False]
--
-- 'holdReset' holds the reset for an additional 2 clock cycles for a total
-- of 3 clock cycles where the reset is asserted.
--
holdReset
  :: forall dom m
   . HiddenClockResetEnable dom
  => SNat m
  -- ^ Hold for /m/ cycles, counting from the moment the incoming reset
  -- signal becomes deasserted.
  -> Reset dom
holdReset :: SNat m -> Reset dom
holdReset m :: SNat m
m =
  (KnownDomain dom =>
 Clock dom -> Reset dom -> Enable dom -> Reset dom)
-> Reset dom
forall (dom :: Domain) r.
HiddenClockResetEnable dom =>
(KnownDomain dom => Clock dom -> Reset dom -> Enable dom -> r) -> r
hideClockResetEnable (\clk :: Clock dom
clk rst :: Reset dom
rst en :: Enable dom
en -> Clock dom -> Enable dom -> SNat m -> Reset dom -> Reset dom
forall (dom :: Domain) (n :: Nat).
KnownDomain dom =>
Clock dom -> Enable dom -> SNat n -> Reset dom -> Reset dom
E.holdReset Clock dom
clk Enable dom
en SNat m
m Reset dom
rst)

-- | Like 'fromList', but resets on reset and has a defined reset value.
--
-- >>> let rst = unsafeFromHighPolarity (fromList [True, True, False, False, True, False])
-- >>> let res = withReset rst (fromListWithReset Nothing [Just 'a', Just 'b', Just 'c'])
-- >>> sampleN @System 6 res
-- [Nothing,Nothing,Just 'a',Just 'b',Nothing,Just 'a']
--
-- __NB__: This function is not synthesizable
fromListWithReset
  :: forall dom a
   . (HiddenReset dom, NFDataX a)
  => a
  -> [a]
  -> Signal dom a
fromListWithReset :: a -> [a] -> Signal dom a
fromListWithReset = (Reset dom -> a -> [a] -> Signal dom a) -> a -> [a] -> Signal dom a
forall (dom :: Domain) r. HiddenReset dom => (Reset dom -> r) -> r
hideReset Reset dom -> a -> [a] -> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Reset dom -> a -> [a] -> Signal dom a
E.fromListWithReset
{-# INLINE fromListWithReset #-}

#ifdef CLASH_MULTIPLE_HIDDEN
-- | Convert between different types of reset, adding a synchronizer in case
-- it needs to convert from an asynchronous to a synchronous reset.
convertReset
  :: forall domA domB
   . ( HiddenClock domA
     , HiddenClock domB
     )
  => Reset domA
  -> Reset domB
convertReset :: Reset domA -> Reset domB
convertReset =
  Clock domA -> Clock domB -> Reset domA -> Reset domB
forall (domA :: Domain) (domB :: Domain).
(KnownDomain domA, KnownDomain domB) =>
Clock domA -> Clock domB -> Reset domA -> Reset domB
E.convertReset Clock domA
forall (dom :: Domain). HiddenClock dom => Clock dom
hasClock Clock domB
forall (dom :: Domain). HiddenClock dom => Clock dom
hasClock
#endif