{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE Trustworthy #-}
{-# OPTIONS_GHC -fno-cpr-anal #-}
{-# OPTIONS_HADDOCK show-extensions #-}
module Clash.Explicit.RAM
(
asyncRam
, asyncRamPow2
, asyncRam#
)
where
import Data.Maybe (isJust)
import GHC.Stack (HasCallStack, withFrozenCallStack)
import GHC.TypeLits (KnownNat)
import qualified Data.Sequence as Seq
import Clash.Explicit.Signal
(unbundle, unsafeSynchronizer, KnownDomain, enable)
import Clash.Promoted.Nat (SNat (..), snatToNum, pow2SNat)
import Clash.Signal.Internal (Clock (..), Signal (..), Enable, fromEnable)
import Clash.Sized.Unsigned (Unsigned)
import Clash.XException (errorX, maybeIsX, fromJustX)
asyncRamPow2
:: forall wdom rdom n a
. ( KnownNat n
, HasCallStack
, KnownDomain wdom
, KnownDomain rdom
)
=> Clock wdom
-> Clock rdom
-> Enable wdom
-> Signal rdom (Unsigned n)
-> Signal wdom (Maybe (Unsigned n, a))
-> Signal rdom a
asyncRamPow2 = \wclk rclk en rd wrM -> withFrozenCallStack
(asyncRam wclk rclk en (pow2SNat (SNat @n)) rd wrM)
{-# INLINE asyncRamPow2 #-}
asyncRam
:: ( Enum addr
, HasCallStack
, KnownDomain wdom
, KnownDomain rdom
)
=> Clock wdom
-> Clock rdom
-> Enable wdom
-> SNat n
-> Signal rdom addr
-> Signal wdom (Maybe (addr, a))
-> Signal rdom a
asyncRam = \wclk rclk gen sz rd wrM ->
let en = isJust <$> wrM
(wr,din) = unbundle (fromJustX <$> wrM)
in withFrozenCallStack
(asyncRam# wclk rclk gen sz (fromEnum <$> rd) en (fromEnum <$> wr) din)
{-# INLINE asyncRam #-}
asyncRam#
:: ( HasCallStack
, KnownDomain wdom
, KnownDomain rdom )
=> Clock wdom
-> Clock rdom
-> Enable wdom
-> SNat n
-> Signal rdom Int
-> Signal wdom Bool
-> Signal wdom Int
-> Signal wdom a
-> Signal rdom a
asyncRam# wclk rclk en sz rd we wr din =
unsafeSynchronizer wclk rclk dout
where
rd' = unsafeSynchronizer rclk wclk rd
ramI = Seq.replicate
(snatToNum sz)
(withFrozenCallStack (errorX "asyncRam#: initial value undefined"))
en' = fromEnable (enable en we)
dout = go ramI rd' en' wr din
go :: Seq.Seq a -> Signal wdom Int -> Signal wdom Bool
-> Signal wdom Int -> Signal wdom a -> Signal wdom a
go !ram (r :- rs) (e :- es) (w :- ws) (d :- ds) =
let ram' = upd ram e (fromEnum w) d
o = ram `Seq.index` r
in o :- go ram' rs es ws ds
upd ram we' waddr d = case maybeIsX we' of
Nothing -> case maybeIsX waddr of
Nothing -> fmap (const (seq waddr d)) ram
Just wa -> Seq.update wa d ram
Just True -> case maybeIsX waddr of
Nothing -> fmap (const (seq waddr d)) ram
Just wa -> Seq.update wa d ram
_ -> ram
{-# NOINLINE asyncRam# #-}