packages feed

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 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 #-}