clash-prelude 0.11.1 → 0.11.2
raw patch · 5 files changed
+112/−9 lines, 5 filesdep ~QuickCheckdep ~criteriondep ~ghc-typelits-knownnatPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: QuickCheck, criterion, ghc-typelits-knownnat
API changes (from Hackage documentation)
+ CLaSH.Prelude.Explicit.Safe: oscillate' :: forall clk n. KnownNat n => SClock clk -> Bool -> SNat n -> Signal' clk Bool
+ CLaSH.Prelude.Explicit.Safe: riseEvery' :: forall clk n. KnownNat n => SClock clk -> SNat n -> Signal' clk Bool
+ CLaSH.Prelude.Safe: oscillate :: KnownNat n => Bool -> SNat n -> Signal Bool
+ CLaSH.Prelude.Safe: riseEvery :: KnownNat n => SNat n -> Signal Bool
Files
- CHANGELOG.md +7/−0
- clash-prelude.cabal +1/−1
- src/CLaSH/Prelude/Explicit/Safe.hs +35/−3
- src/CLaSH/Prelude/Safe.hs +53/−4
- src/CLaSH/Signal/Internal.hs +16/−1
CHANGELOG.md view
@@ -1,5 +1,12 @@ # Changelog for [`clash-prelude` package](http://hackage.haskell.org/package/clash-prelude) +## 0.11.2 *April 25th 2017*+* New features:+ * Add `riseEvery`: Give a pulse every @n@ clock cycles. (Thanks to @thoughtpolice)+ * Add `oscillate`: Oscillate a @'Bool'@ with a given half-period of cycles. (Thanks to @thoughtpolice)+* Fixes bugs:+ * Eagerness bug in `regEn` [#104](https://github.com/clash-lang/clash-prelude/issues/104) (Thanks to @cbiffle)+ ## 0.11.1 *April 10th 2017* * Changes: * Bundle instance for `()` behaves like a product-type instance [#96](https://github.com/clash-lang/clash-prelude/issues/96)
clash-prelude.cabal view
@@ -1,5 +1,5 @@ Name: clash-prelude-Version: 0.11.1+Version: 0.11.2 Synopsis: CAES Language for Synchronous Hardware - Prelude library Description: CλaSH (pronounced ‘clash’) is a functional hardware description language that
src/CLaSH/Prelude/Explicit/Safe.hs view
@@ -14,9 +14,10 @@ using explicitly clocked signals. -} -{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE Safe #-} @@ -44,12 +45,15 @@ -- * Utility functions , isRising' , isFalling'+ , riseEvery'+ , oscillate' -- * Exported modules -- ** Explicitly clocked synchronous signals , module CLaSH.Signal.Explicit ) where +import GHC.TypeLits import Control.Applicative (liftA2) import Prelude hiding (repeat) @@ -60,9 +64,13 @@ import CLaSH.Prelude.ROM (rom', romPow2') import CLaSH.Prelude.Synchronizer (dualFlipFlopSynchronizer, asyncFIFOSynchronizer)+import CLaSH.Promoted.Nat (SNat(..))+import CLaSH.Sized.Index (Index) import CLaSH.Signal.Bundle (Bundle(..), Unbundled') import CLaSH.Signal.Explicit+import CLaSH.Sized.Unsigned + {- $setup >>> :set -XDataKinds >>> import CLaSH.Prelude@@ -114,3 +122,27 @@ where prev = register' clk is s edgeDetect old new = old == maxBound && new == minBound++{-# INLINEABLE riseEvery' #-}+-- | Give a pulse every @n@ clock cycles. This is a useful helper function when+-- combined with functions like @'CLaSH.Signal.regEn'@ or @'CLaSH.Signal.mux'@,+-- in order to delay a register by a known amount.+riseEvery' :: forall clk n. KnownNat n => SClock clk -> SNat n -> Signal' clk Bool+riseEvery' clk SNat = moore' clk transfer output 0 (pure ())+ where+ output :: Index n -> Bool+ output = (== maxBound)++ transfer :: Index n -> () -> Index n+ transfer s _ = if (s == maxBound) then 0 else s+1++{-# INLINEABLE oscillate' #-}+-- | Oscillate a @'Bool'@ for a given number of cycles, given the starting state.+oscillate' :: forall clk n. KnownNat n => SClock clk -> Bool -> SNat n -> Signal' clk Bool+oscillate' clk begin SNat = moore' clk transfer snd (0, begin) (pure ())+ where+ transfer :: (Index n, Bool) -> () -> (Index n, Bool)+ transfer (s, i) _ =+ if s == maxBound+ then (0, not i) -- reset state and oscillate output+ else (s+1, i) -- hold current output
src/CLaSH/Prelude/Safe.hs view
@@ -27,9 +27,9 @@ Some circuit examples can be found in "CLaSH.Examples". -} -{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE Safe #-} @@ -60,6 +60,8 @@ -- * Utility functions , isRising , isFalling+ , riseEvery+ , oscillate -- * Exported modules -- ** Synchronous signals , module CLaSH.Signal@@ -129,7 +131,8 @@ import CLaSH.Prelude.BitIndex import CLaSH.Prelude.BitReduction import CLaSH.Prelude.BlockRam (blockRam, blockRamPow2, readNew, readNew')-import CLaSH.Prelude.Explicit.Safe (registerB', isRising', isFalling')+import CLaSH.Prelude.Explicit.Safe (registerB', isRising', isFalling',+ oscillate', riseEvery') import CLaSH.Prelude.Mealy (mealy, mealyB, (<^>)) import CLaSH.Prelude.Moore (moore, mooreB) import CLaSH.Prelude.RAM (asyncRam,asyncRamPow2)@@ -192,6 +195,52 @@ -> Signal a -> Signal Bool isFalling = isFalling' systemClock++{-# INLINE riseEvery #-}+-- | Give a pulse every @n@ clock cycles. This is a useful helper function when+-- combined with functions like @'CLaSH.Signal.regEn'@ or @'CLaSH.Signal.mux'@,+-- in order to delay a register by a known amount.+--+-- To be precise: the given signal will be @'False'@ for the next @n-1@ cycles,+-- followed by a single @'True'@ value:+--+-- >>> Prelude.last (sampleN 1024 (riseEvery d1024)) == True+-- True+-- >>> Prelude.or (sampleN 1023 (riseEvery d1024)) == False+-- True+--+-- For example, to update a counter once every 10 million cycles:+--+-- @+-- counter = 'CLaSH.Signal.regEn' 0 ('riseEvery' ('SNat' :: 'SNat' 10000000)) (counter + 1)+-- @+riseEvery :: KnownNat n => SNat n -> Signal Bool+riseEvery = riseEvery' systemClock++{-# INLINE oscillate #-}+-- | Oscillate a @'Bool'@ for a given number of cycles. This is a convenient+-- function when combined with something like @'regEn'@, as it allows you to+-- easily hold a register value for a given number of cycles. The input @'Bool'@+-- determines what the initial value is.+--+-- To oscillate on an interval of 5 cycles:+--+-- >>> sampleN 10 (oscillate False d5)+-- [False,False,False,False,False,True,True,True,True,True]+--+-- To oscillate between @'True'@ and @'False'@:+--+-- >>> sampleN 10 (oscillate False d1)+-- [False,True,False,True,False,True,False,True,False,True]+--+-- An alternative definition for the above could be:+--+-- >>> let osc' = register False (not <$> osc')+-- >>> let sample' = sampleN 200+-- >>> sample' (oscillate False d1) == sample' osc'+-- True+oscillate :: KnownNat n => Bool -> SNat n -> Signal Bool+oscillate = oscillate' systemClock undefined :: HasCallStack => a undefined = errorX "undefined"
src/CLaSH/Signal/Internal.hs view
@@ -269,7 +269,22 @@ regEn# :: SClock clk -> a -> Signal' clk Bool -> Signal' clk a -> Signal' clk a regEn# _ = go where- go o (e :- es) as@(~(x :- xs)) =+ -- In order to produce the first (current) value of the register's output+ -- signal, 'o', we don't need to know the shape of either input (enable or+ -- value-in). This is important, because both values might be produced from+ -- the output in a feedback loop, so we can't know their shape (pattern+ -- match) them until we have produced output.+ --+ -- Thus, we use lazy pattern matching to delay inspecting the shape of+ -- either argument until output has been produced.+ --+ -- However, both arguments need to be evaluated to WHNF as soon as possible+ -- to avoid a space-leak. Below, we explicitly reduce the value-in signal+ -- using 'seq' as the tail of our output signal is produced. On the other+ -- hand, because the value of the tail depends on the value of the enable+ -- signal 'e', it will be forced by the 'if'/'then' statement and we don't+ -- need to 'seq' it explicitly.+ go o ~(e :- es) as@(~(x :- xs)) = o `seqX` o :- (as `seq` if e then go x es xs else go o es xs) {-# INLINE mux #-}