clash-prelude-0.6: src/CLaSH/Signal/Delayed.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module CLaSH.Signal.Delayed
( -- * Delay-annotated synchronous signals
DSignal
, dsignal
, delay
, delayI
, feedback
-- * Signal \<-\> DSignal conversion
, fromSignal
, toSignal
, unsafeFromSignal
-- * List \<-\> DSignal conversion (not synthesisable)
, dsample
, dsampleN
, dfromList
)
where
import Data.Coerce (coerce)
import Data.Default (Default(..))
import Control.Applicative (Applicative (..))
import GHC.TypeLits (KnownNat, Nat, type (-))
import Language.Haskell.TH.Syntax (Lift)
import Prelude hiding (head, length, repeat)
import CLaSH.Sized.Vector (Vec, head, length, repeat, shiftInAt0,
singleton)
import CLaSH.Signal (Signal, fromList, register, sample, sampleN,
bundle', unbundle')
-- | A synchronized signal with samples of type @a@, synchronized to \"system\"
-- clock (period 1000), that has accumulated @delay@ amount of samples delay
-- along its path.
newtype DSignal (delay :: Nat) a =
DSignal { -- | Strip a 'DSignal' from its delay information.
toSignal :: Signal a
}
deriving (Show,Default,Lift,Functor,Applicative,Num)
-- | Create a 'DSignal' from a list
--
-- Every element in the list will correspond to a value of the signal for one
-- clock cycle.
--
-- >>> dsampleN 2 (fromList [1,2,3,4,5])
-- [1,2]
--
-- __NB__: This function is not synthesisable
dfromList :: [a] -> DSignal 0 a
dfromList = coerce . fromList
-- | Get an infinite list of samples from a 'DSignal'
--
-- The elements in the list correspond to the values of the 'DSignal' at
-- consecutive clock cycles
--
-- > dsample s == [s0, s1, s2, s3, ...
--
-- __NB__: This function is not synthesisable
dsample :: DSignal t a -> [a]
dsample = sample . coerce
-- | Get a list of @n@ samples from a 'DSignal'
--
-- The elements in the list correspond to the values of the 'DSignal' at
-- consecutive clock cycles
--
-- > dsampleN 3 s == [s0, s1, s2]
--
-- __NB__: This function is not synthesisable
dsampleN :: Int -> DSignal t a -> [a]
dsampleN n = sampleN n . coerce
-- | Create a constant 'DSignal' from a combinational value
--
-- >>> dsample (dsignal 4)
-- [4, 4, 4, 4, ...
dsignal :: a -> DSignal n a
dsignal = pure
-- | Delay a 'DSignal' for @m@ periods.
--
-- > delay3 :: DSignal (n - 3) Int -> DSignal n Int
-- > delay3 = delay (0 :> 0 :> 0 :> Nil)
--
-- >>> dsampleN 6 (delay3 (dfromList [1..]))
-- [0,0,0,1,2,3]
delay :: forall a n m . KnownNat m
=> Vec m a
-> DSignal (n - m) a
-> DSignal n a
delay m ds = coerce (delay' (coerce ds))
where
delay' :: Signal a -> Signal a
delay' s = case length m of
0 -> s
_ -> let (r',o) = shiftInAt0 (unbundle' r) (singleton s)
r = register m (bundle' r')
in head o
-- | Delay a 'DSignal' for @m@ periods, where @m@ is derived from the context.
--
-- > delay2 :: DSignal (n - 2) Int -> DSignal n Int
-- > delay2 = delayI
--
-- >>> dsampleN 6 (delay2 (dfromList [1..])
-- [0,0,1,2,3,4]
delayI :: (Default a, KnownNat m)
=> DSignal (n - m) a
-> DSignal n a
delayI = delay (repeat def)
-- | Feed the delayed result of a function back to its input:
--
-- @
-- mac :: DSignal 0 Int -> DSignal 0 Int -> DSignal 0 Int
-- mac x y = 'feedback' (mac' x y)
-- where
-- mac' :: DSignal 0 Int -> DSignal 0 Int -> DSignal 0 Int
-- -> (DSignal 0 Int, DSignal 1 Int)
-- mac' a b acc = let acc' = a * b + acc
-- in (acc, delay ('singleton' 0) acc')
-- @
--
-- >>> dsampleN 6 (mac (dfromList [1..]) (dfromList [1..]))
-- [0,1,5,14,30,55]
feedback :: (DSignal (n - m - 1) a -> (DSignal (n - m - 1) a,DSignal n a))
-> DSignal (n - m - 1) a
feedback f = let (o,r) = f (coerce r) in o
-- | 'Signal's are not delayed
--
-- > sample s == dsample (fromSignal s)
fromSignal :: Signal a -> DSignal 0 a
fromSignal = coerce
-- | __Unsafely__ convert a 'Signal' to /any/ 'DSignal'.
--
-- __NB__: Should only be used to interface with functions specified in terms of
-- 'Signal'.
unsafeFromSignal :: Signal a -> DSignal n a
unsafeFromSignal = DSignal