{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -fplugin=GHC.TypeLits.Normalise #-}
{-# OPTIONS_GHC -fplugin=GHC.TypeLits.KnownNat.Solver #-}
module Clash.Explicit.Reset
(
resetSynchronizer
, resetGlitchFilter
, holdReset
, convertReset
, Reset
, resetGen
, resetGenN
, resetKind
, systemResetGen
, unsafeToReset
, unsafeFromReset
, unsafeToHighPolarity
, unsafeToLowPolarity
, unsafeFromHighPolarity
, unsafeFromLowPolarity
) where
import Data.Bits (testBit, shiftL, (.|.))
import Data.Type.Equality ((:~:)(Refl))
import GHC.Generics (Generic)
import Clash.Class.BitPack (pack)
import Clash.Class.Resize (resize)
import Clash.Class.Num (satSucc, SaturationMode(SatBound))
import Clash.Explicit.Mealy
import Clash.Explicit.Signal
import Clash.Promoted.Nat
import Clash.Signal.Internal
import Clash.Sized.BitVector (BitVector)
import Clash.Sized.Index (Index)
import Clash.XException (NFDataX, ShowX)
import GHC.TypeLits (type (+), KnownNat)
resetSynchronizer
:: forall dom
. KnownDomain dom
=> Clock dom
-> Reset dom
-> Enable dom
-> Reset dom
resetSynchronizer :: Clock dom -> Reset dom -> Enable dom -> Reset dom
resetSynchronizer Clock dom
clk Reset dom
rst Enable dom
_ = Reset dom
rstOut
where
isActiveHigh :: Bool
isActiveHigh = case forall (dom :: Domain) (polarity :: ResetPolarity).
(KnownDomain dom, DomainResetPolarity dom ~ polarity) =>
SResetPolarity polarity
forall (polarity :: ResetPolarity).
(KnownDomain dom,
DomainConfigurationResetPolarity (KnownConf dom) ~ polarity) =>
SResetPolarity polarity
resetPolarity @dom of { SResetPolarity (DomainConfigurationResetPolarity (KnownConf dom))
SActiveHigh -> Bool
True; SResetPolarity (DomainConfigurationResetPolarity (KnownConf dom))
_ -> Bool
False }
rstOut :: Reset dom
rstOut =
case (forall (dom :: Domain) (sync :: ResetKind).
(KnownDomain dom, DomainResetKind dom ~ sync) =>
SResetKind sync
forall (sync :: ResetKind).
(KnownDomain dom,
DomainConfigurationResetKind (KnownConf dom) ~ sync) =>
SResetKind sync
resetKind @dom) of
SResetKind (DomainConfigurationResetKind (KnownConf dom))
SAsynchronous -> Signal dom Bool -> Reset dom
forall (dom :: Domain). Signal dom Bool -> Reset dom
unsafeToReset
(Signal dom Bool -> Reset dom) -> Signal dom Bool -> Reset dom
forall a b. (a -> b) -> a -> b
$ Clock dom
-> Reset dom
-> Enable dom
-> Bool
-> Signal dom Bool
-> Signal dom Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register Clock dom
clk Reset dom
rst Enable dom
forall (dom :: Domain). Enable dom
enableGen Bool
isActiveHigh
(Signal dom Bool -> Signal dom Bool)
-> Signal dom Bool -> Signal dom Bool
forall a b. (a -> b) -> a -> b
$ Clock dom
-> Reset dom
-> Enable dom
-> Bool
-> Signal dom Bool
-> Signal dom Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register Clock dom
clk Reset dom
rst Enable dom
forall (dom :: Domain). Enable dom
enableGen Bool
isActiveHigh
(Signal dom Bool -> Signal dom Bool)
-> Signal dom Bool -> Signal dom Bool
forall a b. (a -> b) -> a -> b
$ Bool -> Signal dom Bool
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Bool -> Bool
not Bool
isActiveHigh)
SResetKind (DomainConfigurationResetKind (KnownConf dom))
SSynchronous -> Signal dom Bool -> Reset dom
forall (dom :: Domain). Signal dom Bool -> Reset dom
unsafeToReset
(Signal dom Bool -> Reset dom) -> Signal dom Bool -> Reset dom
forall a b. (a -> b) -> a -> b
$ Clock dom
-> Enable dom -> Bool -> Signal dom Bool -> Signal dom Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
delay Clock dom
clk Enable dom
forall (dom :: Domain). Enable dom
enableGen Bool
isActiveHigh
(Signal dom Bool -> Signal dom Bool)
-> Signal dom Bool -> Signal dom Bool
forall a b. (a -> b) -> a -> b
$ Clock dom
-> Enable dom -> Bool -> Signal dom Bool -> Signal dom Bool
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
delay Clock dom
clk Enable dom
forall (dom :: Domain). Enable dom
enableGen Bool
isActiveHigh
(Signal dom Bool -> Signal dom Bool)
-> Signal dom Bool -> Signal dom Bool
forall a b. (a -> b) -> a -> b
$ Reset dom -> Signal dom Bool
forall (dom :: Domain). Reset dom -> Signal dom Bool
unsafeFromReset Reset dom
rst
{-# NOINLINE resetSynchronizer #-}
data GlitchFilterState = Idle | InReset
deriving ((forall x. GlitchFilterState -> Rep GlitchFilterState x)
-> (forall x. Rep GlitchFilterState x -> GlitchFilterState)
-> Generic GlitchFilterState
forall x. Rep GlitchFilterState x -> GlitchFilterState
forall x. GlitchFilterState -> Rep GlitchFilterState x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep GlitchFilterState x -> GlitchFilterState
$cfrom :: forall x. GlitchFilterState -> Rep GlitchFilterState x
Generic, HasCallStack => String -> GlitchFilterState
GlitchFilterState -> Bool
GlitchFilterState -> ()
GlitchFilterState -> GlitchFilterState
(HasCallStack => String -> GlitchFilterState)
-> (GlitchFilterState -> Bool)
-> (GlitchFilterState -> GlitchFilterState)
-> (GlitchFilterState -> ())
-> NFDataX GlitchFilterState
forall a.
(HasCallStack => String -> a)
-> (a -> Bool) -> (a -> a) -> (a -> ()) -> NFDataX a
rnfX :: GlitchFilterState -> ()
$crnfX :: GlitchFilterState -> ()
ensureSpine :: GlitchFilterState -> GlitchFilterState
$censureSpine :: GlitchFilterState -> GlitchFilterState
hasUndefined :: GlitchFilterState -> Bool
$chasUndefined :: GlitchFilterState -> Bool
deepErrorX :: String -> GlitchFilterState
$cdeepErrorX :: HasCallStack => String -> GlitchFilterState
NFDataX, Int -> GlitchFilterState -> ShowS
[GlitchFilterState] -> ShowS
GlitchFilterState -> String
(Int -> GlitchFilterState -> ShowS)
-> (GlitchFilterState -> String)
-> ([GlitchFilterState] -> ShowS)
-> Show GlitchFilterState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [GlitchFilterState] -> ShowS
$cshowList :: [GlitchFilterState] -> ShowS
show :: GlitchFilterState -> String
$cshow :: GlitchFilterState -> String
showsPrec :: Int -> GlitchFilterState -> ShowS
$cshowsPrec :: Int -> GlitchFilterState -> ShowS
Show, Int -> GlitchFilterState -> ShowS
[GlitchFilterState] -> ShowS
GlitchFilterState -> String
(Int -> GlitchFilterState -> ShowS)
-> (GlitchFilterState -> String)
-> ([GlitchFilterState] -> ShowS)
-> ShowX GlitchFilterState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> ShowX a
showListX :: [GlitchFilterState] -> ShowS
$cshowListX :: [GlitchFilterState] -> ShowS
showX :: GlitchFilterState -> String
$cshowX :: GlitchFilterState -> String
showsPrecX :: Int -> GlitchFilterState -> ShowS
$cshowsPrecX :: Int -> GlitchFilterState -> ShowS
ShowX)
resetGlitchFilter
:: forall dom glitchlessPeriod n
. ( KnownDomain dom
, glitchlessPeriod ~ (n + 1) )
=> SNat glitchlessPeriod
-> Clock dom
-> Reset dom
-> Reset dom
resetGlitchFilter :: SNat glitchlessPeriod -> Clock dom -> Reset dom -> Reset dom
resetGlitchFilter SNat glitchlessPeriod
SNat Clock dom
clk Reset dom
rst =
Signal dom Bool -> Reset dom
forall (dom :: Domain). Signal dom Bool -> Reset dom
unsafeToReset (Clock dom
-> Reset dom
-> Enable dom
-> (GlitchFilterState
-> BitVector glitchlessPeriod -> (GlitchFilterState, Bool))
-> GlitchFilterState
-> Signal dom (BitVector glitchlessPeriod)
-> Signal dom Bool
forall (dom :: Domain) s i o.
(KnownDomain dom, NFDataX s) =>
Clock dom
-> Reset dom
-> Enable dom
-> (s -> i -> (s, o))
-> s
-> Signal dom i
-> Signal dom o
mealy Clock dom
clk Reset dom
noReset Enable dom
forall (dom :: Domain). Enable dom
enableGen GlitchFilterState
-> BitVector glitchlessPeriod -> (GlitchFilterState, Bool)
go GlitchFilterState
Idle Signal dom (BitVector glitchlessPeriod)
shiftReg)
where
shiftReg :: Signal dom (BitVector glitchlessPeriod)
shiftReg =
Clock dom
-> Enable dom
-> BitVector glitchlessPeriod
-> Signal dom (BitVector glitchlessPeriod)
-> Signal dom (BitVector glitchlessPeriod)
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom -> Enable dom -> a -> Signal dom a -> Signal dom a
delay Clock dom
clk Enable dom
forall (dom :: Domain). Enable dom
enableGen BitVector glitchlessPeriod
noGlitch (BitVector glitchlessPeriod -> Bool -> BitVector glitchlessPeriod
forall (m :: Nat).
KnownNat m =>
BitVector (m + 1) -> Bool -> BitVector (m + 1)
shiftInLsb (BitVector glitchlessPeriod -> Bool -> BitVector glitchlessPeriod)
-> Signal dom (BitVector glitchlessPeriod)
-> Signal dom (Bool -> BitVector glitchlessPeriod)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (BitVector glitchlessPeriod)
shiftReg Signal dom (Bool -> BitVector glitchlessPeriod)
-> Signal dom Bool -> Signal dom (BitVector glitchlessPeriod)
forall (f :: Type -> Type) a b.
Applicative f =>
f (a -> b) -> f a -> f b
<*> Reset dom -> Signal dom Bool
forall (dom :: Domain). Reset dom -> Signal dom Bool
unsafeFromReset Reset dom
rst)
go :: GlitchFilterState
-> BitVector glitchlessPeriod -> (GlitchFilterState, Bool)
go GlitchFilterState
gfs BitVector glitchlessPeriod
sreg
| BitVector glitchlessPeriod
sreg BitVector glitchlessPeriod -> BitVector glitchlessPeriod -> Bool
forall a. Eq a => a -> a -> Bool
== BitVector glitchlessPeriod
noGlitch = (GlitchFilterState
InReset, Bool
asserted)
| GlitchFilterState
Idle <- GlitchFilterState
gfs = (GlitchFilterState
Idle, Bool -> Bool
not Bool
asserted)
| Bool
otherwise = (if Bool
msb Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool
asserted then GlitchFilterState
InReset else GlitchFilterState
Idle, Bool
msb)
where
msb :: Bool
msb = BitVector glitchlessPeriod -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit BitVector glitchlessPeriod
sreg (forall a. (Num a, KnownNat n) => a
forall (n :: Nat) a. (Num a, KnownNat n) => a
natToNum @n)
noGlitch :: BitVector glitchlessPeriod
noGlitch :: BitVector glitchlessPeriod
noGlitch = if Bool
asserted then BitVector glitchlessPeriod
forall a. Bounded a => a
maxBound else BitVector glitchlessPeriod
forall a. Bounded a => a
minBound
noReset :: Reset dom
noReset :: Reset dom
noReset = Signal dom Bool -> Reset dom
forall (dom :: Domain). Signal dom Bool -> Reset dom
unsafeToReset (Bool -> Signal dom Bool
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Bool -> Bool
not Bool
asserted))
asserted :: Bool
asserted :: Bool
asserted =
case forall (dom :: Domain) (polarity :: ResetPolarity).
(KnownDomain dom, DomainResetPolarity dom ~ polarity) =>
SResetPolarity polarity
forall (polarity :: ResetPolarity).
(KnownDomain dom,
DomainConfigurationResetPolarity (KnownConf dom) ~ polarity) =>
SResetPolarity polarity
resetPolarity @dom of
SResetPolarity (DomainConfigurationResetPolarity (KnownConf dom))
SActiveHigh -> Bool
True
SResetPolarity (DomainConfigurationResetPolarity (KnownConf dom))
SActiveLow -> Bool
False
shiftInLsb :: forall m. KnownNat m => BitVector (m + 1) -> Bool -> BitVector (m + 1)
shiftInLsb :: BitVector (m + 1) -> Bool -> BitVector (m + 1)
shiftInLsb BitVector (m + 1)
bv Bool
s = BitVector (m + 1) -> Int -> BitVector (m + 1)
forall a. Bits a => a -> Int -> a
shiftL BitVector (m + 1)
bv Int
1 BitVector (m + 1) -> BitVector (m + 1) -> BitVector (m + 1)
forall a. Bits a => a -> a -> a
.|. BitVector 1 -> BitVector (m + 1)
forall (f :: Nat -> Type) (a :: Nat) (b :: Nat).
(Resize f, KnownNat a, KnownNat b) =>
f a -> f b
resize (Bool -> BitVector (BitSize Bool)
forall a. BitPack a => a -> BitVector (BitSize a)
pack Bool
s)
{-# NOINLINE resetGlitchFilter #-}
holdReset
:: forall dom n
. KnownDomain dom
=> Clock dom
-> Enable dom
-> SNat n
-> Reset dom
-> Reset dom
holdReset :: Clock dom -> Enable dom -> SNat n -> Reset dom -> Reset dom
holdReset Clock dom
clk Enable dom
en SNat n
SNat Reset dom
rst =
Signal dom Bool -> Reset dom
forall (dom :: Domain).
KnownDomain dom =>
Signal dom Bool -> Reset dom
unsafeFromHighPolarity ((Index (n + 1) -> Index (n + 1) -> Bool
forall a. Eq a => a -> a -> Bool
/=Index (n + 1)
forall a. Bounded a => a
maxBound) (Index (n + 1) -> Bool)
-> Signal dom (Index (n + 1)) -> Signal dom Bool
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (Index (n + 1))
counter)
where
counter :: Signal dom (Index (n+1))
counter :: Signal dom (Index (n + 1))
counter = Clock dom
-> Reset dom
-> Enable dom
-> Index (n + 1)
-> Signal dom (Index (n + 1))
-> Signal dom (Index (n + 1))
forall (dom :: Domain) a.
(KnownDomain dom, NFDataX a) =>
Clock dom
-> Reset dom -> Enable dom -> a -> Signal dom a -> Signal dom a
register Clock dom
clk Reset dom
rst Enable dom
en Index (n + 1)
0 (SaturationMode -> Index (n + 1) -> Index (n + 1)
forall a. SaturatingNum a => SaturationMode -> a -> a
satSucc SaturationMode
SatBound (Index (n + 1) -> Index (n + 1))
-> Signal dom (Index (n + 1)) -> Signal dom (Index (n + 1))
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal dom (Index (n + 1))
counter)
convertReset
:: forall domA domB
. ( KnownDomain domA
, KnownDomain domB
)
=> Clock domA
-> Clock domB
-> Reset domA
-> Reset domB
convertReset :: Clock domA -> Clock domB -> Reset domA -> Reset domB
convertReset Clock domA
clkA Clock domB
clkB Reset domA
rstA0 = Reset domB
rstA2
where
rstA1 :: Reset domB
rstA1 = Signal domB Bool -> Reset domB
forall (dom :: Domain). Signal dom Bool -> Reset dom
unsafeToReset (Clock domA -> Clock domB -> Signal domA Bool -> Signal domB Bool
forall (dom1 :: Domain) (dom2 :: Domain) a.
(KnownDomain dom1, KnownDomain dom2) =>
Clock dom1 -> Clock dom2 -> Signal dom1 a -> Signal dom2 a
unsafeSynchronizer Clock domA
clkA Clock domB
clkB (Reset domA -> Signal domA Bool
forall (dom :: Domain). Reset dom -> Signal dom Bool
unsafeFromReset Reset domA
rstA0))
rstA2 :: Reset domB
rstA2 =
case ((KnownDomain domA, KnownDomain domB) => Maybe (domA :~: domB)
forall (domA :: Domain) (domB :: Domain).
(KnownDomain domA, KnownDomain domB) =>
Maybe (domA :~: domB)
sameDomain @domA @domB) of
Just domA :~: domB
Refl -> Reset domA
Reset domB
rstA0
Maybe (domA :~: domB)
Nothing -> Clock domB -> Reset domB -> Enable domB -> Reset domB
forall (dom :: Domain).
KnownDomain dom =>
Clock dom -> Reset dom -> Enable dom -> Reset dom
resetSynchronizer Clock domB
clkB Reset domB
rstA1 Enable domB
forall (dom :: Domain). Enable dom
enableGen