content: {-|
  Copyright  :  (C) 2013-2016, University of Twente,
                    2017     , Google Inc.
                    2019     , Myrtle Software Ltd,
                    2021-2022, QBayLogic B.V.
  License    :  BSD2 (see the file LICENSE)
  Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>
  
  __This is the <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/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 CPP #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE NoGeneralizedNewtypeDeriving #-}
  {-# 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
      -- ** ROMs defined by a 'MemBlob'
    , asyncRomBlob
    , asyncRomBlobPow2
    , romBlob
    , romBlobPow2
      -- * RAM primitives with a combinational read port
    , asyncRam
    , asyncRamPow2
      -- * Block RAM primitives
    , blockRam
    , blockRamPow2
      -- ** Block RAM primitives initialized with a 'MemBlob'
    , blockRamBlob
    , blockRamBlobPow2
      -- *** Creating and inspecting 'MemBlob'
    , MemBlob
    , createMemBlob
    , memBlobTH
    , unpackMemBlob
      -- ** Block RAM read/write conflict resolution
    , readNew
      -- ** True dual-port block RAM
    , trueDualPortBlockRam
    , RamOp(..)
      -- * 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
      -- *** 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
  #if MIN_VERSION_base(4,18,0)
    hiding (SNat, SSymbol, fromSNat)
  #endif
  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.BlockRam.Blob
  import Clash.Explicit.Mealy
  import Clash.Explicit.Moore
  import Clash.Explicit.RAM
  import Clash.Explicit.ROM
  import Clash.Explicit.ROM.Blob
  import Clash.Explicit.Signal
  import Clash.Explicit.Signal.Delayed
  import Clash.Explicit.Synchronizer
    (dualFlipFlopSynchronizer, asyncFIFOSynchronizer)
  import Clash.Prelude.ROM.Blob (asyncRomBlob, asyncRomBlobPow2)
  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 -Prelude
  >>> import Clash.Explicit.Prelude.Safe
  >>> let rP clk rst en = registerB clk rst en (8::Int,8::Int)
  -}
  
  {- $hiding
  "Clash.Explicit.Prelude.Safe" re-exports most of the Haskell "Prelude" with the
  exception of those functions that the Clash API defines to work on 'Vec' from
  "Clash.Sized.Vector" instead of on lists as the Haskell Prelude does. In
  addition, for the 'Clash.Class.Parity.odd' and 'Clash.Class.Parity.even'
  functions a type class called 'Clash.Class.Parity.Parity' is available at
  "Clash.Class.Parity".
  -}
  
  -- | 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 clk rst en i =
    unbundle Prelude.. register clk rst en i Prelude.. 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 clk rst en is s = liftA2 edgeDetect prev s
    where
      prev = register clk rst en is s
      edgeDetect old new = old == minBound && new == 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 clk rst en is s = liftA2 edgeDetect prev s
    where
      prev = register clk rst en is s
      edgeDetect old new = old == maxBound && new == 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 clk rst en SNat = moore clk rst en transfer output 0 (pure ())
    where
      output :: Index n -> Bool
      output = (== maxBound)
  
      transfer :: Index n -> () -> Index n
      transfer s _ = if (s == maxBound) then 0 else s+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 clk rst en begin SNat =
    moore clk rst en transfer snd (0, begin) (pure ())
   where
    transfer :: (Index n, Bool) -> () -> (Index n, Bool)
    transfer (s, i) _ =
      if s == maxBound
        then (0,   not i) -- reset state and oscillate output
        else (s+1, i)     -- hold current output
  {-# INLINEABLE oscillate #-}
  