Periods in Clash
Periods in Clash are stored on the type level in picoseconds. You can use the DomainPeriod type to extract that information from your domain!
A couple of examples:
{-# LANGUAGE FlexibleContexts #-}
import Clash.Prelude
import Data.Proxy
-- Make some example domain with a frequency of 25 MHz.
createDomain vSystem{vPeriod = hzToPeriod 25e6, vName = "MyDomain"}
-- | A function that when given a domain, returns the period in picoseconds
domPeriod :: forall dom . KnownDomain dom => Proxy dom -> Int
domPeriod _ = natToNum @(DomainPeriod dom)
-- | A function that when given a domain, returns the period in picoseconds as a singleton
domPeriodSingleton :: forall dom . (KnownDomain dom) => Proxy dom -> SNat (DomainPeriod dom)
domPeriodSingleton _ = SNat
Now we can do:
ghci> domPeriod (Proxy @System)
10000
ghci> domPeriod (Proxy @MyDomain)
40000
The next release of clash-prelude
will also contain more type level definitions to reason about time. These were introduced in Add utilities to represent time by lmbollen · Pull Request #2734 · clash-lang/clash-compiler · GitHub.
So now we can also write:
domFrequency :: forall dom . (KnownDomain dom, 1 <= DomainPeriod dom) => Proxy dom -> Int
domFrequency _ = natToNum @(DomainToHz dom)
to extract the frequency of our domain.
ghci> domFrequency (Proxy @System)
100000000
ghci> domFrequency (Proxy @MyDomain)
25000000
Reducing the number of pulses
It seems like you are trying to implement some logic to provide a True
periodically at a certain period which is a multiple of your clock frequency.
To do that you can use the a free running counter whose maxBound
is derived from your desired period and your clock period:
-- | A pulse that goes high every @desiredPeriod@ picoseconds
periodicPulse ::
forall dom desiredPeriod . -- Bring the type variables into the scope of the function
( HiddenClockResetEnable dom -- The domain needs to have a hidden clock, reset, and enable signal
, 1 <= DomainPeriod dom -- The domain needs to have a period greater than 1 ps
, 1 <= PeriodToCycles dom desiredPeriod -- The number of cycles in the resulting period needs to be greater than 1
) =>
-- | The desired period of the pulse in picoseconds
SNat desiredPeriod ->
-- | The pulse signal
Signal dom Bool
periodicPulse SNat = pulse
where
pulse = counter .==. pure maxBound
initialCount = 0 :: Index (PeriodToCycles dom desiredPeriod)
counter = register initialCount $ satSucc SatWrap <$> counter
-- Simulate 20 samples (including once cycel of reset) of a 100ns periodic pulse
-- in the 25 MHz "MyDomain" domain
simPeriodicPulse = sampleN 20 $ periodicPulse @MyDomain (SNat @(Nanoseconds 100))
When we simulate the circuit, we see that after one cycle of reset, we get a pulse every third cycle. Remember that the period of MyDomain
was 40000 picoseconds, or 40 nanoseconds. So every three cycles means every 120 nanoseconds.
ghci> simPeriodicPulse
[False,False,False,True,False,False,True,False,False,True,False,False,True,False,False,True,False,False,True,False]