{-|
Copyright  :  (C) 2013-2016, University of Twente,
                  2016-2019, Myrtle Software,
                  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 :: '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 DataKinds             #-}
{-# LANGUAGE ExplicitNamespaces    #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE MagicHash             #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeApplications      #-}
{-# LANGUAGE TypeOperators         #-}
{-# LANGUAGE ViewPatterns          #-}

{-# LANGUAGE Trustworthy #-}

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

{-# OPTIONS_HADDOCK show-extensions #-}

module Clash.Explicit.Signal
  ( -- * Synchronous signal
    Signal
    -- * 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
    -- ** Enabling
  , Enable(..)
  , toEnable
  , fromEnable
  , enableGen
    -- * Clock
  , Clock
  , freqCalc  -- DEPRECATED
  , periodToHz
  , hzToPeriod
    -- ** Synchronization primitive
  , unsafeSynchronizer
  , veryUnsafeSynchronizer
    -- * Reset
  , Reset(..)
  , unsafeToReset
  , unsafeFromReset
  , unsafeToHighPolarity
  , unsafeToLowPolarity
  , unsafeFromHighPolarity
  , unsafeFromLowPolarity
  , convertReset
  , resetSynchronizer
  , holdReset
    -- * Basic circuit functions
  , enable
  , dflipflop
  , delay
  , delayMaybe
  , delayEn
  , register
  , regMaybe
  , regEn
    -- * Simulation and testbench functions
  , clockGen
  , resetGen
  , resetGenN
  , systemClockGen
  , systemResetGen
    -- * Boolean connectives
  , (.&&.), (.||.)
    -- * Product/Signal isomorphism
  , Bundle(..)
    -- * Simulation functions (not synthesizable)
  , simulate
  , simulateB
  , simulateWithReset
  , simulateWithResetN
    -- ** lazy versions
  , simulate_lazy
  , simulateB_lazy
    -- * List \<-\> Signal conversion (not synthesizable)
  , sample
  , sampleN
  , fromList
  , fromListWithReset
    -- ** lazy versions
  , sample_lazy
  , sampleN_lazy
  , fromList_lazy
    -- * QuickCheck combinators
  , testFor
    -- * Type classes
    -- ** 'Eq'-like
  , (.==.), (./=.)
    -- ** 'Ord'-like
  , (.<.), (.<=.), (.>=.), (.>.)
  )
where

import           Data.Maybe                     (isJust, fromJust)
import           GHC.TypeLits                   (type (+), type (<=))

import           Clash.Annotations.Primitive    (hasBlackBox)
import           Clash.Class.Num                (satSucc, SaturationMode(SatBound))
import           Clash.Promoted.Nat             (SNat(..), snatToNum)
import           Clash.Signal.Bundle            (Bundle (..))
import           Clash.Signal.Internal
import           Clash.Signal.Internal.Ambiguous
  (knownVDomain, clockPeriod, activeEdge, resetKind, initBehavior, resetPolarity)
import           Clash.Sized.Index              (Index)
import           Clash.XException               (NFDataX, deepErrorX)

{- $setup
>>> :set -XDataKinds -XTypeApplications -XFlexibleInstances -XMultiParamTypeClasses -XTypeFamilies
>>> :set -fno-warn-deprecations
>>> 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 (+))
:}

-}

-- **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 'tbSystemClockGen'
systemClockGen
  :: Clock System
systemClockGen :: Clock System
systemClockGen = Clock System
forall (dom :: Domain). KnownDomain dom => Clock dom
clockGen

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

-- | Normally, asynchronous resets can be both asynchronously asserted and
-- de-asserted. Asynchronous de-assertion can induce meta-stability in the
-- component which is being reset. To ensure this doesn't happen,
-- 'resetSynchronizer' ensures that de-assertion of a reset happens
-- synchronously. Assertion of the reset remains asynchronous.
--
-- Note that asynchronous assertion does not induce meta-stability in the
-- component whose reset is asserted. However, when a component \"A\" in another
-- clock or reset domain depends on the value of a component \"B\" being
-- reset, then asynchronous assertion of the reset of component \"B"\ can induce
-- meta-stability in component \"A\". To prevent this from happening you need
-- to use a proper synchronizer, for example one of the synchronizers in
-- "Clash.Explicit.Synchronizer"
--
-- === __Example__
--
-- @
-- topEntity
--   :: Clock  System
--   -> Reset  System
--   -> Signal System Bit
--   -> Signal System (BitVector 8)
-- topEntity clk rst key1 =
--     let  (pllOut,pllStable) = altpll (SSymbol @"altpll50") clk rst
--          rstSync            = 'resetSynchronizer' pllOut (unsafeToHighPolarity pllStable)
--     in   exposeClockResetEnable leds pllOut rstSync
--   where
--     key1R  = isRising 1 key1
--     leds   = mealy blinkerT (1, False, 0) key1R
-- @
resetSynchronizer
  :: forall dom
   . KnownDomain dom
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> Reset dom
resetSynchronizer :: Clock dom -> Reset dom -> Enable dom -> Reset dom
resetSynchronizer clk :: Clock dom
clk rst :: Reset dom
rst en :: Enable dom
en =
  case forall (dom :: Domain) (sync :: ResetKind).
(KnownDomain dom, DomainResetKind dom ~ sync) =>
SResetKind sync
forall (sync :: ResetKind).
(KnownDomain dom,
 DomainConfigurationResetKind (KnownConf dom) ~ sync) =>
SResetKind sync
resetKind @dom of
    SAsynchronous ->
      let isActiveHigh :: Bool
isActiveHigh = case forall (dom :: Domain) (polarity :: ResetPolarity).
(KnownDomain dom, DomainResetPolarity dom ~ polarity) =>
SResetPolarity polarity
forall (polarity :: ResetPolarity).
(KnownDomain dom,
 DomainConfigurationResetPolarity (KnownConf dom) ~ polarity) =>
SResetPolarity polarity
resetPolarity @dom of { SActiveHigh -> Bool
True; _ -> Bool
False }
          r1 :: Signal dom Bool
r1 = Clock dom
-> Reset dom
-> Enable dom
-> Bool
-> Signal dom Bool
-> Signal dom Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register Clock dom
clk Reset dom
rst Enable dom
en Bool
isActiveHigh (Bool -> Signal dom Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Bool -> Bool
not Bool
isActiveHigh))
          r2 :: Signal dom Bool
r2 = Clock dom
-> Reset dom
-> Enable dom
-> Bool
-> Signal dom Bool
-> Signal dom Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register Clock dom
clk Reset dom
rst Enable dom
en Bool
isActiveHigh Signal dom Bool
r1
       in Signal dom Bool -> Reset dom
forall (dom :: Domain). Signal dom Bool -> Reset dom
unsafeToReset Signal dom Bool
r2
    SSynchronous ->
      -- Reset is already synchronous, nothing to do!
      Reset dom
rst

-- | Calculate the period, in __ps__, given a frequency in __Hz__
--
-- i.e. to calculate the clock period for a circuit to run at 240 MHz we get
--
-- >>> freqCalc 240e6
-- 4167
--
-- __NB__: This function is /not/ synthesizable
freqCalc :: Double -> Integer
freqCalc :: Double -> Integer
freqCalc = Natural -> Integer
forall a. Integral a => a -> Integer
toInteger (Natural -> Integer) -> (Double -> Natural) -> Double -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => Double -> Natural
Double -> Natural
hzToPeriod
{-# DEPRECATED freqCalc "Use 'hzToPeriod' instead." #-}

-- ** 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 :: Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
unsafeSynchronizer _clk1 :: Clock dom1
_clk1 _clk2 :: Clock dom2
_clk2 =
  Int -> Int -> Signal dom1 a -> Signal dom2 a
forall (dom1 :: Domain) a (dom2 :: Domain).
Int -> Int -> Signal dom1 a -> Signal dom2 a
veryUnsafeSynchronizer
    (SNat (DomainConfigurationPeriod (KnownConf dom1)) -> Int
forall a (n :: Nat). Num a => SNat n -> a
snatToNum (forall (period :: Nat).
(KnownDomain dom1,
 DomainConfigurationPeriod (KnownConf dom1) ~ period) =>
SNat period
forall (dom :: Domain) (period :: Nat).
(KnownDomain dom, DomainPeriod dom ~ period) =>
SNat period
clockPeriod @dom1))
    (SNat (DomainConfigurationPeriod (KnownConf dom2)) -> Int
forall a (n :: Nat). Num a => SNat n -> a
snatToNum (forall (period :: Nat).
(KnownDomain dom2,
 DomainConfigurationPeriod (KnownConf dom2) ~ period) =>
SNat period
forall (dom :: Domain) (period :: Nat).
(KnownDomain dom, DomainPeriod dom ~ period) =>
SNat period
clockPeriod @dom2))
{-# INLINE unsafeSynchronizer #-}

-- | 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 behaviour. 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
  :: Int
  -- ^ Period of clock belonging to 'dom1'
  -> Int
  -- ^ Period of clock belonging to 'dom2'
  -> Signal dom1 a
  -> Signal dom2 a
veryUnsafeSynchronizer :: Int -> Int -> Signal dom1 a -> Signal dom2 a
veryUnsafeSynchronizer t1 :: Int
t1 t2 :: Int
t2
  -- this case is just an optimisation for when the periods are the same
  | Int
t1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
t2 = Signal dom1 a -> Signal dom2 a
forall (dom1 :: Domain) a (dom2 :: Domain).
Signal dom1 a -> Signal dom2 a
same

  | Bool
otherwise = Int -> Signal dom1 a -> Signal dom2 a
forall (dom1 :: Domain) a (dom2 :: Domain).
Int -> Signal dom1 a -> Signal dom2 a
go 0

  where
  same :: Signal dom1 a -> Signal dom2 a
  same :: Signal dom1 a -> Signal dom2 a
same (s :: a
s :- ss :: Signal dom1 a
ss) = a
s a -> Signal dom2 a -> Signal dom2 a
forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
:- Signal dom1 a -> Signal dom2 a
forall (dom1 :: Domain) a (dom2 :: Domain).
Signal dom1 a -> Signal dom2 a
same Signal dom1 a
ss

  go :: Int -> Signal dom1 a -> Signal dom2 a
  go :: Int -> Signal dom1 a -> Signal dom2 a
go relativeTime :: Int
relativeTime (a :: a
a :- s :: Signal dom1 a
s)
    | Int
relativeTime Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= 0 = a
a a -> Signal dom2 a -> Signal dom2 a
forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
:- Int -> Signal dom1 a -> Signal dom2 a
forall (dom1 :: Domain) a (dom2 :: Domain).
Int -> Signal dom1 a -> Signal dom2 a
go (Int
relativeTime Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
t2) (a
a a -> Signal dom1 a -> Signal dom1 a
forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
:- Signal dom1 a
s)
    | Bool
otherwise = Int -> Signal dom1 a -> Signal dom2 a
forall (dom1 :: Domain) a (dom2 :: Domain).
Int -> Signal dom1 a -> Signal dom2 a
go (Int
relativeTime Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
t1) Signal dom1 a
s
{-# NOINLINE veryUnsafeSynchronizer #-}
{-# ANN veryUnsafeSynchronizer hasBlackBox #-}

-- * Basic circuit functions

-- | Merge enable signal with signal of bools
enable
  :: Enable dom
  -> Signal dom Bool
  -> Enable dom
enable :: Enable dom -> Signal dom Bool -> Enable dom
enable e0 :: Enable dom
e0 e1 :: 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 :: * -> *). Applicative f => f Bool -> f Bool -> f Bool
.&&. Signal dom Bool
e1)

-- | 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 :: Clock dom -> Signal dom a -> Signal dom a
dflipflop clk :: Clock dom
clk 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
    Clock dom
clk
    (Signal dom Bool -> Enable dom
forall (dom :: Domain). Signal dom Bool -> Enable dom
toEnable (Bool -> Signal dom Bool
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True))
    (String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX "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 :: 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 :: Clock dom
-> Enable dom -> a -> Signal dom (Maybe a) -> Signal dom a
delayMaybe clk :: Clock dom
clk gen :: Enable dom
gen dflt :: a
dflt i :: Signal dom (Maybe 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
delayEn Clock dom
clk Enable dom
gen a
dflt (Maybe a -> Bool
forall a. Maybe a -> Bool
isJust (Maybe a -> Bool) -> Signal dom (Maybe a) -> Signal dom Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (Maybe a)
i) (Maybe a -> a
forall a. HasCallStack => Maybe a -> a
fromJust (Maybe a -> a) -> Signal dom (Maybe a) -> Signal dom a
forall (f :: * -> *) 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 :: Clock dom
-> Enable dom
-> a
-> Signal dom Bool
-> Signal dom a
-> Signal dom a
delayEn clk :: Clock dom
clk gen :: Enable dom
gen dflt :: a
dflt en :: Signal dom Bool
en 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 Clock dom
clk (Enable dom -> Signal dom Bool -> Enable dom
forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
enable Enable dom
gen Signal dom Bool
en) a
dflt Signal dom a
i
{-# INLINE delayEn #-}

-- | \"@'register' clk rst 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 :: Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register clk :: Clock dom
clk rst :: Reset dom
rst gen :: Enable dom
gen initial :: a
initial i :: 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 :: Clock dom
-> Reset dom
-> Enable dom
-> a
-> Signal dom (Maybe a)
-> Signal dom a
regMaybe clk :: Clock dom
clk rst :: Reset dom
rst en :: Enable dom
en initial :: a
initial iM :: Signal dom (Maybe a)
iM =
  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
register Clock dom
clk Reset dom
rst (Enable dom -> Signal dom Bool -> Enable dom
forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
enable Enable dom
en ((Maybe a -> Bool) -> Signal dom (Maybe a) -> Signal dom Bool
forall (f :: * -> *) 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 ((Maybe a -> a) -> Signal dom (Maybe a) -> Signal dom a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Maybe a -> a
forall a. HasCallStack => Maybe a -> a
fromJust 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 :: Clock dom
-> Reset dom
-> Enable dom
-> a
-> Signal dom Bool
-> Signal dom a
-> Signal dom a
regEn clk :: Clock dom
clk rst :: Reset dom
rst gen :: Enable dom
gen initial :: a
initial en :: Signal dom Bool
en i :: Signal dom a
i =
  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
register Clock dom
clk Reset dom
rst (Enable dom -> Signal dom Bool -> Enable dom
forall (dom :: Domain). Enable dom -> Signal dom Bool -> Enable dom
enable Enable dom
gen Signal dom Bool
en) 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 :: SNat m
-> a
-> (KnownDomain dom =>
    Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b)
-> [a]
-> [b]
simulateWithReset m :: SNat m
m resetVal :: a
resetVal f :: KnownDomain dom =>
Clock dom
-> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
f as :: [a]
as =
  Int -> [b] -> [b]
forall a. Int -> [a] -> [a]
drop (SNat m -> Int
forall a (n :: Nat). 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 :: Nat). 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 = SNat m -> Reset dom
forall (dom :: Domain) (n :: Nat).
(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
{-# NOINLINE 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 :: SNat m
-> a
-> Int
-> (KnownDomain dom =>
    Clock dom
    -> Reset dom -> Enable dom -> Signal dom a -> Signal dom b)
-> [a]
-> [b]
simulateWithResetN nReset :: SNat m
nReset resetVal :: a
resetVal nSamples :: Int
nSamples f :: KnownDomain dom =>
Clock dom
-> Reset dom -> Enable dom -> Signal dom a -> Signal dom b
f as :: [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 :: 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]
simulateWithReset SNat m
nReset a
resetVal 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 :: (Unbundled dom1 a -> Unbundled dom2 b) -> [a] -> [b]
simulateB f :: 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
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
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 :: (Unbundled dom1 a -> Unbundled dom2 b) -> [a] -> [b]
simulateB_lazy f :: 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
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
unbundle)


-- | Hold reset for a number of cycles relative to an incoming reset signal.
--
-- Example:
--
-- >>> let sampleWithReset = sampleN 8 . unsafeToHighPolarity
-- >>> sampleWithReset (holdReset @System clockGen enableGen (SNat @2) (resetGenN (SNat @3)))
-- [True,True,True,True,True,False,False,False]
--
-- 'holdReset' holds the reset for an additional 2 clock cycles for a total
-- of 5 clock cycles where the reset is asserted. 'holdReset' also works on
-- intermediate assertions of the reset signal:
--
-- >>> let rst = fromList [True, False, False, False, True, False, False, False]
-- >>> sampleWithReset (holdReset @System clockGen enableGen (SNat @2) (unsafeFromHighPolarity rst))
-- [True,True,True,False,True,True,True,False]
--
holdReset
  :: forall dom n
   . KnownDomain dom
  => Clock dom
  -> Enable dom
  -- ^ Global enable
  -> SNat n
  -- ^ Hold for /n/ cycles, counting from the moment the incoming reset
  -- signal becomes deasserted.
  -> Reset dom
  -- ^ Reset to extend
  -> Reset dom
holdReset :: Clock dom -> Enable dom -> SNat n -> Reset dom -> Reset dom
holdReset clk :: Clock dom
clk en :: Enable dom
en SNat rst :: Reset dom
rst =
  Signal dom Bool -> Reset dom
forall (dom :: Domain).
KnownDomain dom =>
Signal dom Bool -> Reset dom
unsafeFromHighPolarity ((Index (n + 1) -> Index (n + 1) -> Bool
forall a. Eq a => a -> a -> Bool
/=Index (n + 1)
forall a. Bounded a => a
maxBound) (Index (n + 1) -> Bool)
-> Signal dom (Index (n + 1)) -> Signal dom Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (Index (n + 1))
counter)
 where
  counter :: Signal dom (Index (n+1))
  counter :: Signal dom (Index (n + 1))
counter = Clock dom
-> Reset dom
-> Enable dom
-> Index (n + 1)
-> Signal dom (Index (n + 1))
-> Signal dom (Index (n + 1))
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register Clock dom
clk Reset dom
rst Enable dom
en 0 (SaturationMode -> Index (n + 1) -> Index (n + 1)
forall a. SaturatingNum a => SaturationMode -> a -> a
satSucc SaturationMode
SatBound (Index (n + 1) -> Index (n + 1))
-> Signal dom (Index (n + 1)) -> Signal dom (Index (n + 1))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (Index (n + 1))
counter)

-- | Like 'fromList', but resets on reset and has a defined reset value.
--
-- >>> let rst = unsafeFromHighPolarity (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 :: Reset dom -> a -> [a] -> Signal dom a
fromListWithReset rst :: Reset dom
rst resetValue :: a
resetValue vals :: [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
unsafeToHighPolarity Reset dom
rst) [a]
vals
 where
  go :: Signal dom Bool -> [a] -> Signal dom a
go (r :: Bool
r :- rs :: Signal dom Bool
rs) _ | 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 (_ :- rs :: Signal dom Bool
rs) [] = String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX "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 (_ :- rs :: Signal dom Bool
rs) (a :: a
a : as :: [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

-- | 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
   . ( KnownDomain domA
     , KnownDomain domB
     )
  => Clock domA
  -> Clock domB
  -> Reset domA
  -> Reset domB
convertReset :: Clock domA -> Clock domB -> Reset domA -> Reset domB
convertReset clkA :: Clock domA
clkA clkB :: Clock domB
clkB (Reset domA -> Signal domA Bool
forall (dom :: Domain).
KnownDomain dom =>
Reset dom -> Signal dom Bool
unsafeToHighPolarity -> Signal domA Bool
rstA0) =
  Signal domB Bool -> Reset domB
forall (dom :: Domain).
KnownDomain dom =>
Signal dom Bool -> Reset dom
unsafeFromHighPolarity Signal domB Bool
rstA2
 where
  rstA1 :: Signal domB Bool
rstA1 = Clock domA -> Clock domB -> Signal domA Bool -> Signal domB Bool
forall (dom1 :: Domain) (dom2 :: Domain) a.
(KnownDomain dom1, KnownDomain dom2) =>
Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
unsafeSynchronizer Clock domA
clkA Clock domB
clkB Signal domA Bool
rstA0
  rstA2 :: Signal domB Bool
rstA2 =
    case (forall (dom :: Domain) (sync :: ResetKind).
(KnownDomain dom, DomainResetKind dom ~ sync) =>
SResetKind sync
forall (sync :: ResetKind).
(KnownDomain domA,
 DomainConfigurationResetKind (KnownConf domA) ~ sync) =>
SResetKind sync
resetKind @domA, forall (dom :: Domain) (sync :: ResetKind).
(KnownDomain dom, DomainResetKind dom ~ sync) =>
SResetKind sync
forall (sync :: ResetKind).
(KnownDomain domB,
 DomainConfigurationResetKind (KnownConf domB) ~ sync) =>
SResetKind sync
resetKind @domB) of
      (SSynchronous,  SSynchronous)  -> Signal domB Bool
rstA1
      (SAsynchronous, SAsynchronous) -> Signal domB Bool
rstA1
      (SSynchronous,  SAsynchronous) -> Signal domB Bool
rstA1
      (SAsynchronous, SSynchronous) ->
        Clock domB
-> Enable domB -> Bool -> Signal domB Bool -> Signal domB Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
delay Clock domB
clkB Enable domB
forall (dom :: Domain). Enable dom
enableGen Bool
True (Signal domB Bool -> Signal domB Bool)
-> Signal domB Bool -> Signal domB Bool
forall a b. (a -> b) -> a -> b
$
          Clock domB
-> Enable domB -> Bool -> Signal domB Bool -> Signal domB Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
delay Clock domB
clkB Enable domB
forall (dom :: Domain). Enable dom
enableGen Bool
True Signal domB Bool
rstA1