clash-prelude-0.6: src/CLaSH/Signal/Internal.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module CLaSH.Signal.Internal
( -- * Datatypes
Clock (..)
, SClock (..)
, CSignal (..)
-- * Basic circuits
, register#
, regEn#
, mux
-- * Boolean connectives
, (.&&.), (.||.), not1
-- * Type classes
-- ** 'Eq'-like
, (.==.), (./=.)
-- ** 'Ord'-like
, compare1, (.<.), (.<=.), (.>=.), (.>.)
-- ** 'Functor'
, mapSignal#
-- ** 'Applicative'
, signal#
, appSignal#
-- ** 'Foldable'
, foldr#
-- ** 'Traversable'
, traverse#
-- ** 'Enum'-like
, fromEnum1
-- ** 'Rational'-like
, toRational1
-- ** 'Integral'-like
, toInteger1
-- ** 'Bits'-like
, testBit1
, popCount1
, shift1
, rotate1
, setBit1
, clearBit1
, shiftL1
, unsafeShiftL1
, shiftR1
, unsafeShiftR1
, rotateL1
, rotateR1
)
where
import Control.Applicative (Applicative (..), (<$>), liftA2, liftA3)
import Data.Bits (Bits (..), FiniteBits (..))
import Data.Default (Default (..))
import Data.Foldable (Foldable (..))
import Data.Traversable (Traversable (..))
import GHC.TypeLits (Nat, Symbol)
import Language.Haskell.TH.Syntax (Lift (..))
import CLaSH.Class.Num (ExtendingNum (..), SaturatingNum (..))
import CLaSH.Promoted.Nat (SNat)
import CLaSH.Promoted.Symbol (SSymbol)
-- | A clock with a name ('Symbol') and period ('Nat')
data Clock = Clk Symbol Nat
-- | Singleton value for a type-level 'Clock' with the given @name@ and @period@
data SClock (clk :: Clock)
where
SClock :: SSymbol name -> SNat period -> SClock (Clk name period)
infixr 5 :-
-- | A synchronized signal with samples of type @a@, explicitly synchronized to
-- a clock @clk@
--
-- __NB__: The constructor, @(':-')@, is __not__ synthesisable.
data CSignal (clk :: Clock) a = a :- CSignal clk a
instance Show a => Show (CSignal clk a) where
show (x :- xs) = show x ++ " " ++ show xs
instance Lift a => Lift (CSignal clk a) where
lift ~(x :- _) = [| signal# x |]
instance Default a => Default (CSignal clk a) where
def = signal# def
instance Functor (CSignal clk) where
fmap = mapSignal#
{-# NOINLINE mapSignal# #-}
mapSignal# :: (a -> b) -> CSignal clk a -> CSignal clk b
mapSignal# f (a :- as) = f a :- mapSignal# f as
instance Applicative (CSignal clk) where
pure = signal#
(<*>) = appSignal#
{-# NOINLINE signal# #-}
signal# :: a -> CSignal clk a
signal# a = let s = a :- s in s
{-# NOINLINE appSignal# #-}
appSignal# :: CSignal clk (a -> b) -> CSignal clk a -> CSignal clk b
appSignal# (f :- fs) ~(a :- as) = f a :- appSignal# fs as
instance Num a => Num (CSignal clk a) where
(+) = liftA2 (+)
(-) = liftA2 (-)
(*) = liftA2 (*)
negate = fmap negate
abs = fmap abs
signum = fmap signum
fromInteger = signal# . fromInteger
-- | __NB__: Not synthesisable
--
-- __NB__: In \"@'foldr' f z s@\":
--
-- * The function @f@ should be /lazy/ in its second argument.
-- * The @z@ element will never be used.
instance Foldable (CSignal clk) where
foldr = foldr#
{-# NOINLINE foldr# #-}
-- | __NB__: Not synthesisable
--
-- __NB__: In \"@'foldr#' f z s@\":
--
-- * The function @f@ should be /lazy/ in its second argument.
-- * The @z@ element will never be used.
foldr# :: (a -> b -> b) -> b -> CSignal clk a -> b
foldr# f z (a :- s) = a `f` (foldr# f z s)
instance Traversable (CSignal clk) where
traverse = traverse#
{-# NOINLINE traverse# #-}
traverse# :: Applicative f => (a -> f b) -> CSignal clk a -> f (CSignal clk b)
traverse# f (a :- s) = (:-) <$> f a <*> traverse# f s
infixr 2 .||.
-- | Version of ('||') that returns a 'CSignal' of 'Bool'
(.||.) :: CSignal clk Bool -> CSignal clk Bool -> CSignal clk Bool
(.||.) = liftA2 (||)
infixr 3 .&&.
-- | Version of ('&&') that returns a 'CSignal' of 'Bool'
(.&&.) :: CSignal clk Bool -> CSignal clk Bool -> CSignal clk Bool
(.&&.) = liftA2 (&&)
-- | Version of 'not' that operates on 'CSignal's of 'Bool'
not1 :: CSignal clk Bool -> CSignal clk Bool
not1 = fmap not
{-# NOINLINE register# #-}
register# :: SClock clk -> a -> CSignal clk a -> CSignal clk a
register# _ i s = i :- s
{-# NOINLINE regEn# #-}
regEn# :: SClock clk -> a -> CSignal clk Bool -> CSignal clk a -> CSignal clk a
regEn# clk i b s = r
where
r = register# clk i s'
s' = mux b s r
{-# INLINE mux #-}
-- | A multiplexer. Given "@'mux' b t f@", output @t@ when @b@ is 'True', and @f@
-- when @b@ is 'False'.
mux :: CSignal clk Bool -> CSignal clk a -> CSignal clk a -> CSignal clk a
mux = liftA3 (\b t f -> if b then t else f)
instance Bounded a => Bounded (CSignal clk a) where
minBound = signal# minBound
maxBound = signal# maxBound
instance ExtendingNum a b => ExtendingNum (CSignal clk a) (CSignal clk b) where
type AResult (CSignal clk a) (CSignal clk b) = CSignal clk (AResult a b)
plus = liftA2 plus
minus = liftA2 minus
type MResult (CSignal clk a) (CSignal clk b) = CSignal clk (MResult a b)
times = liftA2 times
instance SaturatingNum a => SaturatingNum (CSignal clk a) where
satPlus s = liftA2 (satPlus s)
satMin s = liftA2 (satMin s)
satMult s = liftA2 (satMult s)
-- | __WARNING__: ('==') and ('/=') are undefined, use ('.==.') and ('./=.')
-- instead
instance Eq (CSignal clk a) where
(==) = error "(==)' undefined for 'CSignal', use '(.==.)' instead"
(/=) = error "(/=)' undefined for 'CSignal', use '(./=.)' instead"
infix 4 .==.
-- | Version of ('==') that returns a 'CSignal' of 'Bool'
(.==.) :: Eq a => CSignal clk a -> CSignal clk a -> CSignal clk Bool
(.==.) = liftA2 (==)
infix 4 ./=.
-- | Version of ('/=') that returns a 'CSignal' of 'Bool'
(./=.) :: Eq a => CSignal clk a -> CSignal clk a -> CSignal clk Bool
(./=.) = liftA2 (/=)
-- | __WARNING__: 'compare', ('<'), ('>='), ('>'), and ('<=') are
-- undefined, use 'compare1', ('.<.'), ('.>=.'), ('.>.'), and ('.<=.') instead
instance Ord a => Ord (CSignal clk a) where
compare = error "'compare' undefined for 'CSignal', use 'compare1' instead"
(<) = error "'(<)' undefined for 'CSignal', use '(.<.)' instead"
(>=) = error "'(>=)' undefined for 'CSignal', use '(.>=.)' instead"
(>) = error "'(>)' undefined for 'CSignal', use '(.>.)' instead"
(<=) = error "'(<=)' undefined for 'CSignal', use '(.<=.)' instead"
max = liftA2 max
min = liftA2 min
-- | Version of 'compare' that returns a 'CSignal' of 'Ordering'
compare1 :: Ord a => CSignal clk a -> CSignal clk a -> CSignal clk Ordering
compare1 = liftA2 compare
infix 4 .<.
-- | Version of ('<') that returns a 'CSignal' of 'Bool'
(.<.) :: Ord a => CSignal clk a -> CSignal clk a -> CSignal clk Bool
(.<.) = liftA2 (<)
infix 4 .<=.
-- | Version of ('<=') that returns a 'CSignal' of 'Bool'
(.<=.) :: Ord a => CSignal clk a -> CSignal clk a -> CSignal clk Bool
(.<=.) = liftA2 (<=)
infix 4 .>.
-- | Version of ('>') that returns a 'CSignal' of 'Bool'
(.>.) :: Ord a => CSignal clk a -> CSignal clk a -> CSignal clk Bool
(.>.) = liftA2 (>)
infix 4 .>=.
-- | Version of ('>=') that returns a 'CSignal' of 'Bool'
(.>=.) :: Ord a => CSignal clk a -> CSignal clk a -> CSignal clk Bool
(.>=.) = liftA2 (>=)
-- | __WARNING__: 'fromEnum' is undefined, use 'fromEnum1' instead
instance Enum a => Enum (CSignal clk a) where
succ = fmap succ
pred = fmap pred
toEnum = signal# . toEnum
fromEnum = error "'fromEnum' undefined for 'CSignal', use 'fromEnum1'"
enumFrom = sequenceA . fmap enumFrom
enumFromThen = (sequenceA .) . liftA2 enumFromThen
enumFromTo = (sequenceA .) . liftA2 enumFromTo
enumFromThenTo = ((sequenceA .) .) . liftA3 enumFromThenTo
-- | Version of 'fromEnum' that returns a 'CSignal' of 'Int'
fromEnum1 :: Enum a => CSignal clk a -> CSignal clk Int
fromEnum1 = fmap fromEnum
-- | __WARNING__: 'toRational' is undefined, use 'toRational1' instead
instance (Num a, Ord a) => Real (CSignal clk a) where
toRational = error "'toRational' undefined for 'CSignal', use 'toRational1'"
-- | Version of 'toRational' that returns a 'CSignal' of 'Rational'
toRational1 :: Real a => CSignal clk a -> CSignal clk Rational
toRational1 = fmap toRational
-- | __WARNING__: 'toInteger' is undefined, use 'toInteger1' instead
instance Integral a => Integral (CSignal clk a) where
quot = liftA2 quot
rem = liftA2 rem
div = liftA2 div
mod = liftA2 mod
quotRem a b = (quot a b, rem a b)
divMod a b = (div a b, mod a b)
toInteger = error "'toInteger' undefined for 'CSignal', use 'toInteger1'"
-- | Version of 'toRational' that returns a 'CSignal' of 'Integer'
toInteger1 :: Integral a => CSignal clk a -> CSignal clk Integer
toInteger1 = fmap toInteger
-- | __WARNING__: 'testBit' and 'popCount' are undefined, use 'testBit1' and
-- 'popCount1' instead
instance Bits a => Bits (CSignal clk a) where
(.&.) = liftA2 (.&.)
(.|.) = liftA2 (.|.)
xor = liftA2 xor
complement = fmap complement
shift a i = fmap (`shift` i) a
rotate a i = fmap (`rotate` i) a
zeroBits = signal# zeroBits
bit = signal# . bit
setBit a i = fmap (`setBit` i) a
clearBit a i = fmap (`clearBit` i) a
testBit = error "'testBit' undefined for 'CSignal', use 'testbit1'"
bitSizeMaybe _ = bitSizeMaybe (undefined :: a)
bitSize _ = bitSize (undefined :: a)
isSigned _ = isSigned (undefined :: a)
shiftL a i = fmap (`shiftL` i) a
unsafeShiftL a i = fmap (`unsafeShiftL` i) a
shiftR a i = fmap (`shiftR` i) a
unsafeShiftR a i = fmap (`unsafeShiftR` i) a
rotateL a i = fmap (`rotateL` i) a
rotateR a i = fmap (`rotateR` i) a
popCount = error "'popCount' undefined for 'CSignal', use 'popCount1'"
instance FiniteBits a => FiniteBits (CSignal clk a) where
finiteBitSize _ = finiteBitSize (undefined :: a)
-- | Version of 'testBit' that has a 'CSignal' of 'Int' as indexing argument,
-- and a result of 'CSignal' of 'Bool'
testBit1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk Bool
testBit1 = liftA2 testBit
-- | Version of 'popCount' that returns a 'CSignal' of 'Int'
popCount1 :: Bits a => CSignal clk a -> CSignal clk Int
popCount1 = fmap popCount
-- | Version of 'shift' that has a 'CSignal' of 'Int' as indexing argument
shift1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
shift1 = liftA2 shift
-- | Version of 'rotate' that has a 'CSignal' of 'Int' as indexing argument
rotate1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
rotate1 = liftA2 rotate
-- | Version of 'setBit' that has a 'CSignal' of 'Int' as indexing argument
setBit1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
setBit1 = liftA2 setBit
-- | Version of 'clearBit' that has a 'CSignal' of 'Int' as indexing argument
clearBit1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
clearBit1 = liftA2 clearBit
-- | Version of 'shiftL' that has a 'CSignal' of 'Int' as indexing argument
shiftL1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
shiftL1 = liftA2 shiftL
-- | Version of 'unsafeShiftL' that has a 'CSignal' of 'Int' as indexing argument
unsafeShiftL1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
unsafeShiftL1 = liftA2 unsafeShiftL
-- | Version of 'shiftR' that has a 'CSignal' of 'Int' as indexing argument
shiftR1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
shiftR1 = liftA2 shiftR
-- | Version of 'unsafeShiftR' that has a 'CSignal' of 'Int' as indexing argument
unsafeShiftR1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
unsafeShiftR1 = liftA2 unsafeShiftR
-- | Version of 'rotateL' that has a 'CSignal' of 'Int' as indexing argument
rotateL1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
rotateL1 = liftA2 rotateL
-- | Version of 'rotateR' that has a 'CSignal' of 'Int' as indexing argument
rotateR1 :: Bits a => CSignal clk a -> CSignal clk Int -> CSignal clk a
rotateR1 = liftA2 rotateR
instance Fractional a => Fractional (CSignal clk a) where
(/) = liftA2 (/)
recip = fmap recip
fromRational = signal# . fromRational