{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Trustworthy #-}
{-# OPTIONS_GHC -fno-cpr-anal #-}
{-# OPTIONS_HADDOCK show-extensions #-}
module Clash.Explicit.RAM
(
asyncRam
, asyncRamPow2
, asyncRam#
)
where
import Data.Maybe (fromJust, isJust)
import GHC.Stack (HasCallStack, withFrozenCallStack)
import GHC.TypeLits (KnownNat)
import qualified Data.Vector as V
import Clash.Explicit.Signal ((.&&.), unbundle, unsafeSynchronizer)
import Clash.Promoted.Nat (SNat (..), snatToNum, pow2SNat)
import Clash.Signal.Internal (Clock (..), Signal (..), clockEnable)
import Clash.Sized.Unsigned (Unsigned)
import Clash.XException (errorX, maybeX)
asyncRamPow2
:: forall wdom rdom wgated rgated n a
. (KnownNat n, HasCallStack)
=> Clock wdom wgated
-> Clock rdom rgated
-> Signal rdom (Unsigned n)
-> Signal wdom (Maybe (Unsigned n, a))
-> Signal rdom a
asyncRamPow2 = \wclk rclk rd wrM -> withFrozenCallStack
(asyncRam wclk rclk (pow2SNat (SNat @ n)) rd wrM)
{-# INLINE asyncRamPow2 #-}
asyncRam
:: (Enum addr, HasCallStack)
=> Clock wdom wgated
-> Clock rdom rgated
-> SNat n
-> Signal rdom addr
-> Signal wdom (Maybe (addr, a))
-> Signal rdom a
asyncRam = \wclk rclk sz rd wrM ->
let en = isJust <$> wrM
(wr,din) = unbundle (fromJust <$> wrM)
in withFrozenCallStack
(asyncRam# wclk rclk sz (fromEnum <$> rd) en (fromEnum <$> wr) din)
{-# INLINE asyncRam #-}
asyncRam#
:: HasCallStack
=> Clock wdom wgated
-> Clock rdom rgated
-> SNat n
-> Signal rdom Int
-> Signal wdom Bool
-> Signal wdom Int
-> Signal wdom a
-> Signal rdom a
asyncRam# wclk rclk sz rd en wr din =
unsafeSynchronizer wclk rclk dout
where
rd' = unsafeSynchronizer rclk wclk rd
ramI = V.replicate
(snatToNum sz)
(withFrozenCallStack (errorX "asyncRam#: initial value undefined"))
en' = case clockEnable wclk of
Nothing -> en
Just wgt -> wgt .&&. en
dout = go ramI rd' en' wr din
go :: V.Vector 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 V.! r
in o :- go ram' rs es ws ds
upd ram we waddr d = case maybeX we of
Nothing -> case maybeX waddr of
Nothing -> V.map (const (seq waddr d)) ram
Just wa -> ram V.// [(wa,d)]
Just True -> case maybeX waddr of
Nothing -> V.map (const (seq waddr d)) ram
Just wa -> ram V.// [(wa,d)]
_ -> ram
{-# NOINLINE asyncRam# #-}