{-# LANGUAGE RankNTypes, TypeFamilies, ScopedTypeVariables #-} -- | The 'Clock' module provides a utility function for simulating clock rate -- downsampling. module Hardware.KansasLava.Rate(rate, powerOfTwoRate, rateP, throttleP) where import Data.Ratio import Data.Sized.Unsigned import Data.Sized.Signed import Data.Sized.Ix import Language.KansasLava -- | 'rate' constructs a stream of enable bits used for clock-rate -- downsampling. For example, with a rate of n=1/2, every other value in the -- output stream will be True. If 1/n is not a integer, then the function uses -- http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm to approximate the -- given rate. rate :: forall x clk . (Clock clk, Size x) => Witness x -> Rational -> (Signal clk Bool) rate Witness n | step > 2^sz = error \$ "bit-size " ++ show sz ++ " too small for punctuate Witness " ++ show n | n <= 0 = error "can not have rate less than or equal zero" | n > 1 = error \$ "can not have rate greater than 1, requesting " ++ show n -- for power of two, a simple counter works | num == 1 && step == 2^sz = runRTL \$ do count <- newReg (0 :: (Unsigned x)) count := reg count + 1 return (reg count .==. 0) | num == 1 = runRTL \$ do count <- newReg (0 :: (Unsigned x)) CASE [ IF (reg count .<. (fromIntegral step - 1)) \$ count := reg count + 1 , OTHERWISE \$ do count := 0 ] return (reg count .==. 0) -- inexact reciprocal, so use Bresenham's to approximate things. | otherwise = runRTL \$ do count <- newReg (0 :: (Unsigned x)) cut <- newReg (0 :: (Unsigned x)) err <- newReg (0 :: (Signed x)) CASE [ IF (reg count .<. (fromIntegral step + reg cut - 1)) \$ count := reg count + 1 , OTHERWISE \$ do count := 0 CASE [ IF (reg err .>. 0) \$ do cut := 1 err := reg err + fromIntegral nerr , OTHERWISE \$ do cut := 0 err := reg err + fromIntegral perr ] ] return (reg count .==. 0) where sz :: Integer sz = fromIntegral (size (error "witness" :: x)) num = numerator n dom = denominator n step = floor (1 / n) perr = dom - step * num nerr = dom - (step + 1) * num -- | 'powerOfTwoRate' generates a pulse every 2^n cycles, which is often good enough for polling, timeouts, etc. powerOfTwoRate :: forall x clk . (Clock clk, Size x) => Witness x -> Signal clk Bool powerOfTwoRate Witness = rate (Witness :: Witness x) (1/(2^(fromIntegral (size (error "Witness" :: x))))) -- | 'rateP' takes a result from rate, and generates token, one per pulse, with -- unused tokens being discared. rateP :: forall c sig . (Clock c, sig ~ Signal c) => sig Bool -> Patch () (sig (Enabled ())) () (sig Ack) rateP r = outputP (packEnabled r \$ pureS ()) \$\$ enabledToAckBox -- | 'throttleP' throttles input based on a given rate counter. throttleP :: forall sig c a x . (sig ~ Signal c, Clock c, Rep a) => sig Bool -> Patch (sig (Enabled a)) (sig (Enabled a)) (sig Ack) (sig Ack) throttleP in_pred = openP \$\$ (top `stackP` emptyP) \$\$ zipP \$\$ mapP (\ ab -> snd (unpack ab)) where top = outputP (packEnabled in_pred (pureS ())) \$\$ enabledToAckBox {- -- Wrong, omit for this release. -- -- | 'accurateTo' rounds up/down a number within a range, -- in an attempt to be a integral reciprical (and therefore cheaper to implement in hardware). --accurateTo :: Rational -> Rational -> Rational accurateTo n ac | diff > (1-ac) = error \$ "can not find tolerance for " ++ show n ++ " : need " ++ show (fromRational (1 - diff) :: Float) | otherwise = nR where reci = 1 / n nR = 1 / (fromInteger \$ round reci) diff = abs (n - nR) -}