{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Clash.Explicit.DDR
( ddrIn
, ddrOut
, ddrIn#
, ddrOut#
)
where
import GHC.Stack (HasCallStack, withFrozenCallStack)
import Clash.Explicit.Prelude
import Clash.Signal.Internal
ddrIn
:: ( HasCallStack
, fast ~ 'Dom n pFast
, slow ~ 'Dom n (2*pFast))
=> Clock slow gated
-> Reset slow synchronous
-> (a, a, a)
-> Signal fast a
-> Signal slow (a,a)
ddrIn clk rst (i0,i1,i2) = withFrozenCallStack $ ddrIn# clk rst i0 i1 i2
ddrIn#
:: forall a slow fast n pFast gated synchronous
. ( HasCallStack
, fast ~ 'Dom n pFast
, slow ~ 'Dom n (2*pFast))
=> Clock slow gated
-> Reset slow synchronous
-> a
-> a
-> a
-> Signal fast a
-> Signal slow (a,a)
ddrIn# (Clock {}) (Sync rst) i0 i1 i2 =
go ((errorX "ddrIn: initial value 0 undefined")
,(errorX "ddrIn: initial value 1 undefined")
,(errorX "ddrIn: initial value 2 undefined"))
rst
where
go :: (a,a,a) -> Signal slow Bool -> Signal fast a -> Signal slow (a,a)
go (o0,o1,o2) rt@(~(r :- rs)) as@(~(x0 :- x1 :- xs)) =
let (o0',o1',o2') = if r then (i0,i1,i2) else (o2,x0,x1)
in o0 `seqX` o1 `seqX` (o0,o1) :- (rt `seq` as `seq` go (o0',o1',o2') rs xs)
ddrIn# (Clock {}) (Async rst) i0 i1 i2 =
go ((errorX "ddrIn: initial value 0 undefined")
,(errorX "ddrIn: initial value 1 undefined")
,(errorX "ddrIn: initial value 2 undefined"))
rst
where
go :: (a,a,a) -> Signal slow Bool -> Signal fast a -> Signal slow (a,a)
go (o0,o1,o2) ~(r :- rs) as@(~(x0 :- x1 :- xs)) =
let (o0',o1',o2') = if r then (i0,i1,i2) else (o0,o1,o2)
in o0' `seqX` o1' `seqX`(o0',o1') :- (as `seq` go (o2',x0,x1) rs xs)
ddrIn# (GatedClock _ _ ena) (Sync rst) i0 i1 i2 =
go ((errorX "ddrIn: initial value 0 undefined")
,(errorX "ddrIn: initial value 1 undefined")
,(errorX "ddrIn: initial value 2 undefined"))
rst
ena
where
go :: (a,a,a) -> Signal slow Bool -> Signal slow Bool -> Signal fast a -> Signal slow (a,a)
go (o0,o1,o2) rt@(~(r :- rs)) ~(e :- es) as@(~(x0 :- x1 :- xs)) =
let (o0',o1',o2') = if r then (i0,i1,i2) else (o2,x0,x1)
in o0 `seqX` o1 `seqX` (o0,o1)
:- (rt `seq` as `seq` if e then go (o0',o1',o2') rs es xs
else go (o0 ,o1 ,o2) rs es xs)
ddrIn# (GatedClock _ _ ena) (Async rst) i0 i1 i2 =
go ((errorX "ddrIn: initial value 0 undefined")
,(errorX "ddrIn: initial value 1 undefined")
,(errorX "ddrIn: initial value 2 undefined"))
rst
ena
where
go :: (a,a,a) -> Signal slow Bool -> Signal slow Bool -> Signal fast a -> Signal slow (a,a)
go (o0,o1,o2) ~(r :- rs) ~(e :- es) as@(~(x0 :- x1 :- xs)) =
let (o0',o1',o2') = if r then (i0,i1,i2) else (o0,o1,o2)
in o0' `seqX` o1' `seqX` (o0',o1')
:- (as `seq` if e then go (o2',x0 ,x1) rs es xs
else go (o0',o1',o2') rs es xs)
{-# NOINLINE ddrIn# #-}
ddrOut :: ( HasCallStack
, fast ~ 'Dom n pFast
, slow ~ 'Dom n (2*pFast))
=> Clock slow gated
-> Reset slow synchronous
-> a
-> Signal slow (a,a)
-> Signal fast a
ddrOut clk rst i0 = uncurry (withFrozenCallStack $ ddrOut# clk rst i0) . unbundle
ddrOut# :: ( HasCallStack
, fast ~ 'Dom n pFast
, slow ~ 'Dom n (2*pFast))
=> Clock slow gated
-> Reset slow synchronous
-> a
-> Signal slow a
-> Signal slow a
-> Signal fast a
ddrOut# clk rst i0 xs ys =
let (_ :- out) = zipSig xs' ys' in out
where
xs' = register clk rst i0 xs
ys' = register clk rst i0 ys
zipSig (a :- as) (b :- bs) = a :- b :- zipSig as bs
{-# NOINLINE ddrOut# #-}