{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, TypeFamilies, TypeSynonymInstances, FlexibleInstances, GADTs, RankNTypes, UndecidableInstances #-} -- | The 'Enabled' module allows the construction of circuits that use -- additional control logic -- an enable signal -- that externalizes whether a -- data signal is valid. module Language.KansasLava.Protocols.Enabled (Enabled, packEnabled, unpackEnabled, enabledVal, isEnabled, mapEnabled, enabledS, disabledS, registerEnabled ) where import Language.KansasLava.Signal import Language.KansasLava.Rep import Language.KansasLava.Utils import Language.KansasLava.Types -- | Enabled is a synonym for Maybe. type Enabled a = Maybe a -- | This is lifting *Comb* because Comb is stateless, and the 'en' Bool being -- passed on assumes no history, in the 'a -> b' function. mapEnabled :: (Rep a, Rep b, sig ~ Signal clk) => (forall clk' . Signal clk' a -> Signal clk' b) -> sig (Enabled a) -> sig (Enabled b) mapEnabled f en = pack (en_bool,f en_val) where (en_bool,en_val) = unpack en -- | Lift a data signal to be an Enabled signal, that's always enabled. enabledS :: (Rep a, sig ~ Signal clk) => sig a -> sig (Enabled a) enabledS s = pack (pureS True,s) -- | Create a signal that's never enabled. disabledS :: (Rep a, sig ~ Signal clk) => sig (Enabled a) disabledS = pack (pureS False,undefinedS) -- | Combine a boolean control signal and an data signal into an enabled signal. packEnabled :: (Rep a, sig ~ Signal clk) => sig Bool -> sig a -> sig (Enabled a) packEnabled s1 s2 = pack (s1,s2) -- | Break the representation of an Enabled signal into a Bool signal (for whether the -- value is valid) and a signal for the data. unpackEnabled :: (Rep a, sig ~ Signal clk) => sig (Enabled a) -> (sig Bool, sig a) unpackEnabled = unpack -- | Drop the Enabled control from the signal. The output signal will be Rep -- unknown if the input signal is not enabled. enabledVal :: (Rep a, sig ~ Signal clk) => sig (Enabled a) -> sig a enabledVal = snd . unpackEnabled -- | Determine if the the circuit is enabled. isEnabled :: (Rep a, sig ~ Signal clk) => sig (Enabled a) -> sig Bool isEnabled = fst . unpackEnabled -- | Optionally updatable register, based on the value of the enabled signal. registerEnabled :: (Rep a, Clock clk, sig ~ Signal clk) => a -> sig (Enabled a) -> sig a registerEnabled a inp = res where res = register a $ cASE [ (isEnabled inp,enabledVal inp) ] res