    {-|
    Copyright  :  (C) 2017, Google Inc
                      2019, Myrtle Software Ltd
                      2025, QBayLogic B.V.
    License    :  BSD2 (see the file LICENSE)
    Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>

    DDR primitives for Intel FPGAs using ALTDDIO primitives.

    For general information about DDR primitives see "Clash.Explicit.DDR".

    Note that a reset is only available on certain devices,
    see the ALTDDIO user guide for the specifics:
    <https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ug/ug_altddio.pdf>
    -}

    {-# LANGUAGE CPP #-}
    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE TypeFamilies #-}

    module Clash.Intel.DDR
      ( altddioIn
      , altddioOut
      )
    where

    import GHC.Stack (HasCallStack, withFrozenCallStack)

    import Clash.Annotations.Primitive (hasBlackBox)
    import Clash.Explicit.Prelude
    import Clash.Explicit.DDR

    -- | Intel specific variant of 'ddrIn' implemented using the ALTDDIO_IN IP core.
    --
    -- Reset values are @0@
    --
    -- Of the output pair @(o0, o1)@, @o0@ is the data clocked in on the /falling/
    -- edge and @o1@ is the data clocked in on the /rising/ edge, and @o0@ comes
    -- before @o1@ in time.
    --
    -- __NB__: This primitive only supports rising edges as the active edge. Trying
    -- to instantiate this function in a domain where falling edges are the active
    -- edge will lead to a HDL generation or Haskell simulation error.
    altddioIn
      :: forall fast fPeriod edge reset init polarity slow m deviceFamily
       . ( HasCallStack
         , KnownConfiguration fast ('DomainConfiguration fast fPeriod edge reset init polarity)
         , KnownConfiguration slow ('DomainConfiguration slow (2*fPeriod) edge reset init polarity)
         , KnownNat m )
      => SSymbol deviceFamily
      -- ^ The FPGA family
      --
      -- For example this can be instantiated as follows:
      --
      -- > SSymbol @"Cyclone IV GX"
      -> Clock slow
      -> Reset slow
      -> Enable slow
      -> Signal fast (BitVector m)
      -- ^ DDR input signal
      -> Signal slow (BitVector m,BitVector m)
      -- ^ Normal speed output pair @(o0, o1)@
    altddioIn :: forall (fast :: Domain) (fPeriod :: Nat) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior)
           (polarity :: ResetPolarity) (slow :: Domain) (m :: Nat)
           (deviceFamily :: Domain).
    (HasCallStack,
     KnownConfiguration
       fast ('DomainConfiguration fast fPeriod edge reset init polarity),
     KnownConfiguration
       slow
       ('DomainConfiguration slow (2 * fPeriod) edge reset init polarity),
     KnownNat m) =>
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    altddioIn =
      case forall (dom :: Domain) (edge :: ActiveEdge).
    (KnownDomain dom, DomainActiveEdge dom ~ edge) =>
    SActiveEdge edge
    activeEdge @slow of
        SActiveEdge edge
    SRising ->
          (HasCallStack =>
     SSymbol deviceFamily
     -> Clock slow
     -> Reset slow
     -> Enable slow
     -> Signal fast (BitVector m)
     -> Signal slow (BitVector m, BitVector m))
    -> SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    forall a. HasCallStack => (HasCallStack => a) -> a
    withFrozenCallStack HasCallStack =>
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    forall (fast :: Domain) (fPeriod :: Nat) (reset :: ResetKind)
           (init :: InitBehavior) (polarity :: ResetPolarity) (slow :: Domain)
           (m :: Nat) (deviceFamily :: Domain).
    (HasCallStack,
     KnownConfiguration
       fast
       ('DomainConfiguration fast fPeriod 'Rising reset init polarity),
     KnownConfiguration
       slow
       ('DomainConfiguration
          slow (2 * fPeriod) 'Rising reset init polarity),
     KnownNat m) =>
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    altddioIn#
        SActiveEdge edge
    SFalling ->
          String
    -> SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    forall a. HasCallStack => String -> a
    clashCompileError
            String
    "altddioIn: Primitive only supports rising active edge"

    altddioIn#
      :: ( HasCallStack
         , KnownConfiguration fast ('DomainConfiguration fast fPeriod 'Rising reset init polarity)
         , KnownConfiguration slow ('DomainConfiguration slow (2*fPeriod) 'Rising reset init polarity)
         , KnownNat m )
      => SSymbol deviceFamily
      -> Clock slow
      -> Reset slow
      -> Enable slow
      -> Signal fast (BitVector m)
      -> Signal slow (BitVector m,BitVector m)
    altddioIn# :: forall (fast :: Domain) (fPeriod :: Nat) (reset :: ResetKind)
           (init :: InitBehavior) (polarity :: ResetPolarity) (slow :: Domain)
           (m :: Nat) (deviceFamily :: Domain).
    (HasCallStack,
     KnownConfiguration
       fast
       ('DomainConfiguration fast fPeriod 'Rising reset init polarity),
     KnownConfiguration
       slow
       ('DomainConfiguration
          slow (2 * fPeriod) 'Rising reset init polarity),
     KnownNat m) =>
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    altddioIn# SSymbol deviceFamily
    SSymbol Clock slow
    clk Reset slow
    rst Enable slow
    en = (HasCallStack =>
     Clock slow
     -> Reset slow
     -> Enable slow
     -> BitVector m
     -> BitVector m
     -> BitVector m
     -> Signal fast (BitVector m)
     -> Signal slow (BitVector m, BitVector m))
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> BitVector m
    -> BitVector m
    -> BitVector m
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    forall a. HasCallStack => (HasCallStack => a) -> a
    withFrozenCallStack HasCallStack =>
    Clock slow
    -> Reset slow
    -> Enable slow
    -> BitVector m
    -> BitVector m
    -> BitVector m
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    Clock slow
    -> Reset slow
    -> Enable slow
    -> BitVector m
    -> BitVector m
    -> BitVector m
    -> Signal fast (BitVector m)
    -> Signal slow (BitVector m, BitVector m)
    forall a (slow :: Domain) (fast :: Domain) (fPeriod :: Nat)
           (polarity :: ResetPolarity) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior).
    (HasCallStack, NFDataX a,
     KnownConfiguration
       fast ('DomainConfiguration fast fPeriod edge reset init polarity),
     KnownConfiguration
       slow
       ('DomainConfiguration
          slow (2 * fPeriod) edge reset init polarity)) =>
    Clock slow
    -> Reset slow
    -> Enable slow
    -> a
    -> a
    -> a
    -> Signal fast a
    -> Signal slow (a, a)
    ddrIn# Clock slow
    clk Reset slow
    rst Enable slow
    en BitVector m
    0 BitVector m
    0 BitVector m
    0
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE altddioIn# #-}
    {-# ANN altddioIn# hasBlackBox #-}

    -- | Intel specific variant of 'ddrOut' implemented using the ALTDDIO_OUT IP core.
    --
    -- Reset value is @0@
    --
    -- Of the input pair @(i0, i1)@, @i0@ is the data clocked out on the /rising/
    -- edge and @i1@ is the data clocked out on the /falling/ edge, and @i0@ comes
    -- before @i1@ in time.
    --
    -- __NB__: This primitive only supports rising edges as the active edge. Trying
    -- to instantiate this function in a domain where falling edges are the active
    -- edge will lead to a HDL generation or Haskell simulation error.
    altddioOut
      :: forall fast fPeriod edge reset init polarity slow m deviceFamily
       . ( HasCallStack
         , KnownConfiguration fast ('DomainConfiguration fast fPeriod edge reset init polarity)
         , KnownConfiguration slow ('DomainConfiguration slow (2*fPeriod) edge reset init polarity)
         , KnownNat m )
      => SSymbol deviceFamily
      -- ^ The FPGA family
      --
      -- For example this can be instantiated as follows:
      --
      -- > SSymbol @"Cyclone IV E"
      -> Clock slow
      -> Reset slow
      -> Enable slow
      -> Signal slow (BitVector m,BitVector m)
      -- ^ Normal speed input pair @(i0, i1)@
      -> Signal fast (BitVector m)
      -- ^ DDR output signal
    altddioOut :: forall (fast :: Domain) (fPeriod :: Nat) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior)
           (polarity :: ResetPolarity) (slow :: Domain) (m :: Nat)
           (deviceFamily :: Domain).
    (HasCallStack,
     KnownConfiguration
       fast ('DomainConfiguration fast fPeriod edge reset init polarity),
     KnownConfiguration
       slow
       ('DomainConfiguration slow (2 * fPeriod) edge reset init polarity),
     KnownNat m) =>
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal slow (BitVector m, BitVector m)
    -> Signal fast (BitVector m)
    altddioOut SSymbol deviceFamily
    devFam Clock slow
    clk Reset slow
    rst Enable slow
    en =
      case forall (dom :: Domain) (edge :: ActiveEdge).
    (KnownDomain dom, DomainActiveEdge dom ~ edge) =>
    SActiveEdge edge
    activeEdge @slow of
        SActiveEdge edge
    SRising ->
          (Signal slow (BitVector m)
     -> Signal slow (BitVector m) -> Signal fast (BitVector m))
    -> (Signal slow (BitVector m), Signal slow (BitVector m))
    -> Signal fast (BitVector m)
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry ((HasCallStack =>
     SSymbol deviceFamily
     -> Clock slow
     -> Reset slow
     -> Enable slow
     -> Signal slow (BitVector m)
     -> Signal slow (BitVector m)
     -> Signal fast (BitVector m))
    -> SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal slow (BitVector m)
    -> Signal slow (BitVector m)
    -> Signal fast (BitVector m)
    forall a. HasCallStack => (HasCallStack => a) -> a
    withFrozenCallStack HasCallStack =>
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal slow (BitVector m)
    -> Signal slow (BitVector m)
    -> Signal fast (BitVector m)
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal slow (BitVector m)
    -> Signal slow (BitVector m)
    -> Signal fast (BitVector m)
    forall (fast :: Domain) (fPeriod :: Nat) (reset :: ResetKind)
           (init :: InitBehavior) (polarity :: ResetPolarity) (slow :: Domain)
           (m :: Nat) (deviceFamily :: Domain).
    (HasCallStack,
     KnownConfiguration
       fast
       ('DomainConfiguration fast fPeriod 'Rising reset init polarity),
     KnownConfiguration
       slow
       ('DomainConfiguration
          slow (2 * fPeriod) 'Rising reset init polarity),
     KnownNat m) =>
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal slow (BitVector m)
    -> Signal slow (BitVector m)
    -> Signal fast (BitVector m)
    altddioOut# SSymbol deviceFamily
    devFam Clock slow
    clk Reset slow
    rst Enable slow
    en) ((Signal slow (BitVector m), Signal slow (BitVector m))
     -> Signal fast (BitVector m))
    -> (Signal slow (BitVector m, BitVector m)
        -> (Signal slow (BitVector m), Signal slow (BitVector m)))
    -> Signal slow (BitVector m, BitVector m)
    -> Signal fast (BitVector m)
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Signal slow (BitVector m, BitVector m)
    -> (Signal slow (BitVector m), Signal slow (BitVector m))
    Signal slow (BitVector m, BitVector m)
    -> Unbundled slow (BitVector m, BitVector m)
    forall a (dom :: Domain).
    Bundle a =>
    Signal dom a -> Unbundled dom a
    forall (dom :: Domain).
    Signal dom (BitVector m, BitVector m)
    -> Unbundled dom (BitVector m, BitVector m)
    unbundle
        SActiveEdge edge
    SFalling ->
          String
    -> Signal slow (BitVector m, BitVector m)
    -> Signal fast (BitVector m)
    forall a. HasCallStack => String -> a
    clashCompileError
            String
    "altddioOut: Primitive only supports rising active edge"

    altddioOut#
      :: ( HasCallStack
         , KnownConfiguration fast ('DomainConfiguration fast fPeriod 'Rising reset init polarity)
         , KnownConfiguration slow ('DomainConfiguration slow (2*fPeriod) 'Rising reset init polarity)
         , KnownNat m )
      => SSymbol deviceFamily
      -> Clock slow
      -> Reset slow
      -> Enable slow
      -> Signal slow (BitVector m)
      -> Signal slow (BitVector m)
      -> Signal fast (BitVector m)
    altddioOut# :: forall (fast :: Domain) (fPeriod :: Nat) (reset :: ResetKind)
           (init :: InitBehavior) (polarity :: ResetPolarity) (slow :: Domain)
           (m :: Nat) (deviceFamily :: Domain).
    (HasCallStack,
     KnownConfiguration
       fast
       ('DomainConfiguration fast fPeriod 'Rising reset init polarity),
     KnownConfiguration
       slow
       ('DomainConfiguration
          slow (2 * fPeriod) 'Rising reset init polarity),
     KnownNat m) =>
    SSymbol deviceFamily
    -> Clock slow
    -> Reset slow
    -> Enable slow
    -> Signal slow (BitVector m)
    -> Signal slow (BitVector m)
    -> Signal fast (BitVector m)
    altddioOut# SSymbol deviceFamily
    SSymbol Clock slow
    clk Reset slow
    rst Enable slow
    en = Clock slow
    -> Reset slow
    -> Enable slow
    -> BitVector m
    -> Signal slow (BitVector m)
    -> Signal slow (BitVector m)
    -> Signal fast (BitVector m)
    forall a (fast :: Domain) (fPeriod :: Nat) (edge :: ActiveEdge)
           (reset :: ResetKind) (init :: InitBehavior)
           (polarity :: ResetPolarity) (slow :: Domain).
    (HasCallStack, NFDataX a,
     KnownConfiguration
       fast ('DomainConfiguration fast fPeriod edge reset init polarity),
     KnownConfiguration
       slow
       ('DomainConfiguration
          slow (2 * fPeriod) edge reset init polarity)) =>
    Clock slow
    -> Reset slow
    -> Enable slow
    -> a
    -> Signal slow a
    -> Signal slow a
    -> Signal fast a
    ddrOut# Clock slow
    clk Reset slow
    rst Enable slow
    en BitVector m
    0
    -- See: https://github.com/clash-lang/clash-compiler/pull/2511
    {-# CLASH_OPAQUE altddioOut# #-}
    {-# ANN altddioOut# hasBlackBox #-}