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

__This is the <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/safe_haskell.html Safe> API only of "Clash.Explicit.Prelude"__

This module defines the explicitly clocked counterparts of the functions
defined in "Clash.Prelude".
-}

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}

{-# LANGUAGE Safe #-}

{-# OPTIONS_HADDOCK show-extensions, not-home #-}

module Clash.Explicit.Prelude.Safe
  ( -- * Creating synchronous sequential circuits
    mealy
  , mealyB
  , moore
  , mooreB
  , registerB
    -- * Synchronizer circuits for safe clock domain crossing
  , dualFlipFlopSynchronizer
  , asyncFIFOSynchronizer
    -- * ROMs
  , asyncRom
  , asyncRomPow2
  , rom
  , romPow2
    -- * RAM primitives with a combinational read port
  , asyncRam
  , asyncRamPow2
    -- * BlockRAM primitives
  , blockRam
  , blockRamPow2
    -- ** BlockRAM read/write conflict resolution
  , readNew
    -- * Utility functions
  , isRising
  , isFalling
  , riseEvery
  , oscillate
    -- * Exported modules
    -- ** Synchronous signals
  , module Clash.Explicit.Signal
  , module Clash.Explicit.Signal.Delayed
    -- ** Datatypes
    -- *** Bit vectors
  , module Clash.Sized.BitVector
  , module Clash.Prelude.BitIndex
  , module Clash.Prelude.BitReduction
    -- *** Arbitrary-width numbers
  , module Clash.Sized.Signed
  , module Clash.Sized.Unsigned
  , module Clash.Sized.Index
    -- *** Fixed point numbers
  , module Clash.Sized.Fixed
    -- *** Fixed size vectors
  , module Clash.Sized.Vector
    -- *** Perfect depth trees
  , module Clash.Sized.RTree
    -- ** Annotations
  , module Clash.Annotations.TopEntity
    -- ** Generics type-classes
  , Generic
  , Generic1
    -- ** Type-level natural numbers
  , module GHC.TypeLits
  , module GHC.TypeLits.Extra
  , module Clash.Promoted.Nat
  , module Clash.Promoted.Nat.Literals
  , module Clash.Promoted.Nat.TH
    -- ** Type-level strings
  , module Clash.Promoted.Symbol
    -- ** Type classes
    -- *** Clash
  , module Clash.Class.BitPack
  , module Clash.Class.Num
  , module Clash.Class.Resize
    -- *** Other
  , module Control.Applicative
  , module Data.Bits
      -- ** Exceptions
  , module Clash.XException
    -- ** Named types
  , module Clash.NamedTypes
    -- ** Haskell Prelude
    -- $hiding
  , module Clash.HaskellPrelude
  )
where

import Control.Applicative
import Data.Bits
import GHC.Generics (Generic, Generic1)
import GHC.TypeLits
import GHC.TypeLits.Extra
import Clash.HaskellPrelude
import qualified Prelude

import Clash.Annotations.TopEntity
import Clash.Class.BitPack
import Clash.Class.Num
import Clash.Class.Resize
import Clash.NamedTypes

import Clash.Explicit.BlockRam
import Clash.Explicit.Mealy
import Clash.Explicit.Moore
import Clash.Explicit.RAM
import Clash.Explicit.ROM
import Clash.Explicit.Signal
import Clash.Explicit.Signal.Delayed
import Clash.Explicit.Synchronizer
  (dualFlipFlopSynchronizer, asyncFIFOSynchronizer)
import Clash.Prelude.BitIndex
import Clash.Prelude.BitReduction
import Clash.Prelude.ROM             (asyncRom, asyncRomPow2)
import Clash.Promoted.Nat
import Clash.Promoted.Nat.TH
import Clash.Promoted.Nat.Literals
import Clash.Promoted.Symbol
import Clash.Sized.BitVector
import Clash.Sized.Fixed
import Clash.Sized.Index
import Clash.Sized.RTree
import Clash.Sized.Signed
import Clash.Sized.Unsigned
import Clash.Sized.Vector hiding (fromList, unsafeFromList)
import Clash.XException

{- $setup
>>> :set -XDataKinds
>>> :m -Clash.Prelude
>>> :m -Clash.Prelude.Safe
>>> import Clash.Explicit.Prelude.Safe
>>> let rP clk rst en = registerB clk rst en (8::Int,8::Int)
-}


-- | Create a 'register' function for product-type like signals (e.g.
-- @('Signal' a, 'Signal' b)@)
--
-- @
-- rP :: Clock dom -> Reset dom -> Enable dom
--    -> ('Signal' dom Int, 'Signal' dom Int)
--    -> ('Signal' dom Int, 'Signal' dom Int)
-- rP clk rst en = 'registerB' clk rst en (8,8)
-- @
--
-- >>> simulateB (rP systemClockGen systemResetGen enableGen) [(1,1),(1,1),(2,2),(3,3)] :: [(Int,Int)]
-- [(8,8),(8,8),(1,1),(2,2),(3,3)...
-- ...
registerB
  :: ( KnownDomain dom
     , NFDataX a
     , Bundle a )
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> a
  -> Unbundled dom a
  -> Unbundled dom a
registerB :: Clock dom
-> Reset dom
-> Enable dom
-> a
-> Unbundled dom a
-> Unbundled dom a
registerB Clock dom
clk Reset dom
rst Enable dom
en a
i =
  Signal dom a -> Unbundled dom a
forall a (dom :: Domain).
Bundle a =>
Signal dom a -> Unbundled dom a
unbundle (Signal dom a -> Unbundled dom a)
-> (Unbundled dom a -> Signal dom a)
-> Unbundled dom a
-> Unbundled dom a
forall b c a. (b -> c) -> (a -> b) -> a -> c
Prelude.. 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
en a
i (Signal dom a -> Signal dom a)
-> (Unbundled dom a -> Signal dom a)
-> Unbundled dom a
-> Signal dom a
forall b c a. (b -> c) -> (a -> b) -> a -> c
Prelude.. Unbundled dom a -> Signal dom a
forall a (dom :: Domain).
Bundle a =>
Unbundled dom a -> Signal dom a
bundle
{-# INLINE registerB #-}

-- | Give a pulse when the 'Signal' goes from 'minBound' to 'maxBound'
isRising
  :: ( KnownDomain dom
     , NFDataX a
     , Bounded a
     , Eq a )
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> a -- ^ Starting value
  -> Signal dom a
  -> Signal dom Bool
isRising :: Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom Bool
isRising Clock dom
clk Reset dom
rst Enable dom
en a
is Signal dom a
s = (a -> a -> Bool) -> Signal dom a -> Signal dom a -> Signal dom Bool
forall (f :: Type -> Type) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 a -> a -> Bool
forall a a. (Eq a, Eq a, Bounded a, Bounded a) => a -> a -> Bool
edgeDetect Signal dom a
prev Signal dom a
s
  where
    prev :: Signal dom a
prev = 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
en a
is Signal dom a
s
    edgeDetect :: a -> a -> Bool
edgeDetect a
old a
new = a
old a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
forall a. Bounded a => a
minBound Bool -> Bool -> Bool
&& a
new a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
forall a. Bounded a => a
maxBound
{-# INLINABLE isRising #-}

-- | Give a pulse when the 'Signal' goes from 'maxBound' to 'minBound'
isFalling
  :: ( KnownDomain dom
     , NFDataX a
     , Bounded a
     , Eq a )
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> a -- ^ Starting value
  -> Signal dom a
  -> Signal dom Bool
isFalling :: Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom Bool
isFalling Clock dom
clk Reset dom
rst Enable dom
en a
is Signal dom a
s = (a -> a -> Bool) -> Signal dom a -> Signal dom a -> Signal dom Bool
forall (f :: Type -> Type) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 a -> a -> Bool
forall a a. (Eq a, Eq a, Bounded a, Bounded a) => a -> a -> Bool
edgeDetect Signal dom a
prev Signal dom a
s
  where
    prev :: Signal dom a
prev = 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
en a
is Signal dom a
s
    edgeDetect :: a -> a -> Bool
edgeDetect a
old a
new = a
old a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
forall a. Bounded a => a
maxBound Bool -> Bool -> Bool
&& a
new a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
forall a. Bounded a => a
minBound
{-# INLINABLE isFalling #-}

-- | Give a pulse every @n@ clock cycles. This is a useful helper function when
-- combined with functions like @'Clash.Explicit.Signal.regEn'@ or
-- @'Clash.Explicit.Signal.mux'@, in order to delay a register by a known amount.
riseEvery
  :: forall dom  n
   . KnownDomain dom
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> SNat n
  -> Signal dom Bool
riseEvery :: Clock dom -> Reset dom -> Enable dom -> SNat n -> Signal dom Bool
riseEvery Clock dom
clk Reset dom
rst Enable dom
en SNat n
SNat = Clock dom
-> Reset dom
-> Enable dom
-> (Index n -> () -> Index n)
-> (Index n -> Bool)
-> Index n
-> Signal dom ()
-> Signal dom Bool
forall (dom :: Domain) s i o.
(KnownDomain dom, NFDataX s) =>
Clock dom
-> Reset dom
-> Enable dom
-> (s -> i -> s)
-> (s -> o)
-> s
-> Signal dom i
-> Signal dom o
moore Clock dom
clk Reset dom
rst Enable dom
en Index n -> () -> Index n
transfer Index n -> Bool
output Index n
0 (() -> Signal dom ()
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ())
  where
    output :: Index n -> Bool
    output :: Index n -> Bool
output = (Index n -> Index n -> Bool
forall a. Eq a => a -> a -> Bool
== Index n
forall a. Bounded a => a
maxBound)

    transfer :: Index n -> () -> Index n
    transfer :: Index n -> () -> Index n
transfer Index n
s ()
_ = if (Index n
s Index n -> Index n -> Bool
forall a. Eq a => a -> a -> Bool
== Index n
forall a. Bounded a => a
maxBound) then Index n
0 else Index n
sIndex n -> Index n -> Index n
forall a. Num a => a -> a -> a
+Index n
1
{-# INLINEABLE riseEvery #-}

-- | Oscillate a @'Bool'@ for a given number of cycles, given the starting state.
oscillate
  :: forall dom  n
   . KnownDomain dom
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> Bool
  -> SNat n
  -> Signal dom Bool
oscillate :: Clock dom
-> Reset dom -> Enable dom -> Bool -> SNat n -> Signal dom Bool
oscillate Clock dom
clk Reset dom
rst Enable dom
en Bool
begin SNat n
SNat =
  Clock dom
-> Reset dom
-> Enable dom
-> ((Index n, Bool) -> () -> (Index n, Bool))
-> ((Index n, Bool) -> Bool)
-> (Index n, Bool)
-> Signal dom ()
-> Signal dom Bool
forall (dom :: Domain) s i o.
(KnownDomain dom, NFDataX s) =>
Clock dom
-> Reset dom
-> Enable dom
-> (s -> i -> s)
-> (s -> o)
-> s
-> Signal dom i
-> Signal dom o
moore Clock dom
clk Reset dom
rst Enable dom
en (Index n, Bool) -> () -> (Index n, Bool)
transfer (Index n, Bool) -> Bool
forall a b. (a, b) -> b
snd (Index n
0, Bool
begin) (() -> Signal dom ()
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ())
 where
  transfer :: (Index n, Bool) -> () -> (Index n, Bool)
  transfer :: (Index n, Bool) -> () -> (Index n, Bool)
transfer (Index n
s, Bool
i) ()
_ =
    if Index n
s Index n -> Index n -> Bool
forall a. Eq a => a -> a -> Bool
== Index n
forall a. Bounded a => a
maxBound
      then (Index n
0,   Bool -> Bool
not Bool
i) -- reset state and oscillate output
      else (Index n
sIndex n -> Index n -> Index n
forall a. Num a => a -> a -> a
+Index n
1, Bool
i)     -- hold current output
{-# INLINEABLE oscillate #-}