{-|
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>

We simulate DDR signal by using 'Signal's which have exactly half the period
(or double the speed) of our normal 'Signal's.

The primitives in this module can be used to produce or consume DDR signals.

DDR signals are not meant to be used internally in a design,
but only to communicate with the outside world.

In some cases hardware specific DDR IN registers can be inferred by synthesis
tools from these generic primitives. But to be sure your design will synthesize
to dedicated hardware resources use the functions from "Clash.Intel.DDR"
or "Clash.Xilinx.DDR".
-}

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

module Clash.Explicit.DDR
  ( ddrIn
  , ddrOut
  , ddrForwardClock
    -- * Internal
  , ddrIn#
  , ddrOut#
  , ddrForwardClock#
  )
where

import Data.List.Infinite (Infinite(..), (...))
import Data.String.Interpolate (__i)
import GHC.Stack (HasCallStack, withFrozenCallStack)
import Unsafe.Coerce (unsafeCoerce)

import Clash.Annotations.Primitive (hasBlackBox, Primitive(..), HDL(..))
import Clash.Explicit.Prelude hiding ((:<))
import Clash.Signal.Internal

{- $setup
>>> :set -XNoImplicitPrelude -XTypeFamilies -XFlexibleInstances
>>> import Clash.Explicit.Prelude
>>> import Clash.Explicit.DDR
>>> :{
type DDR = "DDR" :: Domain
instance KnownDomain "DDR" where
  type KnownConf "DDR" = 'DomainConfiguration "DDR" 5000 'Rising 'Asynchronous 'Defined 'ActiveHigh
  knownDomain = SDomainConfiguration SSymbol SNat SRising SAsynchronous SDefined SActiveHigh
:}

-}

-- | DDR input primitive
--
-- Consumes a DDR input signal and produces a regular signal containing a pair
-- of values.
--
-- Data is clocked in on both edges of the clock signal. We can discern the
-- /active edge/ of the clock and the /other edge/. When the domain has the
-- rising edge as the active edge (which is the most common), this means that
-- the /rising/ edge is the /active/ edge and the /falling/ edge is the /other/
-- edge.
--
-- Of the output pair @(o0, o1)@, @o0@ is the data clocked in on the /other/
-- edge and @o1@ is the data clocked in on the /active/ edge, and @o0@ comes
-- before @o1@ in time. With a domain where the rising edge is the active edge,
-- this means @o0@ is clocked in on the falling clock edge and @o1@ is clocked
-- in on the rising clock edge. For a domain with the falling edge as the active
-- edge, this is the other way around, but @o0@ still comes before @o1@ in time.
--
-- >>> sampleN 5 $ ddrIn @Int @System @DDR clockGen resetGen enableGen (-1,-2,-3) (fromList [0..10])
-- [(-1,-2),(-1,-2),(-3,2),(3,4),(5,6)]
ddrIn
  :: forall a dom domDDR
   . HasCallStack
  => NFDataX a
  => KnownDomain dom
  => KnownDomain domDDR
  => DomainPeriod dom ~ (2 * DomainPeriod domDDR)
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> (a, a, a)
  -- ^ Reset values
  -> Signal domDDR a
  -- ^ DDR input signal
  -> Signal dom (a, a)
  -- ^ Normal speed output pair @(o0, o1)@
ddrIn :: 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 (a
i0,a
i1,a
i2) =
  (HasCallStack => Signal domDDR a -> Signal dom (a, a))
-> Signal domDDR a -> Signal dom (a, a)
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack ((HasCallStack => Signal domDDR a -> Signal dom (a, a))
 -> Signal domDDR a -> Signal dom (a, a))
-> (HasCallStack => Signal domDDR a -> Signal dom (a, a))
-> Signal domDDR a
-> Signal dom (a, a)
forall a b. (a -> b) -> a -> b
$ Clock dom
-> Reset dom
-> Enable dom
-> a
-> a
-> a
-> Signal domDDR a
-> Signal dom (a, a)
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 a
i0 a
i1 a
i2


-- For details about all the seq's en seqX's
-- see the [Note: register strictness annotations] in Clash.Signal.Internal
ddrIn#
  :: forall a dom domDDR
   . 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# :: 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 SSymbol dom
_ Maybe (Signal dom Femtoseconds)
Nothing) (Reset dom -> Signal dom Bool
forall (dom :: Domain).
KnownDomain dom =>
Reset dom -> Signal dom Bool
unsafeToActiveHigh -> Signal dom Bool
hRst) (Enable dom -> Signal dom Bool
forall (dom :: Domain). Enable dom -> Signal dom Bool
fromEnable -> Signal dom Bool
ena) a
i0 a
i1 a
i2 =
  case forall (dom :: Domain) (sync :: ResetKind).
(KnownDomain dom, DomainResetKind dom ~ sync) =>
SResetKind sync
resetKind @domDDR of
    SResetKind (DomainConfigurationResetKind (KnownConf domDDR))
SAsynchronous ->
      (a, a, a)
-> Signal dom Bool
-> Signal dom Bool
-> Signal domDDR a
-> Signal dom (a, a)
goAsync
        ( String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"ddrIn: initial value 0 undefined"
        , String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"ddrIn: initial value 1 undefined"
        , String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"ddrIn: initial value 2 undefined" )
        Signal dom Bool
hRst
        Signal dom Bool
ena
    SResetKind (DomainConfigurationResetKind (KnownConf domDDR))
SSynchronous ->
      (a, a, a)
-> Signal dom Bool
-> Signal dom Bool
-> Signal domDDR a
-> Signal dom (a, a)
goSync
        ( String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"ddrIn: initial value 0 undefined"
        , String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"ddrIn: initial value 1 undefined"
        , String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"ddrIn: initial value 2 undefined" )
        Signal dom Bool
hRst
        Signal dom Bool
ena
  where
    goSync
      :: (a, a, a)
      -> Signal dom Bool
      -> Signal dom Bool
      -> Signal domDDR a
      -> Signal dom (a,a)
    goSync :: (a, a, a)
-> Signal dom Bool
-> Signal dom Bool
-> Signal domDDR a
-> Signal dom (a, a)
goSync (a
o0,a
o1,a
o2) rt :: Signal dom Bool
rt@(~(Bool
r :- Signal dom Bool
rs)) ~(Bool
e :- Signal dom Bool
es) as :: Signal domDDR a
as@(~(a
x0 :- a
x1 :- Signal domDDR a
xs)) =
      let (a
o0',a
o1',a
o2') = if Bool
r then (a
i0,a
i1,a
i2) else (a
o2,a
x0,a
x1)
      in a
o0 a -> Signal dom (a, a) -> Signal dom (a, a)
forall a b. a -> b -> b
`seqX` a
o1 a -> Signal dom (a, a) -> Signal dom (a, a)
forall a b. a -> b -> b
`seqX` (a
o0,a
o1)
           (a, a) -> Signal dom (a, a) -> Signal dom (a, a)
forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
:- (Signal dom Bool
rt Signal dom Bool -> Signal dom (a, a) -> Signal dom (a, a)
forall a b. a -> b -> b
`seq` Signal domDDR a
as Signal domDDR a -> Signal dom (a, a) -> Signal dom (a, a)
forall a b. a -> b -> b
`seq` if Bool
e then (a, a, a)
-> Signal dom Bool
-> Signal dom Bool
-> Signal domDDR a
-> Signal dom (a, a)
goSync (a
o0',a
o1',a
o2') Signal dom Bool
rs Signal dom Bool
es Signal domDDR a
xs
                                      else (a, a, a)
-> Signal dom Bool
-> Signal dom Bool
-> Signal domDDR a
-> Signal dom (a, a)
goSync (a
o0 ,a
o1 ,a
o2)  Signal dom Bool
rs Signal dom Bool
es Signal domDDR a
xs)

    goAsync
      :: (a, a, a)
      -> Signal dom Bool
      -> Signal dom Bool
      -> Signal domDDR a
      -> Signal dom (a, a)
    goAsync :: (a, a, a)
-> Signal dom Bool
-> Signal dom Bool
-> Signal domDDR a
-> Signal dom (a, a)
goAsync (a
o0,a
o1,a
o2) ~(Bool
r :- Signal dom Bool
rs) ~(Bool
e :- Signal dom Bool
es) as :: Signal domDDR a
as@(~(a
x0 :- a
x1 :- Signal domDDR a
xs)) =
      let (a
o0',a
o1',a
o2',a
o3',a
o4') = if Bool
r then (a
i0,a
i1,a
i0,a
i1,a
i2) else (a
o0,a
o1,a
o2,a
x0,a
x1)
      in a
o0' a -> Signal dom (a, a) -> Signal dom (a, a)
forall a b. a -> b -> b
`seqX` a
o1' a -> Signal dom (a, a) -> Signal dom (a, a)
forall a b. a -> b -> b
`seqX` (a
o0',a
o1')
           (a, a) -> Signal dom (a, a) -> Signal dom (a, a)
forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
:- (Signal domDDR a
as Signal domDDR a -> Signal dom (a, a) -> Signal dom (a, a)
forall a b. a -> b -> b
`seq` if Bool
e then (a, a, a)
-> Signal dom Bool
-> Signal dom Bool
-> Signal domDDR a
-> Signal dom (a, a)
goAsync (a
o2',a
o3',a
o4') Signal dom Bool
rs Signal dom Bool
es Signal domDDR a
xs
                             else (a, a, a)
-> Signal dom Bool
-> Signal dom Bool
-> Signal domDDR a
-> Signal dom (a, a)
goAsync (a
o0',a
o1',a
o2') Signal dom Bool
rs Signal dom Bool
es Signal domDDR a
xs)

ddrIn# Clock dom
_ Reset dom
_ Enable dom
_ a
_ a
_ a
_ =
  String -> Signal domDDR a -> Signal dom (a, a)
forall a. HasCallStack => String -> a
error String
"ddrIn#: dynamic clocks not supported"
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE ddrIn# #-}
{-# ANN ddrIn# hasBlackBox #-}

-- | DDR output primitive
--
-- Produces a DDR output signal from a normal signal of pairs of input.
--
-- Data is clocked out on both edges of the clock signal. We can discern the
-- /active edge/ of the clock and the /other edge/. When the domain has the
-- rising edge as the active edge (which is the most common), this means that
-- the /rising/ edge is the /active/ edge and the /falling/ edge is the /other/
-- edge.
--
-- Of the input pair @(i0, i1)@, @i0@ is the data clocked out on the /active/
-- edge and @i1@ is the data clocked out on the /other/ edge, and @i0@ comes
-- before @i1@ in time. With a domain where the rising edge is the active edge,
-- this means @i0@ is clocked out on the rising clock edge and @i1@ is clocked
-- out on the falling clock edge. For a domain with the falling edge as the
-- active edge, this is the other way around, but @i0@ still comes before @i1@
-- in time.
--
-- >>> sampleN 7 (ddrOut @Int @System @DDR clockGen resetGen enableGen (-1) (fromList [(0,1),(2,3),(4,5)]))
-- [-1,-1,-1,2,3,4,5]
ddrOut
  :: forall a dom domDDR
   . HasCallStack
  => NFDataX a
  => KnownDomain dom
  => KnownDomain domDDR
  => DomainPeriod dom ~ (2 * DomainPeriod domDDR)
  => Clock dom
  -> Reset dom
  -> Enable dom
  -> a
  -- ^ Reset value
  -> Signal dom (a, a)
  -- ^ Normal speed input pair @(i0, i1)@
  -> Signal domDDR a
  -- ^ DDR output signal
ddrOut :: 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, a)
-> Signal domDDR a
ddrOut Clock dom
clk Reset dom
rst Enable dom
en a
i0 =
  (Signal dom a -> Signal dom a -> Signal domDDR a)
-> (Signal dom a, Signal dom a) -> Signal domDDR a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((HasCallStack => Signal dom a -> Signal dom a -> Signal domDDR a)
-> Signal dom a -> Signal dom a -> Signal domDDR a
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack ((HasCallStack => Signal dom a -> Signal dom a -> Signal domDDR a)
 -> Signal dom a -> Signal dom a -> Signal domDDR a)
-> (HasCallStack =>
    Signal dom a -> Signal dom a -> Signal domDDR a)
-> Signal dom a
-> Signal dom a
-> Signal domDDR a
forall a b. (a -> b) -> a -> b
$ Clock dom
-> Reset dom
-> Enable dom
-> a
-> Signal dom a
-> Signal dom a
-> Signal domDDR a
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 a
i0) ((Signal dom a, Signal dom a) -> Signal domDDR a)
-> (Signal dom (a, a) -> (Signal dom a, Signal dom a))
-> Signal dom (a, a)
-> Signal domDDR a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Signal dom (a, a) -> (Signal dom a, Signal dom a)
Signal dom (a, a) -> Unbundled dom (a, a)
forall a (dom :: Domain).
Bundle a =>
Signal dom a -> Unbundled dom a
forall (dom :: Domain). Signal dom (a, a) -> Unbundled dom (a, a)
unbundle


ddrOut#
  :: forall a dom domDDR
   . 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# :: 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 a
i0 Signal dom a
xs Signal dom a
ys =
    -- We only observe one reset value, because when the mux switches on the
    -- next clock level, the second register will already be outputting its
    -- first input.
    --
    -- That is why we drop the first value of the stream.
    let (a
_ :- Signal domDDR a
out) = Signal dom a -> Signal dom a -> Signal domDDR a
forall {dom :: Domain} {a} {dom :: Domain} {dom :: Domain}.
Signal dom a -> Signal dom a -> Signal dom a
zipSig Signal dom a
xs' Signal dom a
ys' in Signal domDDR a
out
  where
    xs' :: Signal dom a
xs' = Clock dom
-> Reset dom
-> Enable dom
-> a
-> a
-> Signal dom a
-> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom
-> Enable dom
-> a
-> a
-> Signal dom a
-> Signal dom a
register# Clock dom
clk Reset dom
rst Enable dom
en (String -> a
forall a. HasCallStack => String -> a
errorX String
"ddrOut: unreachable error") a
i0 Signal dom a
xs
    ys' :: Signal dom a
ys' = Clock dom
-> Reset dom
-> Enable dom
-> a
-> a
-> Signal dom a
-> Signal dom a
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom
-> Enable dom
-> a
-> a
-> Signal dom a
-> Signal dom a
register# Clock dom
clk Reset dom
rst Enable dom
en (String -> a
forall a. (NFDataX a, HasCallStack) => String -> a
deepErrorX String
"ddrOut: initial value undefined") a
i0 Signal dom a
ys
    zipSig :: Signal dom a -> Signal dom a -> Signal dom a
zipSig (a
a :- Signal dom a
as) (a
b :- Signal dom a
bs) = a
a a -> Signal dom a -> Signal dom a
forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
:- a
b a -> Signal dom a -> Signal dom a
forall (dom :: Domain) a. a -> Signal dom a -> Signal dom a
:- Signal dom a -> Signal dom a -> Signal dom a
zipSig Signal dom a
as Signal dom a
bs
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE ddrOut# #-}
{-# ANN ddrOut# hasBlackBox #-}

-- | Use a DDR output primitive to forward a clock to an output pin
--
-- This function allows outputting a clock signal on a DDR-capable output pin.
-- As with the DDR output primitive itself, the created clock cannot be used
-- internally in the design.
--
-- The @ddrOut@ primitive passed in will always have its enable asserted. If the
-- @Enable@ input of @ddrForwardClock@ is deasserted, the data inputs of the
-- @ddrOut@ primitive will switch to achieve the desired output signal. This is
-- because the behavior of the enable input of the DDR primitive differs between
-- vendor-specific primitives.
--
-- The @Reset@ input of this function is passed on to the @ddrOut@ primitive and
-- not otherwise used by @ddrForwardClock@.
--
-- With the @phase@ argument, the phase relation between input and output clock
-- can be defined. With the argument @Nothing@, the clocks are in phase: the
-- active edge of the output clock is on the active edge of the input clock,
-- even if the domains differ on what the active edge is.
--
-- With the @idle@ argument, the output level when the @Enable@ input is
-- deasserted can be defined. With @Nothing@, it will be 0 for a clock with the
-- rising edge as the active edge, and 1 for a clock with the falling edge as
-- the active edge.
--
-- __NB__: The deassertion of the @Enable@ input or the assertion of the @Reset@
-- input is not faithfully simulated in Haskell simulation: Haskell simulation
-- of a Clash design has clocks that always run. The generated HDL will actually
-- output an idle state when @Enable@ is deasserted (and the reset depends on
-- the @ddrOut@ primitive used).
ddrForwardClock
  :: forall domDDR domOut domIn
   . KnownDomain domOut
  => DomainPeriod domIn ~ DomainPeriod domOut
  => DomainPeriod domIn ~ (2 * DomainPeriod domDDR)
  => Clock domIn
  -> Reset domIn
  -> Enable domIn
  -> Maybe Bit
  -- ^ @idle@: Output value when @Enable@ is deasserted
  -> Maybe Bit
  -- ^ @phase@: Value to output at active edge of incoming clock
  -> (Clock domIn -> Reset domIn -> Enable domIn -> Signal domIn (Bit, Bit)
      -> Signal domDDR Bit)
  -- ^ @ddrOut@ primitive to use
  -> Clock domOut
ddrForwardClock :: forall (domDDR :: Domain) (domOut :: Domain) (domIn :: Domain).
(KnownDomain domOut, DomainPeriod domIn ~ DomainPeriod domOut,
 DomainPeriod domIn ~ (2 * DomainPeriod domDDR)) =>
Clock domIn
-> Reset domIn
-> Enable domIn
-> Maybe Bit
-> Maybe Bit
-> (Clock domIn
    -> Reset domIn
    -> Enable domIn
    -> Signal domIn (Bit, Bit)
    -> Signal domDDR Bit)
-> Clock domOut
ddrForwardClock Clock domIn
clk Reset domIn
rst Enable domIn
en Maybe Bit
idle Maybe Bit
phase Clock domIn
-> Reset domIn
-> Enable domIn
-> Signal domIn (Bit, Bit)
-> Signal domDDR Bit
oddr =
  Clock domIn -> Signal domDDR Bit -> Clock domOut
forall (domOut :: Domain) (domIn :: Domain) (domDDR :: Domain).
(KnownDomain domOut, DomainPeriod domIn ~ DomainPeriod domOut,
 DomainPeriod domIn ~ (2 * DomainPeriod domDDR)) =>
Clock domIn -> Signal domDDR Bit -> Clock domOut
ddrForwardClock# Clock domIn
clk (Signal domDDR Bit -> Clock domOut)
-> Signal domDDR Bit -> Clock domOut
forall a b. (a -> b) -> a -> b
$ Clock domIn
-> Reset domIn
-> Enable domIn
-> Signal domIn (Bit, Bit)
-> Signal domDDR Bit
oddr Clock domIn
clk Reset domIn
rst Enable domIn
forall (dom :: Domain). Enable dom
enableGen Signal domIn (Bit, Bit)
ins
 where
  ins :: Signal domIn (Bit, Bit)
ins =
    Signal domIn Bool
-> Signal domIn (Bit, Bit)
-> Signal domIn (Bit, Bit)
-> Signal domIn (Bit, Bit)
forall (f :: Type -> Type) a.
Applicative f =>
f Bool -> f a -> f a -> f a
mux
      (Enable domIn -> Signal domIn Bool
forall (dom :: Domain). Enable dom -> Signal dom Bool
fromEnable Enable domIn
en)
      ((Bit, Bit) -> Signal domIn (Bit, Bit)
forall a. a -> Signal domIn a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Bit
activeLevel, Bit -> Bit
forall a. Bits a => a -> a
complement Bit
activeLevel))
      ((Bit, Bit) -> Signal domIn (Bit, Bit)
forall a. a -> Signal domIn a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Bit
idleLevel, Bit
idleLevel))
  activeLevel :: Bit
activeLevel =
    case Maybe Bit
phase of
      Maybe Bit
Nothing ->
        case forall (dom :: Domain) (edge :: ActiveEdge).
(KnownDomain dom, DomainActiveEdge dom ~ edge) =>
SActiveEdge edge
activeEdge @domOut of
          SActiveEdge (DomainConfigurationActiveEdge (KnownConf domOut))
SRising -> Bit
1
          SActiveEdge (DomainConfigurationActiveEdge (KnownConf domOut))
SFalling -> Bit
0
      Just Bit
x -> Bit
x
  idleLevel :: Bit
idleLevel =
    case Maybe Bit
idle of
      Maybe Bit
Nothing ->
        case forall (dom :: Domain) (edge :: ActiveEdge).
(KnownDomain dom, DomainActiveEdge dom ~ edge) =>
SActiveEdge edge
activeEdge @domOut of
          SActiveEdge (DomainConfigurationActiveEdge (KnownConf domOut))
SRising -> Bit
0
          SActiveEdge (DomainConfigurationActiveEdge (KnownConf domOut))
SFalling -> Bit
1
      Just Bit
x -> Bit
x

ddrForwardClock#
  :: KnownDomain domOut
  => DomainPeriod domIn ~ DomainPeriod domOut
  => DomainPeriod domIn ~ (2 * DomainPeriod domDDR)
  => Clock domIn
  -> Signal domDDR Bit
  -> Clock domOut
ddrForwardClock# :: forall (domOut :: Domain) (domIn :: Domain) (domDDR :: Domain).
(KnownDomain domOut, DomainPeriod domIn ~ DomainPeriod domOut,
 DomainPeriod domIn ~ (2 * DomainPeriod domDDR)) =>
Clock domIn -> Signal domDDR Bit -> Clock domOut
ddrForwardClock# (Clock SSymbol domIn
SSymbol Maybe (Signal domIn Femtoseconds)
periods) Signal domDDR Bit
ddrSignal =
  SSymbol domOut
-> Maybe (Signal domOut Femtoseconds) -> Clock domOut
forall (dom :: Domain).
SSymbol dom -> Maybe (Signal dom Femtoseconds) -> Clock dom
Clock (Signal domDDR Bit
ddrSignal Signal domDDR Bit -> SSymbol domOut -> SSymbol domOut
forall a b. a -> b -> b
`seq` SSymbol domOut
forall (s :: Domain). KnownSymbol s => SSymbol s
SSymbol) (Maybe (Signal domIn Femtoseconds)
-> Maybe (Signal domOut Femtoseconds)
forall a b. a -> b
unsafeCoerce Maybe (Signal domIn Femtoseconds)
periods)
-- See: https://github.com/clash-lang/clash-compiler/pull/2511
{-# CLASH_OPAQUE ddrForwardClock# #-}
{-# ANN ddrForwardClock# (
  let
    bbName = show 'ddrForwardClock#
    _knownDomOut
      :< _domInOutPeriod
      :< _domDDRPeriod
      :< _clkIn
      :< ddrSignal
      :< _ = ((0 :: Int)...)
  in InlineYamlPrimitive [VHDL] [__i|
    BlackBox:
      name: #{bbName}
      kind: Expression
      template: ~TYPMO'(~ARG[#{ddrSignal}])
      workInfo: Never
    |]) #-}
{-# ANN ddrForwardClock# (
  let
    bbName = show 'ddrForwardClock#
    _knownDomOut
      :< _domInOutPeriod
      :< _domDDRPeriod
      :< _clkIn
      :< ddrSignal
      :< _ = ((0 :: Int)...)
  in InlineYamlPrimitive [Verilog, SystemVerilog] [__i|
    BlackBox:
      name: #{bbName}
      kind: Expression
      template: ~ARG[#{ddrSignal}]
      workInfo: Never
    |]) #-}