{-# LANGUAGE ConstrainedClassMethods #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
module Clash.Clocks.Internal
( Clocks(..)
, deriveClocksInstances
, ClocksSync(..)
, deriveClocksSyncInstances
) where
import Control.Monad.Extra (concatMapM)
import Data.Kind (Constraint, Type)
import GHC.TypeLits (Nat)
import Language.Haskell.TH hiding (Type)
import Clash.CPP (haddockOnly)
import Clash.Explicit.Reset (resetSynchronizer)
import Clash.Explicit.Signal (unsafeSynchronizer)
import Clash.Magic (setName)
import Clash.Promoted.Symbol (SSymbol(..))
import Clash.Signal.Internal
(clockGen, Clock(..), Domain, KnownDomain, Reset, Signal, unsafeFromActiveLow,
unsafeToActiveLow)
class Clocks t where
type ClocksCxt t :: Constraint
type NumOutClocks t :: Nat
clocks ::
(KnownDomain domIn, ClocksCxt t) =>
Clock domIn ->
Reset domIn ->
t
deriveClocksInstance :: Int -> DecsQ
deriveClocksInstance n =
[d| instance Clocks $instType where
type ClocksCxt $instType = $cxtType
type NumOutClocks $instType = $numOutClocks
clocks (Clock _ Nothing) $(varP rst) = $funcImpl
clocks _ _ = error "clocks: dynamic clocks unsupported"
{-# CLASH_OPAQUE clocks #-}
|]
where
clkTyVar m = varT $ mkName $ "c" <> show m
clkTypes = map (\m -> [t| Clock $(clkTyVar m) |]) [1..n]
lockTyVar = varT $ mkName "pllLock"
instType = foldl appT (tupleT $ n + 1) $
clkTypes <> [ [t| Signal $lockTyVar Bool |] ]
clkKnownDoms = map (\m -> [t| KnownDomain $(clkTyVar m) |]) [1..n]
cxtType = foldl appT (tupleT $ n + 1) $
clkKnownDoms <> [ [t| KnownDomain $lockTyVar |] ]
numOutClocks = litT . numTyLit $ toInteger n
rst = mkName "rst"
lockImpl = [|
unsafeSynchronizer clockGen clockGen (unsafeToActiveLow $(varE rst))
|]
clkImpls = replicate n [| Clock SSymbol Nothing |]
funcImpl = tupE $ clkImpls <> [lockImpl]
deriveClocksInstances :: DecsQ
deriveClocksInstances = concatMapM deriveClocksInstance [1..n]
where
n | haddockOnly = 3
| otherwise = 18
class ClocksSync t where
type ClocksSyncClocksInst t (domIn :: Domain) :: Type
type ClocksResetSynchronizerCxt t :: Constraint
clocksResetSynchronizer ::
( KnownDomain domIn
, ClocksResetSynchronizerCxt t
) =>
ClocksSyncClocksInst t domIn ->
Clock domIn ->
t
deriveClocksSyncInstance :: Int -> DecsQ
deriveClocksSyncInstance n =
[d|
instance ClocksSync $instType where
type ClocksSyncClocksInst $instType $domInTyVar = $clocksInstType
type ClocksResetSynchronizerCxt $instType = $cxtType
clocksResetSynchronizer pllOut $(varP clkIn) =
let $pllPat = pllOut
in $funcImpl
|]
where
clkVarName m = mkName $ "c" <> show m
clkTyVar :: Int -> TypeQ
clkTyVar = varT . clkVarName
clkAndRstTy m = [ [t| Clock $(clkTyVar m) |]
, [t| Reset $(clkTyVar m) |]
]
instType = foldl appT (tupleT $ n * 2) $ concatMap clkAndRstTy [1..n]
domInTyVar = varT $ mkName "domIn"
clkTypes = map (\m -> [t| Clock $(clkTyVar m) |]) [1..n]
clocksInstType = foldl appT (tupleT $ n + 1) $
clkTypes <> [ [t| Signal $domInTyVar Bool |] ]
cxtType
| n == 1
= [t| KnownDomain $(clkTyVar 1) |]
| otherwise
= foldl appT (tupleT n) $
map (\m -> [t| KnownDomain $(clkTyVar m) |]) [1..n]
clkIn = mkName "clkIn"
pllLock = mkName "pllLock"
pllPat = tupP $ map (varP . clkVarName) [1..n] <> [varP pllLock]
syncImpl m =
[|
setName @"resetSynchronizer" (resetSynchronizer $(varE $ clkVarName m)
(unsafeFromActiveLow
(unsafeSynchronizer $(varE clkIn) $(varE $ clkVarName m)
$(varE pllLock))))
|]
clkAndRstExp m = [ varE $ clkVarName m
, syncImpl m
]
funcImpl = tupE $ concatMap clkAndRstExp [1..n]
deriveClocksSyncInstances :: DecsQ
deriveClocksSyncInstances = concatMapM deriveClocksSyncInstance [1..n]
where
n | haddockOnly = 3
| otherwise = 18