{-|
Copyright  :  (C) 2017, Google Inc
License    :  BSD2 (see the file LICENSE)
Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>

DDR primitives for Xilinx FPGAs

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

For more information about the Xilinx DDR primitives see:

* Vivado Design Suite 7 Series FPGA and Zynq-7000 All Programmable SoC
  Libraries Guide, UG953 (v2022.2) October 19, 2022, p369-371, p477-479,
  <https://www.xilinx.com/content/dam/xilinx/support/documents/sw_manuals/xilinx2022_2/ug953-vivado-7series-libraries.pdf>
-}

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

module Clash.Xilinx.DDR
  ( iddr
  , oddr
    -- * Internal
  , iddr#
  , oddr#
  )
where

import Data.Bifunctor
import GHC.Stack (HasCallStack, withFrozenCallStack)

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

-- | Xilinx specific variant of 'ddrIn' implemented using the Xilinx IDDR
-- primitive in @SAME_EDGE@ mode.
--
-- 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.
iddr
  :: forall a dom domDDR
   . HasCallStack
  => KnownDomain dom
  => KnownDomain domDDR
  => DomainPeriod dom ~ (2 * DomainPeriod domDDR)
  => DomainActiveEdge dom ~ 'Rising
  => BitPack a
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> Signal domDDR a
  -- ^ DDR input signal
  -> Signal dom (a, a)
  -- ^ Normal speed output pair @(o0, o1)@
iddr :: forall a (dom :: Domain) (domDDR :: Domain).
(HasCallStack, KnownDomain dom, KnownDomain domDDR,
 DomainPeriod dom ~ (2 * DomainPeriod domDDR),
 DomainActiveEdge dom ~ 'Rising, BitPack a) =>
Clock dom
-> Reset dom -> Enable dom -> Signal domDDR a -> Signal dom (a, a)
iddr Clock dom
clk Reset dom
rst Enable dom
en =
  ((BitVector (BitSize a), BitVector (BitSize a)) -> (a, a))
-> Signal dom (BitVector (BitSize a), BitVector (BitSize a))
-> Signal dom (a, a)
forall a b. (a -> b) -> Signal dom a -> Signal dom b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap ((BitVector (BitSize a) -> a)
-> (BitVector (BitSize a) -> a)
-> (BitVector (BitSize a), BitVector (BitSize a))
-> (a, a)
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: Type -> Type -> Type) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap BitVector (BitSize a) -> a
forall a. BitPack a => BitVector (BitSize a) -> a
unpack BitVector (BitSize a) -> a
forall a. BitPack a => BitVector (BitSize a) -> a
unpack) (Signal dom (BitVector (BitSize a), BitVector (BitSize a))
 -> Signal dom (a, a))
-> (Signal domDDR a
    -> Signal dom (BitVector (BitSize a), BitVector (BitSize a)))
-> Signal domDDR a
-> Signal dom (a, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (HasCallStack =>
 Signal domDDR (BitVector (BitSize a))
 -> Signal dom (BitVector (BitSize a), BitVector (BitSize a)))
-> Signal domDDR (BitVector (BitSize a))
-> Signal dom (BitVector (BitSize a), BitVector (BitSize a))
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack (Clock dom
-> Reset dom
-> Enable dom
-> Signal domDDR (BitVector (BitSize a))
-> Signal dom (BitVector (BitSize a), BitVector (BitSize a))
forall (n :: Nat) (dom :: Domain) (domDDR :: Domain).
(HasCallStack, KnownDomain dom, KnownDomain domDDR,
 DomainPeriod dom ~ (2 * DomainPeriod domDDR),
 DomainActiveEdge dom ~ 'Rising, KnownNat n) =>
Clock dom
-> Reset dom
-> Enable dom
-> Signal domDDR (BitVector n)
-> Signal dom (BitVector n, BitVector n)
iddr# Clock dom
clk Reset dom
rst Enable dom
en) (Signal domDDR (BitVector (BitSize a))
 -> Signal dom (BitVector (BitSize a), BitVector (BitSize a)))
-> (Signal domDDR a -> Signal domDDR (BitVector (BitSize a)))
-> Signal domDDR a
-> Signal dom (BitVector (BitSize a), BitVector (BitSize a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    (a -> BitVector (BitSize a))
-> Signal domDDR a -> Signal domDDR (BitVector (BitSize a))
forall a b. (a -> b) -> Signal domDDR a -> Signal domDDR b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> BitVector (BitSize a)
forall a. BitPack a => a -> BitVector (BitSize a)
pack

iddr#
  :: forall n dom domDDR
   . HasCallStack
  => KnownDomain dom
  => KnownDomain domDDR
  => DomainPeriod dom ~ (2 * DomainPeriod domDDR)
  => DomainActiveEdge dom ~ 'Rising
  => KnownNat n
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> Signal domDDR (BitVector n)
  -> Signal dom (BitVector n, BitVector n)
iddr# :: forall (n :: Nat) (dom :: Domain) (domDDR :: Domain).
(HasCallStack, KnownDomain dom, KnownDomain domDDR,
 DomainPeriod dom ~ (2 * DomainPeriod domDDR),
 DomainActiveEdge dom ~ 'Rising, KnownNat n) =>
Clock dom
-> Reset dom
-> Enable dom
-> Signal domDDR (BitVector n)
-> Signal dom (BitVector n, BitVector n)
iddr# Clock dom
clk Reset dom
rst Enable dom
en = (HasCallStack =>
 Clock dom
 -> Reset dom
 -> Enable dom
 -> BitVector n
 -> BitVector n
 -> BitVector n
 -> Signal domDDR (BitVector n)
 -> Signal dom (BitVector n, BitVector n))
-> Clock dom
-> Reset dom
-> Enable dom
-> BitVector n
-> BitVector n
-> BitVector n
-> Signal domDDR (BitVector n)
-> Signal dom (BitVector n, BitVector n)
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack HasCallStack =>
Clock dom
-> Reset dom
-> Enable dom
-> BitVector n
-> BitVector n
-> BitVector n
-> Signal domDDR (BitVector n)
-> Signal dom (BitVector n, BitVector n)
Clock dom
-> Reset dom
-> Enable dom
-> BitVector n
-> BitVector n
-> BitVector n
-> Signal domDDR (BitVector n)
-> Signal dom (BitVector n, BitVector n)
forall a (dom :: Domain) (domDDR :: Domain).
(HasCallStack, NFDataX a, KnownDomain dom, KnownDomain domDDR,
 DomainPeriod dom ~ (2 * DomainPeriod domDDR)) =>
Clock dom
-> Reset dom
-> Enable dom
-> a
-> a
-> a
-> Signal domDDR a
-> Signal dom (a, a)
ddrIn# Clock dom
clk Reset dom
rst Enable dom
en BitVector n
0 BitVector n
0 BitVector n
0
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE iddr# #-}
{-# ANN iddr# hasBlackBox #-}

-- | Xilinx specific variant of 'ddrOut' implemented using the Xilinx ODDR
-- primitive in @SAME_EDGE@ mode.
--
-- 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.
oddr
  :: forall a dom domDDR
   . HasCallStack
  => KnownDomain dom
  => KnownDomain domDDR
  => DomainPeriod dom ~ (2 * DomainPeriod domDDR)
  => DomainActiveEdge dom ~ 'Rising
  => BitPack a
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> Signal dom (a, a)
  -- ^ Normal speed input pair @(i0, i1)@
  -> Signal domDDR a
  -- ^ DDR output signal
oddr :: forall a (dom :: Domain) (domDDR :: Domain).
(HasCallStack, KnownDomain dom, KnownDomain domDDR,
 DomainPeriod dom ~ (2 * DomainPeriod domDDR),
 DomainActiveEdge dom ~ 'Rising, BitPack a) =>
Clock dom
-> Reset dom -> Enable dom -> Signal dom (a, a) -> Signal domDDR a
oddr Clock dom
clk Reset dom
rst Enable dom
en =
  (BitVector (BitSize a) -> a)
-> Signal domDDR (BitVector (BitSize a)) -> Signal domDDR a
forall a b. (a -> b) -> Signal domDDR a -> Signal domDDR b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap BitVector (BitSize a) -> a
forall a. BitPack a => BitVector (BitSize a) -> a
unpack (Signal domDDR (BitVector (BitSize a)) -> Signal domDDR a)
-> (Signal dom (a, a) -> Signal domDDR (BitVector (BitSize a)))
-> Signal dom (a, a)
-> Signal domDDR a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Signal dom (BitVector (BitSize a))
 -> Signal dom (BitVector (BitSize a))
 -> Signal domDDR (BitVector (BitSize a)))
-> (Signal dom (BitVector (BitSize a)),
    Signal dom (BitVector (BitSize a)))
-> Signal domDDR (BitVector (BitSize a))
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((HasCallStack =>
 Clock dom
 -> Reset dom
 -> Enable dom
 -> Signal dom (BitVector (BitSize a))
 -> Signal dom (BitVector (BitSize a))
 -> Signal domDDR (BitVector (BitSize a)))
-> Clock dom
-> Reset dom
-> Enable dom
-> Signal dom (BitVector (BitSize a))
-> Signal dom (BitVector (BitSize a))
-> Signal domDDR (BitVector (BitSize a))
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack HasCallStack =>
Clock dom
-> Reset dom
-> Enable dom
-> Signal dom (BitVector (BitSize a))
-> Signal dom (BitVector (BitSize a))
-> Signal domDDR (BitVector (BitSize a))
Clock dom
-> Reset dom
-> Enable dom
-> Signal dom (BitVector (BitSize a))
-> Signal dom (BitVector (BitSize a))
-> Signal domDDR (BitVector (BitSize a))
forall (n :: Nat) (dom :: Domain) (domDDR :: Domain).
(HasCallStack, KnownDomain dom, KnownDomain domDDR,
 DomainPeriod dom ~ (2 * DomainPeriod domDDR),
 DomainActiveEdge dom ~ 'Rising, KnownNat n) =>
Clock dom
-> Reset dom
-> Enable dom
-> Signal dom (BitVector n)
-> Signal dom (BitVector n)
-> Signal domDDR (BitVector n)
oddr# Clock dom
clk Reset dom
rst Enable dom
en) ((Signal dom (BitVector (BitSize a)),
  Signal dom (BitVector (BitSize a)))
 -> Signal domDDR (BitVector (BitSize a)))
-> (Signal dom (a, a)
    -> (Signal dom (BitVector (BitSize a)),
        Signal dom (BitVector (BitSize a))))
-> Signal dom (a, a)
-> Signal domDDR (BitVector (BitSize a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signal dom (BitVector (BitSize a), BitVector (BitSize a))
-> (Signal dom (BitVector (BitSize a)),
    Signal dom (BitVector (BitSize a)))
Signal dom (BitVector (BitSize a), BitVector (BitSize a))
-> Unbundled dom (BitVector (BitSize a), BitVector (BitSize a))
forall a (dom :: Domain).
Bundle a =>
Signal dom a -> Unbundled dom a
forall (dom :: Domain).
Signal dom (BitVector (BitSize a), BitVector (BitSize a))
-> Unbundled dom (BitVector (BitSize a), BitVector (BitSize a))
unbundle (Signal dom (BitVector (BitSize a), BitVector (BitSize a))
 -> (Signal dom (BitVector (BitSize a)),
     Signal dom (BitVector (BitSize a))))
-> (Signal dom (a, a)
    -> Signal dom (BitVector (BitSize a), BitVector (BitSize a)))
-> Signal dom (a, a)
-> (Signal dom (BitVector (BitSize a)),
    Signal dom (BitVector (BitSize a)))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
    ((a, a) -> (BitVector (BitSize a), BitVector (BitSize a)))
-> Signal dom (a, a)
-> Signal dom (BitVector (BitSize a), BitVector (BitSize a))
forall a b. (a -> b) -> Signal dom a -> Signal dom b
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
fmap ((a -> BitVector (BitSize a))
-> (a -> BitVector (BitSize a))
-> (a, a)
-> (BitVector (BitSize a), BitVector (BitSize a))
forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
forall (p :: Type -> Type -> Type) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap a -> BitVector (BitSize a)
forall a. BitPack a => a -> BitVector (BitSize a)
pack a -> BitVector (BitSize a)
forall a. BitPack a => a -> BitVector (BitSize a)
pack)

oddr#
  :: forall n dom domDDR
   . HasCallStack
  => KnownDomain dom
  => KnownDomain domDDR
  => DomainPeriod dom ~ (2 * DomainPeriod domDDR)
  => DomainActiveEdge dom ~ 'Rising
  => KnownNat n
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> Signal dom (BitVector n)
  -> Signal dom (BitVector n)
  -> Signal domDDR (BitVector n)
oddr# :: forall (n :: Nat) (dom :: Domain) (domDDR :: Domain).
(HasCallStack, KnownDomain dom, KnownDomain domDDR,
 DomainPeriod dom ~ (2 * DomainPeriod domDDR),
 DomainActiveEdge dom ~ 'Rising, KnownNat n) =>
Clock dom
-> Reset dom
-> Enable dom
-> Signal dom (BitVector n)
-> Signal dom (BitVector n)
-> Signal domDDR (BitVector n)
oddr# Clock dom
clk Reset dom
rst Enable dom
en = Clock dom
-> Reset dom
-> Enable dom
-> BitVector n
-> Signal dom (BitVector n)
-> Signal dom (BitVector n)
-> Signal domDDR (BitVector n)
forall a (dom :: Domain) (domDDR :: Domain).
(HasCallStack, NFDataX a, KnownDomain dom, KnownDomain domDDR,
 DomainPeriod dom ~ (2 * DomainPeriod domDDR)) =>
Clock dom
-> Reset dom
-> Enable dom
-> a
-> Signal dom a
-> Signal dom a
-> Signal domDDR a
ddrOut# Clock dom
clk Reset dom
rst Enable dom
en BitVector n
0
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE oddr# #-}
{-# ANN oddr# hasBlackBox #-}