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

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

    {-# LANGUAGE CPP #-}
    {-# LANGUAGE NoImplicitPrelude #-}

    {-# LANGUAGE Unsafe #-}

    {-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}
    {-# OPTIONS_HADDOCK show-extensions, not-home #-}

    module Clash.Explicit.Prelude
      ( -- * Creating synchronous sequential circuits
        mealy
      , mealyS
      , mealyB
      , mealySB
      , moore
      , mooreB
      , registerB
        -- * Synchronizer circuits for safe clock domain crossings
      , dualFlipFlopSynchronizer
      , asyncFIFOSynchronizer
        -- * ROMs
      , asyncRom
      , asyncRomPow2
      , rom
      , romPow2
        -- ** ROMs defined by a 'MemBlob'
      , asyncRomBlob
      , asyncRomBlobPow2
      , romBlob
      , romBlobPow2
        -- ** ROMs defined by a data file
      , asyncRomFile
      , asyncRomFilePow2
      , romFile
      , romFilePow2
        -- * RAM primitives with a combinational read port
      , asyncRam
      , asyncRamPow2
        -- * Block RAM primitives
      , blockRam
      , blockRamPow2
      , blockRamU
      , blockRam1
      , ResetStrategy(..)
        -- ** Block RAM primitives initialized with a 'MemBlob'
      , blockRamBlob
      , blockRamBlobPow2
        -- *** Creating and inspecting 'MemBlob'
      , MemBlob
      , createMemBlob
      , memBlobTH
      , unpackMemBlob
        -- ** Block RAM primitives initialized with a data file
      , blockRamFile
      , blockRamFilePow2
      -- ** Block RAM read/write conflict resolution
      , readNew
        -- ** True dual-port block RAM
      , trueDualPortBlockRam
      , RamOp(..)
        -- * Utility functions
      , window
      , windowD
      , isRising
      , isFalling
      , riseEvery
      , oscillate
        -- * Testbench functions
      , assert
      , stimuliGenerator
      , outputVerifier'
        -- * Tracing
        -- ** Simple
      , traceSignal1
      , traceVecSignal1
        -- ** Tracing in a multi-clock environment
      , traceSignal
      , traceVecSignal
        -- ** VCD dump functions
      , dumpVCD
        -- * Exported modules
        -- ** Synchronous signals
      , module Clash.Explicit.Reset
      , 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
        -- ** Template Haskell
      , Lift (..)
        -- ** Type classes
        -- *** Clash
      , module Clash.Class.AutoReg
      , module Clash.Class.BitPack
      , module Clash.Class.Exp
      , module Clash.Class.Num
      , module Clash.Class.Resize
        -- *** Other
      , module Control.Applicative
      , module Data.Bits
      , module Data.Default.Class
        -- ** Exceptions
      , module Clash.XException
        -- ** Named types
      , module Clash.NamedTypes
        -- ** Magic
      , module Clash.Magic
        -- ** Haskell Prelude
        -- $hiding
      , module Clash.HaskellPrelude
      )
    where

    import Control.Applicative
    import Data.Bits
    import Data.Default.Class
    import GHC.TypeLits
    #if MIN_VERSION_base(4,18,0)
      hiding (SNat, SSymbol, fromSNat)
    #endif
    import GHC.TypeLits.Extra
    import Language.Haskell.TH.Syntax  (Lift(..))
    import Clash.HaskellPrelude

    import Clash.Annotations.TopEntity
    import Clash.Class.AutoReg
    import Clash.Class.BitPack
    import Clash.Class.Exp
    import Clash.Class.Num
    import Clash.Class.Resize
    import Clash.Magic
    import Clash.NamedTypes
    import Clash.Explicit.BlockRam
    import Clash.Explicit.BlockRam.Blob
    import Clash.Explicit.BlockRam.File
    import Clash.Explicit.Mealy
    import Clash.Explicit.Moore
    import Clash.Explicit.RAM
    import Clash.Explicit.ROM
    import Clash.Explicit.ROM.Blob
    import Clash.Explicit.ROM.File
    import Clash.Explicit.Prelude.Safe
    import Clash.Explicit.Reset
    import Clash.Explicit.Signal
    import Clash.Explicit.Signal.Delayed
    import Clash.Explicit.Testbench
    import Clash.Prelude.ROM.File       (asyncRomFile, asyncRomFilePow2)
    import Clash.Promoted.Nat
    import Clash.Promoted.Nat.TH
    import Clash.Promoted.Nat.Literals
    import Clash.Promoted.Symbol
    import Clash.Signal.Trace
    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 -XTypeApplications
    >>> import Clash.Explicit.Prelude
    >>> let window4 = window @3
    >>> let windowD3 = windowD @2
    -}

    {- $hiding
    "Clash.Explicit.Prelude" 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".
    -}

    -- | Give a window over a 'Signal'
    --
    -- @
    -- window4
    ---  :: Clock dom
    --   -> Reset dom
    --   -> Enable dom
    --   -> 'Signal' dom Int
    --   -> 'Vec' 4 ('Signal' dom Int)
    -- window4 = 'window'
    -- @
    --
    -- >>> simulateB (window4 systemClockGen systemResetGen enableGen) [1::Int,2,3,4,5] :: [Vec 4 Int]
    -- [1 :> 0 :> 0 :> 0 :> Nil,2 :> 1 :> 0 :> 0 :> Nil,3 :> 2 :> 1 :> 0 :> Nil,4 :> 3 :> 2 :> 1 :> Nil,5 :> 4 :> 3 :> 2 :> Nil,...
    -- ...
    window
      :: ( KnownNat n
         , KnownDomain dom
         , NFDataX a
         , Default a
         )
      => Clock dom
      -- ^ Clock to the incoming signal is synchronized
      -> Reset dom
      -> Enable dom
      -> Signal dom a
      -- ^ Signal to create a window over
      -> Vec (n + 1) (Signal dom a)
      -- ^ Window of at least size 1
    window :: forall (n :: Nat) (dom :: Domain) a.
    (KnownNat n, KnownDomain dom, NFDataX a, Default a) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> Signal dom a
    -> Vec (n + 1) (Signal dom a)
    window Clock dom
    clk Reset dom
    rst Enable dom
    en Signal dom a
    x = Vec (n + 1) (Signal dom a)
    res
      where
        res :: Vec (n + 1) (Signal dom a)
    res  = Signal dom a
    x Signal dom a -> Vec n (Signal dom a) -> Vec (n + 1) (Signal dom a)
    forall a (n :: Nat). a -> Vec n a -> Vec (n + 1) a
    :> Vec n (Signal dom a)
    prev
        prev :: Vec n (Signal dom a)
    prev = case Proxy n -> Integer
    forall (n :: Nat) (proxy :: Nat -> Type).
    KnownNat n =>
    proxy n -> Integer
    natVal (Vec n (Signal dom a) -> Proxy n
    forall (n :: Nat) a. Vec n a -> Proxy n
    asNatProxy Vec n (Signal dom a)
    prev) of
                 Integer
    0 -> Signal dom a -> Vec n (Signal dom a)
    forall (n :: Nat) a. KnownNat n => a -> Vec n a
    repeat Signal dom a
    forall a. Default a => a
    def
                 Integer
    _ -> let next :: Vec n (Signal dom a)
    next = Signal dom a
    x Signal dom a -> Vec n (Signal dom a) -> Vec n (Signal dom a)
    forall (n :: Nat) a. KnownNat n => a -> Vec n a -> Vec n a
    +>> Vec n (Signal dom a)
    prev
                      in  Clock dom
    -> Reset dom
    -> Enable dom
    -> Vec n a
    -> Unbundled dom (Vec n a)
    -> Unbundled dom (Vec n a)
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a, Bundle a) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> Unbundled dom a
    -> Unbundled dom a
    registerB Clock dom
    clk Reset dom
    rst Enable dom
    en (a -> Vec n a
    forall (n :: Nat) a. KnownNat n => a -> Vec n a
    repeat a
    forall a. Default a => a
    def) Vec n (Signal dom a)
    Unbundled dom (Vec n a)
    next
    {-# INLINABLE window #-}

    -- | Give a delayed window over a 'Signal'
    --
    -- @
    -- windowD3
    --   :: KnownDomain dom
    --   -> Clock dom
    --   -> Enable dom
    --   -> Reset dom
    --   -> 'Signal' dom Int
    --   -> 'Vec' 3 ('Signal' dom Int)
    -- windowD3 = 'windowD'
    -- @
    --
    -- >>> simulateB (windowD3 systemClockGen resetGen enableGen) [1::Int,1,2,3,4] :: [Vec 3 Int]
    -- [0 :> 0 :> 0 :> Nil,0 :> 0 :> 0 :> Nil,1 :> 0 :> 0 :> Nil,2 :> 1 :> 0 :> Nil,3 :> 2 :> 1 :> Nil,4 :> 3 :> 2 :> Nil,...
    -- ...
    windowD
      :: ( KnownNat n
         , NFDataX a
         , Default a
         , KnownDomain dom )
      => Clock dom
      -- ^ Clock to which the incoming signal is synchronized
      -> Reset dom
      -> Enable dom
      -> Signal dom a
      -- ^ Signal to create a window over
      -> Vec (n + 1) (Signal dom a)
      -- ^ Window of at least size 1
    windowD :: forall (n :: Nat) a (dom :: Domain).
    (KnownNat n, NFDataX a, Default a, KnownDomain dom) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> Signal dom a
    -> Vec (n + 1) (Signal dom a)
    windowD Clock dom
    clk Reset dom
    rst Enable dom
    en Signal dom a
    x =
      let prev :: Vec (n + 1) (Signal dom a)
    prev = Clock dom
    -> Reset dom
    -> Enable dom
    -> Vec (n + 1) a
    -> Unbundled dom (Vec (n + 1) a)
    -> Unbundled dom (Vec (n + 1) a)
    forall (dom :: Domain) a.
    (KnownDomain dom, NFDataX a, Bundle a) =>
    Clock dom
    -> Reset dom
    -> Enable dom
    -> a
    -> Unbundled dom a
    -> Unbundled dom a
    registerB Clock dom
    clk Reset dom
    rst Enable dom
    en (a -> Vec (n + 1) a
    forall (n :: Nat) a. KnownNat n => a -> Vec n a
    repeat a
    forall a. Default a => a
    def) Vec (n + 1) (Signal dom a)
    Unbundled dom (Vec (n + 1) a)
    next
          next :: Vec (n + 1) (Signal dom a)
    next = Signal dom a
    x Signal dom a
    -> Vec (n + 1) (Signal dom a) -> Vec (n + 1) (Signal dom a)
    forall (n :: Nat) a. KnownNat n => a -> Vec n a -> Vec n a
    +>> Vec (n + 1) (Signal dom a)
    prev
      in  Vec (n + 1) (Signal dom a)
    prev
    {-# INLINABLE windowD #-}