Skip to content

Commit

Permalink
Implement safe PLL's
Browse files Browse the repository at this point in the history
  • Loading branch information
DigitalBrains1 committed Oct 25, 2023
1 parent 35cf9e9 commit c3233c7
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 19 deletions.
26 changes: 24 additions & 2 deletions clash-prelude/src/Clash/Clocks.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,36 @@ Maintainer : QBayLogic B.V. <[email protected]>
Generic clock related utilities.
-}

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

{-# OPTIONS_GHC "-Wno-orphans" #-}

module Clash.Clocks (Clocks(..)) where
module Clash.Clocks
( Clocks(..)
, ClocksSync(..)
, ClocksSyncCxt
, NumOutClocksSync
) where

import Clash.Clocks.Internal (Clocks(..), deriveClocksInstances)
import Clash.Clocks.Internal
(Clocks(..), ClocksSync(..), deriveClocksInstances, deriveClocksSyncInstances)
import Clash.Signal.Internal (Domain, KnownDomain)

deriveClocksInstances

type ClocksSyncCxt t (domIn :: Domain) =
( KnownDomain domIn
, ClocksSync t
, ClocksResetSynchronizerCxt t
, Clocks (ClocksSyncClocksInst t domIn)
, ClocksCxt (ClocksSyncClocksInst t domIn)
)

type NumOutClocksSync t (domIn :: Domain) =
NumOutClocks (ClocksSyncClocksInst t domIn)

deriveClocksSyncInstances
90 changes: 86 additions & 4 deletions clash-prelude/src/Clash/Clocks/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,26 @@ Maintainer : QBayLogic B.V. <[email protected]>
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

module Clash.Clocks.Internal (Clocks(..), deriveClocksInstances) where
module Clash.Clocks.Internal
( Clocks(..)
, deriveClocksInstances
, ClocksSync(..)
, deriveClocksSyncInstances
) where

import Control.Monad.Extra (concatMapM)
import Data.Kind (Constraint)
import Data.Kind (Constraint, Type)
import GHC.TypeLits (Nat)
import Language.Haskell.TH
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(..), KnownDomain, Reset, Signal, unsafeToActiveLow)
(clockGen, Clock(..), Domain, KnownDomain, Reset, Signal, unsafeFromActiveLow,
unsafeToActiveLow)

-- | __NB__: The documentation only shows instances up to /3/ output clocks. By
-- default, instances up to and including /18/ clocks will exist.
Expand Down Expand Up @@ -75,3 +83,77 @@ deriveClocksInstances = concatMapM deriveClocksInstance [1..n]
where
n | haddockOnly = 3
| otherwise = 18

-- | __NB__: The documentation only shows instances up to /3/ output clocks. By
-- default, instances up to and including /18/ clocks will exist.
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

-- Derive instance for /n/ clocks
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) |]
]
-- (Clock c1, Reset c1, Clock c2, Reset c2, ...)
instType = foldl appT (tupleT $ n * 2) $ concatMap clkAndRstTy [1..n]
domInTyVar = varT $ mkName "domIn"
clkTypes = map (\m -> [t| Clock $(clkTyVar m) |]) [1..n]
-- (Clock c1, Clock c2, ..., Signal domIn Bool)
clocksInstType = foldl appT (tupleT $ n + 1) $
clkTypes <> [ [t| Signal $domInTyVar Bool |] ]
-- (KnownDomain c1, KnownDomain c2, ...)
cxtType
| n == 1
= [t| KnownDomain $(clkTyVar 1) |]
| otherwise
= foldl appT (tupleT n) $
map (\m -> [t| KnownDomain $(clkTyVar m) |]) [1..n]

-- 'clocksResetSynchronizer' function
clkIn = mkName "clkIn"
pllLock = mkName "pllLock"
-- (c1, c2, ..., 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
]
-- (c1, r1, c2, r2, ...) where rN is the synchronized reset for clock N
funcImpl = tupE $ concatMap clkAndRstExp [1..n]

-- Derive instances for up to and including 18 clocks, except when we are
-- generating Haddock
deriveClocksSyncInstances :: DecsQ
deriveClocksSyncInstances = concatMapM deriveClocksSyncInstance [1..n]
where
n | haddockOnly = 3
| otherwise = 18
40 changes: 34 additions & 6 deletions clash-prelude/src/Clash/Intel/ClockGen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ you want to run your circuit at.
{-# LANGUAGE TypeFamilies #-}

module Clash.Intel.ClockGen
( unsafeAltpll
( altpllSync
, alteraPllSync
, unsafeAltpll
, unsafeAlteraPll
-- ** Deprecated
, altpll
Expand All @@ -40,10 +42,24 @@ module Clash.Intel.ClockGen
import GHC.TypeLits (type (<=))

import Clash.Annotations.Primitive (hasBlackBox)
import Clash.Clocks (Clocks(..))
import Clash.Clocks
(Clocks(..), ClocksSync(..), ClocksSyncCxt, NumOutClocksSync)
import Clash.Magic (setName)
import Clash.Promoted.Symbol (SSymbol)
import Clash.Signal.Internal (Signal, Clock, Reset, KnownDomain)
import Clash.Signal.Internal
(Signal, Clock, Reset, KnownDomain, HasAsynchronousReset)

altpllSync ::
forall t domIn .
( HasAsynchronousReset domIn
, ClocksSyncCxt t domIn
, NumOutClocksSync t domIn <= 5
) =>
Clock domIn ->
Reset domIn ->
t
altpllSync clkIn rstIn =
clocksResetSynchronizer (unsafeAltpll clkIn rstIn) clkIn

-- | A clock source that corresponds to the Intel/Quartus \"ALTPLL\" component
-- (Arria GX, Arria II, Stratix IV, Stratix III, Stratix II, Stratix,
Expand Down Expand Up @@ -107,7 +123,7 @@ import Clash.Signal.Internal (Signal, Clock, Reset, KnownDomain)
-- @
altpll ::
forall domOut domIn name .
( KnownDomain domIn
( HasAsynchronousReset domIn
, KnownDomain domOut
) =>
-- | Name of the component instance
Expand Down Expand Up @@ -139,6 +155,18 @@ unsafeAltpll = clocks
{-# CLASH_OPAQUE unsafeAltpll #-}
{-# ANN unsafeAltpll hasBlackBox #-}

alteraPllSync ::
forall t domIn .
( HasAsynchronousReset domIn
, ClocksSyncCxt t domIn
, NumOutClocksSync t domIn <= 18
) =>
Clock domIn ->
Reset domIn ->
t
alteraPllSync clkIn rstIn =
clocksResetSynchronizer (unsafeAlteraPll clkIn rstIn) clkIn

-- | A clock source that corresponds to the Intel/Quartus \"Altera PLL\"
-- component (Arria V, Stratix V, Cyclone V) with settings to provide a stable
-- 'Clock' from a single free-running input
Expand Down Expand Up @@ -213,8 +241,8 @@ unsafeAltpll = clocks
-- if the component doesn't need a reset).
alteraPll ::
forall t domIn name .
( Clocks t
, KnownDomain domIn
( HasAsynchronousReset domIn
, Clocks t
, ClocksCxt t
, NumOutClocks t <= 18
) =>
Expand Down
35 changes: 33 additions & 2 deletions clash-prelude/src/Clash/Xilinx/ClockGen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,32 @@ PLL and other clock-related components for Xilinx FPGAs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}

module Clash.Xilinx.ClockGen where
module Clash.Xilinx.ClockGen
( clockWizard
, clockWizardDifferential
, unsafeClockWizard
, unsafeClockWizardDifferential
) where

import GHC.TypeLits (type (<=))

import Clash.Annotations.Primitive (hasBlackBox)
import Clash.Clocks (Clocks(..))
import Clash.Clocks
(Clocks(..), ClocksSync(..), ClocksSyncCxt, NumOutClocksSync)
import Clash.Signal.Internal
(Clock, DiffClock(..), Reset, KnownDomain, HasAsynchronousReset)

clockWizard ::
forall t domIn .
( HasAsynchronousReset domIn
, ClocksSyncCxt t domIn
, NumOutClocksSync t domIn <= 7
) =>
Clock domIn ->
Reset domIn ->
t
clockWizard clkIn rstIn =
clocksResetSynchronizer (unsafeClockWizard clkIn rstIn) clkIn

-- | A clock source that corresponds to the Xilinx MMCM component created
-- with the \"Clock Wizard\" with settings to provide a stable 'Clock' from
Expand Down Expand Up @@ -50,6 +69,18 @@ unsafeClockWizard = clocks
{-# CLASH_OPAQUE unsafeClockWizard #-}
{-# ANN unsafeClockWizard hasBlackBox #-}

clockWizardDifferential ::
forall t domIn .
( HasAsynchronousReset domIn
, ClocksSyncCxt t domIn
, NumOutClocksSync t domIn <= 7
) =>
DiffClock domIn ->
Reset domIn ->
t
clockWizardDifferential clkIn@(DiffClock clkInP _) rstIn =
clocksResetSynchronizer (unsafeClockWizardDifferential clkIn rstIn) clkInP

-- | A clock source that corresponds to the Xilinx MMCM component created
-- with the \"Clock Wizard\", with settings to provide a stable 'Clock'
-- from a free-running differential clock input.
Expand Down
8 changes: 3 additions & 5 deletions tests/shouldwork/Xilinx/ClockWizard.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import Clash.Explicit.Prelude
import Clash.Explicit.Testbench
import Clash.Xilinx.ClockGen

createDomain vXilinxSystem{vName="DomIn", vPeriod=hzToPeriod 24_000_000}
createDomain vSystem{vName="DomIn", vPeriod=hzToPeriod 24_000_000}
createDomain vXilinxSystem{vName="DomOut", vPeriod=hzToPeriod 300_000_000}

topEntity ::
Expand All @@ -24,10 +24,8 @@ topEntity ::
Signal DomOut (Index 10, Index 10)
topEntity clkInSE clkInDiff rstIn =
let f clk rst = register clk rst enableGen 0 . fmap (satSucc SatBound)
(clkA, stableA) = unsafeClockWizard clkInSE rstIn
rstA = unsafeFromActiveLow stableA
(clkB, stableB) = unsafeClockWizardDifferential clkInDiff rstIn
rstB = unsafeFromActiveLow stableB
(clkA, rstA) = clockWizard clkInSE rstIn
(clkB, rstB) = clockWizardDifferential clkInDiff rstIn
o1 = f clkA rstA o1
o2 = f clkB rstB o2
in bundle (o1, o2)
Expand Down

0 comments on commit c3233c7

Please sign in to comment.