{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
#if __GLASGOW_HASKELL__ < 806
{-# LANGUAGE TypeInType #-}
#endif
{-# OPTIONS_GHC -fplugin=GHC.TypeLits.Extra.Solver #-}
{-# OPTIONS_GHC -fplugin=GHC.TypeLits.Normalise #-}
{-# OPTIONS_GHC -fplugin=GHC.TypeLits.KnownNat.Solver #-}
module Clash.Signal.BiSignal (
BiSignalIn()
, BiSignalOut()
, BiSignalDefault(..)
, mergeBiSignalOuts
, readFromBiSignal
, writeToBiSignal
, veryUnsafeToBiSignalIn
) where
import Data.Kind (Type)
import Data.List (intercalate)
import Data.Maybe (fromMaybe,isJust)
import Clash.Class.HasDomain
import Clash.Class.BitPack (BitPack (..))
import Clash.Sized.BitVector (BitVector)
import qualified Clash.Sized.Vector as V
import Clash.Sized.Vector (Vec)
import Clash.Signal.Internal (Signal(..), Domain, head#, tail#)
import Clash.XException (errorX, fromJustX)
import GHC.TypeLits (KnownNat, Nat)
import GHC.Stack (HasCallStack)
import Data.Reflection (Given (..))
data BiSignalDefault
= PullUp
| PullDown
| Floating
deriving (Show)
data SBiSignalDefault :: BiSignalDefault -> Type where
SPullUp :: SBiSignalDefault 'PullUp
SPullDown :: SBiSignalDefault 'PullDown
SFloating :: SBiSignalDefault 'Floating
instance Given (SBiSignalDefault 'PullUp) where
given = SPullUp
instance Given (SBiSignalDefault 'PullDown) where
given = SPullDown
instance Given (SBiSignalDefault 'Floating) where
given = SFloating
data BiSignalIn (ds :: BiSignalDefault) (dom :: Domain) (n :: Nat)
= BiSignalIn (SBiSignalDefault ds) (Signal dom (Maybe (BitVector n)))
newtype BiSignalOut (ds :: BiSignalDefault) (dom :: Domain) (n :: Nat)
= BiSignalOut [Signal dom (Maybe (BitVector n))]
type instance HasDomain dom1 (BiSignalOut ds dom2 n) = DomEq dom1 dom2
type instance TryDomain t (BiSignalOut ds dom n) = 'Found dom
instance Semigroup (BiSignalOut defaultState dom n) where
(BiSignalOut b1) <> (BiSignalOut b2) = BiSignalOut (b1 ++ b2)
instance Monoid (BiSignalOut defaultState dom n) where
mempty = BiSignalOut []
prepend#
:: Given (SBiSignalDefault ds)
=> Maybe (BitVector n)
-> BiSignalIn ds d n
-> BiSignalIn ds d n
prepend# a ~(BiSignalIn _ as) = BiSignalIn given (a :- as)
readFromBiSignal#
:: ( HasCallStack
, KnownNat n)
=> BiSignalIn ds d n
-> Signal d (BitVector n)
readFromBiSignal# (BiSignalIn ds s) =
case ds of
SFloating -> fromMaybe (errorX " undefined value on BiSignalIn") <$> s
SPullDown -> fromMaybe minBound <$> s
SPullUp -> fromMaybe maxBound <$> s
{-# NOINLINE readFromBiSignal# #-}
readFromBiSignal
:: ( HasCallStack
, BitPack a)
=> BiSignalIn ds d (BitSize a)
-> Signal d a
readFromBiSignal = fmap unpack . readFromBiSignal#
mergeBiSignalOuts
:: ( HasCallStack
, KnownNat n
)
=> Vec n (BiSignalOut defaultState dom m)
-> BiSignalOut defaultState dom m
mergeBiSignalOuts = mconcat . V.toList
{-# NOINLINE mergeBiSignalOuts #-}
writeToBiSignal#
:: HasCallStack
=> BiSignalIn ds d n
-> Signal d (Maybe (BitVector n))
-> Signal d Bool
-> Signal d (BitVector n)
-> BiSignalOut ds d n
writeToBiSignal# _ maybeSignal _ _ = BiSignalOut [maybeSignal]
{-# NOINLINE writeToBiSignal# #-}
writeToBiSignal
:: (HasCallStack, BitPack a)
=> BiSignalIn ds d (BitSize a)
-> Signal d (Maybe a)
-> BiSignalOut ds d (BitSize a)
writeToBiSignal input writes =
writeToBiSignal#
input
(fmap pack <$> writes)
(isJust <$> writes)
(pack . fromJustX <$> writes)
{-# INLINE writeToBiSignal #-}
veryUnsafeToBiSignalIn
:: ( HasCallStack
, KnownNat n
, Given (SBiSignalDefault ds)
)
=> BiSignalOut ds d n
-> BiSignalIn ds d n
veryUnsafeToBiSignalIn (BiSignalOut signals) = prepend# result biSignalOut'
where
result = case filter (isJust . head#) signals of
[] -> Nothing
[w] -> head# w
_ -> errorX err
err = unwords
[ "Multiple components wrote to the BiSignal. This is undefined behavior"
, "in hardware and almost certainly a logic error. The components wrote:\n"
, intercalate "\n " (map (show . head#) signals)
]
biSignalOut' = veryUnsafeToBiSignalIn $ BiSignalOut $ map tail# signals
{-# NOINLINE veryUnsafeToBiSignalIn #-}