packages feed

clash-prelude 0.8.1 → 0.9

raw patch · 25 files changed

+2795/−447 lines, 25 filesdep +arrayPVP ok

version bump matches the API change (PVP)

Dependencies added: array

API changes (from Hackage documentation)

- CLaSH.Annotations.TopEntity: defClkAltera :: String -> String -> String -> ClockSource
- CLaSH.Annotations.TopEntity: defClkXilinx :: String -> String -> String -> ClockSource
- CLaSH.Sized.Internal.BitVector: mod# :: BitVector n -> BitVector n -> BitVector n
- CLaSH.Sized.Internal.Index: mod# :: Index n -> Index n -> Index n
- CLaSH.Sized.Internal.Unsigned: [unsafeToBitVector] :: Unsigned -> Integer
- CLaSH.Sized.Internal.Unsigned: mod# :: Unsigned n -> Unsigned n -> Unsigned n
+ CLaSH.Annotations.TopEntity: alteraPll :: String -> String -> String -> ClockSource
+ CLaSH.Annotations.TopEntity: altpll :: String -> String -> String -> ClockSource
+ CLaSH.Annotations.TopEntity: clockWizard :: String -> String -> String -> ClockSource
+ CLaSH.Prelude: asyncRam :: (KnownNat n, Enum addr) => SNat n -> Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude: asyncRamPow2 :: (KnownNat (2 ^ n), KnownNat n) => Signal (Unsigned n) -> Signal (Unsigned n) -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude: asyncRom :: (KnownNat n, Enum addr) => Vec n a -> addr -> a
+ CLaSH.Prelude: asyncRomFile :: (KnownNat m, Enum addr) => SNat n -> FilePath -> addr -> BitVector m
+ CLaSH.Prelude: asyncRomFilePow2 :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => FilePath -> Unsigned n -> BitVector m
+ CLaSH.Prelude: asyncRomPow2 :: (KnownNat (2 ^ n), KnownNat n) => Vec (2 ^ n) a -> Unsigned n -> a
+ CLaSH.Prelude: blockRamFile :: (KnownNat m, Enum addr) => SNat n -> FilePath -> Signal addr -> Signal addr -> Signal Bool -> Signal (BitVector m) -> Signal (BitVector m)
+ CLaSH.Prelude: blockRamFilePow2 :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => FilePath -> Signal (Unsigned n) -> Signal (Unsigned n) -> Signal Bool -> Signal (BitVector m) -> Signal (BitVector m)
+ CLaSH.Prelude: rom :: (KnownNat n, KnownNat m) => Vec n a -> Signal (Unsigned m) -> Signal a
+ CLaSH.Prelude: romFile :: (KnownNat m, KnownNat k) => SNat n -> FilePath -> Signal (Unsigned k) -> Signal (BitVector m)
+ CLaSH.Prelude: romFilePow2 :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => FilePath -> Signal (Unsigned n) -> Signal (BitVector m)
+ CLaSH.Prelude: romPow2 :: (KnownNat (2 ^ n), KnownNat n) => Vec (2 ^ n) a -> Signal (Unsigned n) -> Signal a
+ CLaSH.Prelude.BlockRam: blockRam# :: KnownNat n => SClock clk -> Vec n a -> Signal' clk Int -> Signal' clk Int -> Signal' clk Bool -> Signal' clk a -> Signal' clk a
+ CLaSH.Prelude.BlockRam.File: blockRamFile :: (KnownNat m, Enum addr) => SNat n -> FilePath -> Signal addr -> Signal addr -> Signal Bool -> Signal (BitVector m) -> Signal (BitVector m)
+ CLaSH.Prelude.BlockRam.File: blockRamFile# :: KnownNat m => SClock clk -> SNat n -> FilePath -> Signal' clk Int -> Signal' clk Int -> Signal' clk Bool -> Signal' clk (BitVector m) -> Signal' clk (BitVector m)
+ CLaSH.Prelude.BlockRam.File: blockRamFile' :: (KnownNat m, Enum addr) => SClock clk -> SNat n -> FilePath -> Signal' clk addr -> Signal' clk addr -> Signal' clk Bool -> Signal' clk (BitVector m) -> Signal' clk (BitVector m)
+ CLaSH.Prelude.BlockRam.File: blockRamFilePow2 :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => FilePath -> Signal (Unsigned n) -> Signal (Unsigned n) -> Signal Bool -> Signal (BitVector m) -> Signal (BitVector m)
+ CLaSH.Prelude.BlockRam.File: blockRamFilePow2' :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => SClock clk -> FilePath -> Signal' clk (Unsigned n) -> Signal' clk (Unsigned n) -> Signal' clk Bool -> Signal' clk (BitVector m) -> Signal' clk (BitVector m)
+ CLaSH.Prelude.BlockRam.File: initMem :: KnownNat n => FilePath -> [BitVector n]
+ CLaSH.Prelude.Explicit: assert' :: (Eq a, Show a) => SClock t -> String -> Signal' t a -> Signal' t a -> Signal' t b -> Signal' t b
+ CLaSH.Prelude.Explicit: asyncFIFOSynchronizer :: _ => SNat addrSize -> SClock wclk -> SClock rclk -> Signal' wclk a -> Signal' wclk Bool -> Signal' rclk Bool -> (Signal' rclk a, Signal' rclk Bool, Signal' wclk Bool)
+ CLaSH.Prelude.Explicit: asyncRam' :: (KnownNat n, Enum addr) => SClock wclk -> SClock rclk -> SNat n -> Signal' wclk addr -> Signal' rclk addr -> Signal' wclk Bool -> Signal' wclk a -> Signal' rclk a
+ CLaSH.Prelude.Explicit: asyncRamPow2' :: (KnownNat n, KnownNat (2 ^ n)) => SClock wclk -> SClock rclk -> Signal' wclk (Unsigned n) -> Signal' rclk (Unsigned n) -> Signal' wclk Bool -> Signal' wclk a -> Signal' rclk a
+ CLaSH.Prelude.Explicit: blockRamFile' :: (KnownNat m, Enum addr) => SClock clk -> SNat n -> FilePath -> Signal' clk addr -> Signal' clk addr -> Signal' clk Bool -> Signal' clk (BitVector m) -> Signal' clk (BitVector m)
+ CLaSH.Prelude.Explicit: blockRamFilePow2' :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => SClock clk -> FilePath -> Signal' clk (Unsigned n) -> Signal' clk (Unsigned n) -> Signal' clk Bool -> Signal' clk (BitVector m) -> Signal' clk (BitVector m)
+ CLaSH.Prelude.Explicit: dualFlipFlopSynchronizer :: SClock clk1 -> SClock clk2 -> a -> Signal' clk1 a -> Signal' clk2 a
+ CLaSH.Prelude.Explicit: rom' :: (KnownNat n, Enum addr) => SClock clk -> Vec n a -> Signal' clk addr -> Signal' clk a
+ CLaSH.Prelude.Explicit: romFile' :: (KnownNat m, Enum addr) => SClock clk -> SNat n -> FilePath -> Signal' clk addr -> Signal' clk (BitVector m)
+ CLaSH.Prelude.Explicit: romFilePow2' :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => SClock clk -> FilePath -> Signal' clk (Unsigned n) -> Signal' clk (BitVector m)
+ CLaSH.Prelude.Explicit: romPow2' :: (KnownNat (2 ^ n), KnownNat n) => SClock clk -> Vec (2 ^ n) a -> Signal' clk (Unsigned n) -> Signal' clk a
+ CLaSH.Prelude.Explicit.Safe: asyncFIFOSynchronizer :: _ => SNat addrSize -> SClock wclk -> SClock rclk -> Signal' wclk a -> Signal' wclk Bool -> Signal' rclk Bool -> (Signal' rclk a, Signal' rclk Bool, Signal' wclk Bool)
+ CLaSH.Prelude.Explicit.Safe: asyncRam' :: (KnownNat n, Enum addr) => SClock wclk -> SClock rclk -> SNat n -> Signal' wclk addr -> Signal' rclk addr -> Signal' wclk Bool -> Signal' wclk a -> Signal' rclk a
+ CLaSH.Prelude.Explicit.Safe: asyncRamPow2' :: (KnownNat n, KnownNat (2 ^ n)) => SClock wclk -> SClock rclk -> Signal' wclk (Unsigned n) -> Signal' rclk (Unsigned n) -> Signal' wclk Bool -> Signal' wclk a -> Signal' rclk a
+ CLaSH.Prelude.Explicit.Safe: blockRam' :: (KnownNat n, Enum addr) => SClock clk -> Vec n a -> Signal' clk addr -> Signal' clk addr -> Signal' clk Bool -> Signal' clk a -> Signal' clk a
+ CLaSH.Prelude.Explicit.Safe: blockRamPow2' :: (KnownNat n, KnownNat (2 ^ n)) => SClock clk -> Vec (2 ^ n) a -> Signal' clk (Unsigned n) -> Signal' clk (Unsigned n) -> Signal' clk Bool -> Signal' clk a -> Signal' clk a
+ CLaSH.Prelude.Explicit.Safe: dualFlipFlopSynchronizer :: SClock clk1 -> SClock clk2 -> a -> Signal' clk1 a -> Signal' clk2 a
+ CLaSH.Prelude.Explicit.Safe: isFalling' :: (Bounded a, Eq a) => SClock clk -> a -> Signal' clk a -> Signal' clk Bool
+ CLaSH.Prelude.Explicit.Safe: isRising' :: (Bounded a, Eq a) => SClock clk -> a -> Signal' clk a -> Signal' clk Bool
+ CLaSH.Prelude.Explicit.Safe: mealy' :: SClock clk -> (s -> i -> (s, o)) -> s -> (Signal' clk i -> Signal' clk o)
+ CLaSH.Prelude.Explicit.Safe: mealyB' :: (Bundle i, Bundle o) => SClock clk -> (s -> i -> (s, o)) -> s -> (Unbundled' clk i -> Unbundled' clk o)
+ CLaSH.Prelude.Explicit.Safe: moore' :: SClock clk -> (s -> i -> s) -> (s -> o) -> s -> (Signal' clk i -> Signal' clk o)
+ CLaSH.Prelude.Explicit.Safe: mooreB' :: (Bundle i, Bundle o) => SClock clk -> (s -> i -> s) -> (s -> o) -> s -> (Unbundled' clk i -> Unbundled' clk o)
+ CLaSH.Prelude.Explicit.Safe: registerB' :: Bundle a => SClock clk -> a -> Unbundled' clk a -> Unbundled' clk a
+ CLaSH.Prelude.Explicit.Safe: rom' :: (KnownNat n, Enum addr) => SClock clk -> Vec n a -> Signal' clk addr -> Signal' clk a
+ CLaSH.Prelude.Explicit.Safe: romPow2' :: (KnownNat (2 ^ n), KnownNat n) => SClock clk -> Vec (2 ^ n) a -> Signal' clk (Unsigned n) -> Signal' clk a
+ CLaSH.Prelude.RAM: asyncRam :: (KnownNat n, Enum addr) => SNat n -> Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude.RAM: asyncRam# :: SClock wclk -> SClock rclk -> SNat n -> Signal' wclk Int -> Signal' rclk Int -> Signal' wclk Bool -> Signal' wclk a -> Signal' rclk a
+ CLaSH.Prelude.RAM: asyncRam' :: (KnownNat n, Enum addr) => SClock wclk -> SClock rclk -> SNat n -> Signal' wclk addr -> Signal' rclk addr -> Signal' wclk Bool -> Signal' wclk a -> Signal' rclk a
+ CLaSH.Prelude.RAM: asyncRamPow2 :: (KnownNat (2 ^ n), KnownNat n) => Signal (Unsigned n) -> Signal (Unsigned n) -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude.RAM: asyncRamPow2' :: (KnownNat n, KnownNat (2 ^ n)) => SClock wclk -> SClock rclk -> Signal' wclk (Unsigned n) -> Signal' rclk (Unsigned n) -> Signal' wclk Bool -> Signal' wclk a -> Signal' rclk a
+ CLaSH.Prelude.ROM: asyncRom :: (KnownNat n, Enum addr) => Vec n a -> addr -> a
+ CLaSH.Prelude.ROM: asyncRom# :: KnownNat n => Vec n a -> Int -> a
+ CLaSH.Prelude.ROM: asyncRomPow2 :: (KnownNat (2 ^ n), KnownNat n) => Vec (2 ^ n) a -> Unsigned n -> a
+ CLaSH.Prelude.ROM: rom :: (KnownNat n, KnownNat m) => Vec n a -> Signal (Unsigned m) -> Signal a
+ CLaSH.Prelude.ROM: rom# :: KnownNat n => SClock clk -> Vec n a -> Signal' clk Int -> Signal' clk a
+ CLaSH.Prelude.ROM: rom' :: (KnownNat n, Enum addr) => SClock clk -> Vec n a -> Signal' clk addr -> Signal' clk a
+ CLaSH.Prelude.ROM: romPow2 :: (KnownNat (2 ^ n), KnownNat n) => Vec (2 ^ n) a -> Signal (Unsigned n) -> Signal a
+ CLaSH.Prelude.ROM: romPow2' :: (KnownNat (2 ^ n), KnownNat n) => SClock clk -> Vec (2 ^ n) a -> Signal' clk (Unsigned n) -> Signal' clk a
+ CLaSH.Prelude.ROM.File: asyncRomFile :: (KnownNat m, Enum addr) => SNat n -> FilePath -> addr -> BitVector m
+ CLaSH.Prelude.ROM.File: asyncRomFile# :: KnownNat m => SNat n -> FilePath -> Int -> BitVector m
+ CLaSH.Prelude.ROM.File: asyncRomFilePow2 :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => FilePath -> Unsigned n -> BitVector m
+ CLaSH.Prelude.ROM.File: romFile :: (KnownNat m, KnownNat k) => SNat n -> FilePath -> Signal (Unsigned k) -> Signal (BitVector m)
+ CLaSH.Prelude.ROM.File: romFile# :: KnownNat m => SClock clk -> SNat n -> FilePath -> Signal' clk Int -> Signal' clk (BitVector m)
+ CLaSH.Prelude.ROM.File: romFile' :: (KnownNat m, Enum addr) => SClock clk -> SNat n -> FilePath -> Signal' clk addr -> Signal' clk (BitVector m)
+ CLaSH.Prelude.ROM.File: romFilePow2 :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => FilePath -> Signal (Unsigned n) -> Signal (BitVector m)
+ CLaSH.Prelude.ROM.File: romFilePow2' :: (KnownNat m, KnownNat n, KnownNat (2 ^ n)) => SClock clk -> FilePath -> Signal' clk (Unsigned n) -> Signal' clk (BitVector m)
+ CLaSH.Prelude.Safe: (<^>) :: (Bundle i, Bundle o) => (s -> i -> (s, o)) -> s -> (Unbundled i -> Unbundled o)
+ CLaSH.Prelude.Safe: asyncRam :: (KnownNat n, Enum addr) => SNat n -> Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude.Safe: asyncRamPow2 :: (KnownNat (2 ^ n), KnownNat n) => Signal (Unsigned n) -> Signal (Unsigned n) -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude.Safe: asyncRom :: (KnownNat n, Enum addr) => Vec n a -> addr -> a
+ CLaSH.Prelude.Safe: asyncRomPow2 :: (KnownNat (2 ^ n), KnownNat n) => Vec (2 ^ n) a -> Unsigned n -> a
+ CLaSH.Prelude.Safe: blockRam :: (KnownNat n, Enum addr) => Vec n a -> Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude.Safe: blockRamPow2 :: (KnownNat (2 ^ n), KnownNat n) => Vec (2 ^ n) a -> Signal (Unsigned n) -> Signal (Unsigned n) -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude.Safe: isFalling :: (Bounded a, Eq a) => a -> Signal a -> Signal Bool
+ CLaSH.Prelude.Safe: isRising :: (Bounded a, Eq a) => a -> Signal a -> Signal Bool
+ CLaSH.Prelude.Safe: mealy :: (s -> i -> (s, o)) -> s -> (Signal i -> Signal o)
+ CLaSH.Prelude.Safe: mealyB :: (Bundle i, Bundle o) => (s -> i -> (s, o)) -> s -> (Unbundled i -> Unbundled o)
+ CLaSH.Prelude.Safe: moore :: (s -> i -> s) -> (s -> o) -> s -> (Signal i -> Signal o)
+ CLaSH.Prelude.Safe: mooreB :: (Bundle i, Bundle o) => (s -> i -> s) -> (s -> o) -> s -> (Unbundled i -> Unbundled o)
+ CLaSH.Prelude.Safe: registerB :: Bundle a => a -> Unbundled a -> Unbundled a
+ CLaSH.Prelude.Safe: rom :: (KnownNat n, KnownNat m) => Vec n a -> Signal (Unsigned m) -> Signal a
+ CLaSH.Prelude.Safe: romPow2 :: (KnownNat (2 ^ n), KnownNat n) => Vec (2 ^ n) a -> Signal (Unsigned n) -> Signal a
+ CLaSH.Prelude.Synchronizer: asyncFIFOSynchronizer :: _ => SNat addrSize -> SClock wclk -> SClock rclk -> Signal' wclk a -> Signal' wclk Bool -> Signal' rclk Bool -> (Signal' rclk a, Signal' rclk Bool, Signal' wclk Bool)
+ CLaSH.Prelude.Synchronizer: dualFlipFlopSynchronizer :: SClock clk1 -> SClock clk2 -> a -> Signal' clk1 a -> Signal' clk2 a
+ CLaSH.Prelude.Testbench: assert' :: (Eq a, Show a) => SClock t -> String -> Signal' t a -> Signal' t a -> Signal' t b -> Signal' t b
+ CLaSH.Promoted.Nat: addSNat :: KnownNat (a + b) => SNat a -> SNat b -> SNat (a + b)
+ CLaSH.Promoted.Nat: mulSNat :: KnownNat (a * b) => SNat a -> SNat b -> SNat (a * b)
+ CLaSH.Promoted.Nat: powSNat :: KnownNat (a ^ b) => SNat a -> SNat b -> SNat (a ^ b)
+ CLaSH.Promoted.Nat: subSNat :: KnownNat (a - b) => SNat a -> SNat b -> SNat (a - b)
+ CLaSH.Signal.Explicit: freqCalc :: [Integer] -> [Integer]
+ CLaSH.Signal.Internal: joinSignal# :: Signal' clk (Signal' clk a) -> Signal' clk a
+ CLaSH.Sized.Fixed: fLitR :: (size ~ (int + frac), KnownNat frac, Bounded (rep size), Integral (rep size)) => Double -> Fixed rep int frac
+ CLaSH.Sized.Internal.Unsigned: [unsafeToInteger] :: Unsigned -> Integer
- CLaSH.Prelude: assert :: (Eq a, Show a) => Signal' t a -> Signal' t a -> Signal' t b -> Signal' t b
+ CLaSH.Prelude: assert :: (Eq a, Show a) => String -> Signal a -> Signal a -> Signal b -> Signal b
- CLaSH.Prelude: blockRam :: (KnownNat n, KnownNat m) => Vec n a -> Signal (Unsigned m) -> Signal (Unsigned m) -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude: blockRam :: (KnownNat n, Enum addr) => Vec n a -> Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a
- CLaSH.Prelude.BitIndex: (!) :: (BitPack a, KnownNat (BitSize a), Integral i) => a -> i -> Bit
+ CLaSH.Prelude.BitIndex: (!) :: (BitPack a, KnownNat (BitSize a), Enum i) => a -> i -> Bit
- CLaSH.Prelude.BitIndex: replaceBit :: (BitPack a, KnownNat (BitSize a), Integral i) => i -> Bit -> a -> a
+ CLaSH.Prelude.BitIndex: replaceBit :: (BitPack a, KnownNat (BitSize a), Enum i) => i -> Bit -> a -> a
- CLaSH.Prelude.BlockRam: blockRam :: (KnownNat n, KnownNat m) => Vec n a -> Signal (Unsigned m) -> Signal (Unsigned m) -> Signal Bool -> Signal a -> Signal a
+ CLaSH.Prelude.BlockRam: blockRam :: (KnownNat n, Enum addr) => Vec n a -> Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a
- CLaSH.Prelude.BlockRam: blockRam' :: (KnownNat n, KnownNat m) => SClock clk -> Vec n a -> Signal' clk (Unsigned m) -> Signal' clk (Unsigned m) -> Signal' clk Bool -> Signal' clk a -> Signal' clk a
+ CLaSH.Prelude.BlockRam: blockRam' :: (KnownNat n, Enum addr) => SClock clk -> Vec n a -> Signal' clk addr -> Signal' clk addr -> Signal' clk Bool -> Signal' clk a -> Signal' clk a
- CLaSH.Prelude.Explicit: blockRam' :: (KnownNat n, KnownNat m) => SClock clk -> Vec n a -> Signal' clk (Unsigned m) -> Signal' clk (Unsigned m) -> Signal' clk Bool -> Signal' clk a -> Signal' clk a
+ CLaSH.Prelude.Explicit: blockRam' :: (KnownNat n, Enum addr) => SClock clk -> Vec n a -> Signal' clk addr -> Signal' clk addr -> Signal' clk Bool -> Signal' clk a -> Signal' clk a
- CLaSH.Prelude.Testbench: assert :: (Eq a, Show a) => Signal' t a -> Signal' t a -> Signal' t b -> Signal' t b
+ CLaSH.Prelude.Testbench: assert :: (Eq a, Show a) => String -> Signal a -> Signal a -> Signal b -> Signal b
- CLaSH.Signal: mux :: Signal' clk Bool -> Signal' clk a -> Signal' clk a -> Signal' clk a
+ CLaSH.Signal: mux :: Applicative f => f Bool -> f a -> f a -> f a
- CLaSH.Signal.Delayed: antiDelay :: SNat d -> DSignal n a -> DSignal (n - d) a
+ CLaSH.Signal.Delayed: antiDelay :: SNat d -> DSignal (n + d) a -> DSignal n a
- CLaSH.Signal.Delayed: delay :: KnownNat m => Vec m a -> DSignal (n - m) a -> DSignal n a
+ CLaSH.Signal.Delayed: delay :: KnownNat d => Vec d a -> DSignal n a -> DSignal (n + d) a
- CLaSH.Signal.Delayed: delayI :: (Default a, KnownNat m) => DSignal (n - m) a -> DSignal n a
+ CLaSH.Signal.Delayed: delayI :: (Default a, KnownNat d) => DSignal n a -> DSignal (n + d) a
- CLaSH.Signal.Delayed: feedback :: (DSignal ((n - m) - 1) a -> (DSignal ((n - m) - 1) a, DSignal n a)) -> DSignal ((n - m) - 1) a
+ CLaSH.Signal.Delayed: feedback :: (DSignal n a -> (DSignal n a, DSignal ((n + m) + 1) a)) -> DSignal n a
- CLaSH.Signal.Internal: mux :: Signal' clk Bool -> Signal' clk a -> Signal' clk a -> Signal' clk a
+ CLaSH.Signal.Internal: mux :: Applicative f => f Bool -> f a -> f a -> f a
- CLaSH.Sized.Vector: (!!) :: (KnownNat n, Integral i) => Vec n a -> i -> a
+ CLaSH.Sized.Vector: (!!) :: (KnownNat n, Enum i) => Vec n a -> i -> a
- CLaSH.Sized.Vector: replace :: (KnownNat n, Integral i) => i -> a -> Vec n a -> Vec n a
+ CLaSH.Sized.Vector: replace :: (KnownNat n, Enum i) => i -> a -> Vec n a -> Vec n a

Files

CHANGELOG.md view
@@ -1,18 +1,32 @@ # Changelog for [`clash-prelude` package](http://hackage.haskell.org/package/clash-prelude) +## 0.9 *June 25th 2015*+* New features:+  * Add operations on singleton natural numbers: `addSNat`, `subSNat`, `mulSNat`, and `powSNat`.+  * Add asynchronous RAM functions in `CLaSH.Prelude.RAM`, which have an asynchronous/combinational read port.+  * Add ROM functions in modules `CLaSH.Prelude.ROM` and `CLaSH.Prelude.ROM.File`, where the latter module contains functions that instantiate a ROM from the content specified in an external data-file.+  * Add BlockRam functions, in the `CLaSH.Prelude.BlockRam.File` module, whose content can be initialised with the content specified in an external data-file.+  * `assert` now takes an extra `String` argument so you can distinguish one `assert` from the others.+  Additionally, `assert'` is added which takes an additional `SClock` argument.+  This is needed, because `assert` now reports the clock cycle, and clock domain, when an assertion fails.+  * `defClkAltera` and `defClkXilinx` are replaced by, `altpll` and `alteraPll` for Altera clock sources, and `clockWizard` for Xilinx clock sources.+  These names correspond to the names of the generator utilities in Quartus and ISE/Vivado.+  * Add [Safe](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/safe-haskell.html) versions of the prelude modules: `CLaSH.Prelude.Safe` and `CLaSH.Prelude.Explicit.Safe`+  * Add synchronizers in the `CLaSH.Prelude.Synchronizer` module+ ## 0.8 *June 3rd 2015* * New features:   * Make the (Bit)Vector argument the _last_ argument for the following functions: `slice`, `setSlice`, `replaceBit`, `replace`. The signatures for the above functions are now:-    +     ```     slice      :: BitPack a => SNat m -> SNat n -> a -> BitVector (m + 1 - n)     setSlice   :: BitPack a => SNat m -> SNat n -> BitVector (m + 1 - n) -> a -> a     replaceBit :: Integral i => i -> Bit -> a -> a     replace    :: Integral i => i -> a -> Vec n a -> Vec n a     ```-    +     This allows for easier chaining, e.g.:-    +     ```     replaceBit 0 1 $     repleceBit 4 0 $@@ -28,16 +42,16 @@     > unpack 0x0F :: Vec 8 Bit     <1,1,1,1,0,0,0,0>     ```-    +     As of version 0.8, we have `head x == msb y`:-    +     ```     > 0x0F :: BitVector 8     0000_1111     > unpack 0x0F :: Vec 8 Bit     <0,0,0,0,1,1,1,1>     ```-    +     So converting for `Vec`tors of `Bit`s to `BitVector`s is no longer _index_-preserving, but it is _order_-preserving.   * Add [QuickCheck](http://hackage.haskell.org/package/QuickCheck) `Arbitary` and `CoArbitary` instances for all data types   * Add [lens](http://hackage.haskell.org/package/lens) `Ixed` instances for `BitVector`, `Signed`, `Unsigned`, and `Vec`
clash-prelude.cabal view
@@ -1,157 +1,165 @@-Name:                 clash-prelude
-Version:              0.8.1
-Synopsis:             CAES Language for Synchronous Hardware - Prelude library
-Description:
-  CλaSH (pronounced ‘clash’) is a functional hardware description language that
-  borrows both its syntax and semantics from the functional programming language
-  Haskell. The merits of using a functional language to describe hardware comes
-  from the fact that combinational circuits can be directly modeled as
-  mathematical functions and that functional languages lend themselves very well
-  at describing and (de-)composing mathematical functions.
-  .
-  This package provides:
-  .
-  * Prelude library containing datatypes and functions for circuit design
-  .
-  To use the library:
-  .
-  * Import "CLaSH.Prelude"
-  .
-  * Additionally import "CLaSH.Prelude.Explicit" if you want to design
-    explicitly clocked circuits in a multi-clock setting
-  .
-  A preliminary version of a tutorial can be found in "CLaSH.Tutorial", for a
-  general overview of the library you should however check out "CLaSH.Prelude".
-  Some circuit examples can be found in "CLaSH.Examples".
-Homepage:             http://www.clash-lang.org/
-bug-reports:          http://github.com/clash-lang/clash-prelude/issues
-License:              BSD2
-License-file:         LICENSE
-Author:               Christiaan Baaij
-Maintainer:           Christiaan Baaij <christiaan.baaij@gmail.com>
-Copyright:            Copyright © 2013-2015 University of Twente
-Category:             Hardware
-Build-type:           Simple
-
-Extra-source-files:   README.md
-                      CHANGELOG.md
-                      AUTHORS.md
-
-extra-doc-files:      doc/*.svg
-
-Cabal-version:        >=1.10
-
-source-repository head
-  type: git
-  location: https://github.com/clash-lang/clash-prelude.git
-
-flag doctests
-  description:
-    You can disable testing with doctests using `-f-doctests`.
-  default: True
-  manual: True
-
-flag doclinks
-  description:
-    Create hyperlinks to non-dependent packages using `-fdoclinks`.
-  default: False
-  manual: True
-
-Library
-  HS-Source-Dirs:     src
-
-  default-language:   Haskell2010
-  ghc-options:        -Wall -fexpose-all-unfoldings
-
-  Exposed-modules:    CLaSH.Annotations.TopEntity
-
-                      CLaSH.Class.BitPack
-                      CLaSH.Class.Num
-                      CLaSH.Class.Resize
-
-                      CLaSH.Prelude
-                      CLaSH.Prelude.BitIndex
-                      CLaSH.Prelude.BitReduction
-                      CLaSH.Prelude.BlockRam
-                      CLaSH.Prelude.DataFlow
-                      CLaSH.Prelude.Explicit
-                      CLaSH.Prelude.Mealy
-                      CLaSH.Prelude.Moore
-                      CLaSH.Prelude.Testbench
-
-                      CLaSH.Promoted.Nat
-                      CLaSH.Promoted.Nat.TH
-                      CLaSH.Promoted.Nat.Literals
-                      CLaSH.Promoted.Ord
-                      CLaSH.Promoted.Symbol
-
-                      CLaSH.Signal
-                      CLaSH.Signal.Bundle
-                      CLaSH.Signal.Delayed
-                      CLaSH.Signal.Explicit
-                      CLaSH.Signal.Internal
-
-                      CLaSH.Sized.BitVector
-                      CLaSH.Sized.Fixed
-                      CLaSH.Sized.Index
-                      CLaSH.Sized.Signed
-                      CLaSH.Sized.Unsigned
-                      CLaSH.Sized.Vector
-
-                      CLaSH.Sized.Internal.BitVector
-                      CLaSH.Sized.Internal.Index
-                      CLaSH.Sized.Internal.Signed
-                      CLaSH.Sized.Internal.Unsigned
-
-                      CLaSH.Tutorial
-                      CLaSH.Examples
-
-  other-extensions:   BangPatterns
-                      DataKinds
-                      ConstraintKinds
-                      DefaultSignatures
-                      DeriveDataTypeable
-                      FlexibleContexts
-                      GADTs
-                      GeneralizedNewtypeDeriving
-                      KindSignatures
-                      MagicHash
-                      MultiParamTypeClasses
-                      Rank2Types
-                      ScopedTypeVariables
-                      StandaloneDeriving
-                      TemplateHaskell
-                      TupleSections
-                      TypeFamilies
-                      TypeOperators
-                      UndecidableInstances
-
-  Build-depends:      base                      >= 4.8.0.0 && < 5,
-                      data-default              >= 0.5.3,
-                      integer-gmp               >= 0.5.1.0,
-                      ghc-prim                  >= 0.3.1.0,
-                      ghc-typelits-natnormalise >= 0.3,
-                      lens                      >= 4.9,
-                      QuickCheck                >= 2.7 && <2.9,
-                      singletons                >= 1.0,
-                      template-haskell          >= 2.9.0.0,
-                      th-lift                   >= 0.5.6
-
-  if flag(doclinks)
-    CPP-Options:      -DDOCLINKS
-    build-depends:    transformers              >= 0.4.2.0
-
-test-suite doctests
-  type:             exitcode-stdio-1.0
-  default-language: Haskell2010
-  main-is:          doctests.hs
-  ghc-options:      -Wall
-  hs-source-dirs:   tests
-
-  if !flag(doctests)
-    buildable: False
-  else
-    build-depends:
-      base    >= 4     && < 5,
-      doctest >= 0.9.1 && < 0.11,
-      Glob    >= 0.7   && < 0.8
+Name:                 clash-prelude+Version:              0.9+Synopsis:             CAES Language for Synchronous Hardware - Prelude library+Description:+  CλaSH (pronounced ‘clash’) is a functional hardware description language that+  borrows both its syntax and semantics from the functional programming language+  Haskell. The merits of using a functional language to describe hardware comes+  from the fact that combinational circuits can be directly modeled as+  mathematical functions and that functional languages lend themselves very well+  at describing and (de-)composing mathematical functions.+  .+  This package provides:+  .+  * Prelude library containing datatypes and functions for circuit design+  .+  To use the library:+  .+  * Import "CLaSH.Prelude"+  .+  * Additionally import "CLaSH.Prelude.Explicit" if you want to design+    explicitly clocked circuits in a multi-clock setting+  .+  A preliminary version of a tutorial can be found in "CLaSH.Tutorial", for a+  general overview of the library you should however check out "CLaSH.Prelude".+  Some circuit examples can be found in "CLaSH.Examples".+Homepage:             http://www.clash-lang.org/+bug-reports:          http://github.com/clash-lang/clash-prelude/issues+License:              BSD2+License-file:         LICENSE+Author:               Christiaan Baaij+Maintainer:           Christiaan Baaij <christiaan.baaij@gmail.com>+Copyright:            Copyright © 2013-2015 University of Twente+Category:             Hardware+Build-type:           Simple++Extra-source-files:   README.md+                      CHANGELOG.md+                      AUTHORS.md++extra-doc-files:      doc/*.svg++Cabal-version:        >=1.10++source-repository head+  type: git+  location: https://github.com/clash-lang/clash-prelude.git++flag doctests+  description:+    You can disable testing with doctests using `-f-doctests`.+  default: True+  manual: True++flag doclinks+  description:+    Create hyperlinks to non-dependent packages using `-fdoclinks`.+  default: False+  manual: True++Library+  HS-Source-Dirs:     src++  default-language:   Haskell2010+  ghc-options:        -Wall -fexpose-all-unfoldings++  Exposed-modules:    CLaSH.Annotations.TopEntity++                      CLaSH.Class.BitPack+                      CLaSH.Class.Num+                      CLaSH.Class.Resize++                      CLaSH.Prelude+                      CLaSH.Prelude.BitIndex+                      CLaSH.Prelude.BitReduction+                      CLaSH.Prelude.BlockRam+                      CLaSH.Prelude.BlockRam.File+                      CLaSH.Prelude.DataFlow+                      CLaSH.Prelude.Explicit+                      CLaSH.Prelude.Explicit.Safe+                      CLaSH.Prelude.Mealy+                      CLaSH.Prelude.Moore+                      CLaSH.Prelude.RAM+                      CLaSH.Prelude.ROM+                      CLaSH.Prelude.ROM.File+                      CLaSH.Prelude.Safe+                      CLaSH.Prelude.Synchronizer+                      CLaSH.Prelude.Testbench++                      CLaSH.Promoted.Nat+                      CLaSH.Promoted.Nat.TH+                      CLaSH.Promoted.Nat.Literals+                      CLaSH.Promoted.Ord+                      CLaSH.Promoted.Symbol++                      CLaSH.Signal+                      CLaSH.Signal.Bundle+                      CLaSH.Signal.Delayed+                      CLaSH.Signal.Explicit+                      CLaSH.Signal.Internal++                      CLaSH.Sized.BitVector+                      CLaSH.Sized.Fixed+                      CLaSH.Sized.Index+                      CLaSH.Sized.Signed+                      CLaSH.Sized.Unsigned+                      CLaSH.Sized.Vector++                      CLaSH.Sized.Internal.BitVector+                      CLaSH.Sized.Internal.Index+                      CLaSH.Sized.Internal.Signed+                      CLaSH.Sized.Internal.Unsigned++                      CLaSH.Tutorial+                      CLaSH.Examples++  other-extensions:   BangPatterns+                      DataKinds+                      ConstraintKinds+                      DefaultSignatures+                      DeriveDataTypeable+                      FlexibleContexts+                      GADTs+                      GeneralizedNewtypeDeriving+                      KindSignatures+                      MagicHash+                      MultiParamTypeClasses+                      Rank2Types+                      ScopedTypeVariables+                      StandaloneDeriving+                      TemplateHaskell+                      TupleSections+                      TypeFamilies+                      TypeOperators+                      UndecidableInstances++  Build-depends:      array                     >= 0.5.1.0,+                      base                      >= 4.8.0.0 && < 5,+                      data-default              >= 0.5.3,+                      integer-gmp               >= 0.5.1.0,+                      ghc-prim                  >= 0.3.1.0,+                      ghc-typelits-natnormalise >= 0.3,+                      lens                      >= 4.9,+                      QuickCheck                >= 2.7 && <2.9,+                      singletons                >= 1.0,+                      template-haskell          >= 2.9.0.0,+                      th-lift                   >= 0.5.6++  if flag(doclinks)+    CPP-Options:      -DDOCLINKS+    build-depends:    transformers              >= 0.4.2.0++test-suite doctests+  type:             exitcode-stdio-1.0+  default-language: Haskell2010+  main-is:          doctests.hs+  ghc-options:      -Wall+  hs-source-dirs:   tests++  if !flag(doctests)+    buildable: False+  else+    build-depends:+      base    >= 4     && < 5,+      doctest >= 0.9.1 && < 0.11,+      Glob    >= 0.7   && < 0.8
src/CLaSH/Annotations/TopEntity.hs view
@@ -89,7 +89,7 @@     , t_extraIn  = [ (\"CLOCK_50\", 1)                    , (\"KEY0\"    , 1)                    ]-    , t_clocks   = [ 'defClkAltera' "altpll50" "CLOCK_50(0)" "not KEY0(0)" ]+    , t_clocks   = [ 'altpll' "altpll50" "CLOCK_50(0)" "not KEY0(0)" ]     }) \#-\} @ @@ -173,8 +173,11 @@   , ClockSource (..)     -- * Convenience functions   , defTop-  , defClkAltera-  , defClkXilinx+    -- ** Altera clock sources+  , altpll+  , alteraPll+    -- ** Xilinx clock sources+  , clockWizard   ) where @@ -196,22 +199,18 @@   --   -- So given a bit-width @n@, the port has type:   ---  -- @std_logic_vector (n-1 downto 0)@ in VHDL-  ---  -- and-  ---  -- @logic [n-1:0]@ in (System)Verilog.+  -- * __VHDL__: @std_logic_vector (n-1 downto 0)@+  -- * __Verilog__: @[n-1:0]@+  -- * __SystemVerilog__: @logic [n-1:0]@   , t_extraOut :: [(String,Int)]   -- ^ Extra output ports, where every tuple holds the name of the input port   -- and the number of bits are used for that input port.   --   -- So given a bit-width @n@, the port has type:   ---  -- @std_logic_vector (n-1 downto 0)@ in VHDL-  ---  -- and-  ---  -- @logic [n-1:0]@ in (System)Verilog.+  -- * __VHDL__: @std_logic_vector (n-1 downto 0)@+  -- * __Verilog__: @[n-1:0]@+  -- * __SystemVerilog__: @logic [n-1:0]@   , t_clocks   :: [ClockSource]  -- ^ List of clock sources   }   deriving (Data,Show)@@ -275,10 +274,10 @@   , t_clocks   = []   } --- | A clock source that corresponds to the Altera PLL component with default--- settings to provide a stable 'systemClock'.+-- | A clock source that corresponds to the Altera/Quartus \"ALTPLL\" component+-- with default settings to provide a stable 'systemClock'. ----- >>> defClkAltera "altpll50" "CLOCK(0)" "not KEY(0)"+-- >>> altpll "altpll50" "CLOCK(0)" "not KEY(0)" -- ClockSource {c_name = "altpll50", c_inp = Just ("inclk0","CLOCK(0)"), c_outp = [("c0","system1000")], c_reset = Just ("areset","not KEY(0)"), c_lock = "locked", c_sync = False} -- -- Will generate the following VHDL:@@ -292,7 +291,7 @@ -- -- If you are however generating (System)Verilog you should write: ----- >>> defClkAltera "altpll50" "CLOCK[0]" "~ KEY[0]"+-- >>> altpll "altpll50" "CLOCK[0]" "~ KEY[0]" -- ClockSource {c_name = "altpll50", c_inp = Just ("inclk0","CLOCK[0]"), c_outp = [("c0","system1000")], c_reset = Just ("areset","~ KEY[0]"), c_lock = "locked", c_sync = False} -- -- so that the following (System)Verilog is created:@@ -302,11 +301,11 @@ -- > ,.c0 (system1000) -- > ,.areset (~ KEY0[0]) -- > ,.locked (altpll50_locked));-defClkAltera :: String -- ^ Name of the component.-             -> String -- ^ Clock Pin/Expression of the free running clock.-             -> String -- ^ Reset Pin/Expression controlling the reset of the PLL.-             -> ClockSource-defClkAltera pllName clkExpr resExpr = ClockSource+altpll :: String -- ^ Name of the component.+       -> String -- ^ Clock Pin/Expression of the free running clock.+       -> String -- ^ Reset Pin/Expression controlling the reset of the PLL.+       -> ClockSource+altpll pllName clkExpr resExpr = ClockSource   { c_name  = pllName   , c_inp   = Just ("inclk0",clkExpr)   , c_outp  = [("c0",show systemClock)]@@ -315,10 +314,50 @@   , c_sync  = False   } --- | A clock source that corresponds to the Xilinx PLL/MMCM component with--- settings to provide a stable 'systemClock'.+-- | A clock source that corresponds to the Altera \"Altera PLL\" component+-- with default settings to provide a stable 'systemClock'. ----- >>> defClkXilinx "clkwiz50" "CLOCK(0)" "not KEY(0)"+-- >>> alteraPll "alteraPll50" "CLOCK(0)" "not KEY(0)"+-- ClockSource {c_name = "alteraPll50", c_inp = Just ("refclk","CLOCK(0)"), c_outp = [("outclk_0","system1000")], c_reset = Just ("rst","not KEY(0)"), c_lock = "locked", c_sync = False}+--+-- Will generate the following VHDL:+--+-- > alteraPll50_inst : entity alteraPll+-- >   port map+-- >     (refclk   => CLOCK_50(0)+-- >     ,outclk_0 => system1000+-- >     ,rst      => not KEY0(0)+-- >     ,locked   => alteraPll50_locked);+--+-- If you are however generating (System)Verilog you should write:+--+-- >>> alteraPll "alteraPll50" "CLOCK[0]" "~ KEY[0]"+-- ClockSource {c_name = "alteraPll50", c_inp = Just ("refclk","CLOCK[0]"), c_outp = [("outclk_0","system1000")], c_reset = Just ("rst","~ KEY[0]"), c_lock = "locked", c_sync = False}+--+-- so that the following (System)Verilog is created:+--+-- > alteraPll50 alteraPll50_inst+-- > (.refclk (CLOCK_50[0])+-- > ,.outclk_0 (system1000)+-- > ,.rst (~ KEY0[0])+-- > ,.locked (alteraPll50_locked));+alteraPll :: String -- ^ Name of the component.+          -> String -- ^ Clock Pin/Expression of the free running clock.+          -> String -- ^ Reset Pin/Expression controlling the reset of the PLL.+          -> ClockSource+alteraPll pllName clkExpr resExpr = ClockSource+  { c_name  = pllName+  , c_inp   = Just ("refclk",clkExpr)+  , c_outp  = [("outclk_0",show systemClock)]+  , c_reset = Just ("rst",resExpr)+  , c_lock  = "locked"+  , c_sync  = False+  }++-- | A clock source that corresponds to the Xilinx PLL/MMCM component created+-- with the \"Clock Wizard\", with settings to provide a stable 'systemClock'.+--+-- >>> clockWizard "clkwiz50" "CLOCK(0)" "not KEY(0)" -- ClockSource {c_name = "clkwiz50", c_inp = Just ("CLK_IN1","CLOCK(0)"), c_outp = [("CLK_OUT1","system1000")], c_reset = Just ("RESET","not KEY(0)"), c_lock = "LOCKED", c_sync = False} -- -- Will generate the following VHDL:@@ -332,7 +371,7 @@ -- -- If you are however generating (System)Verilog you should write: ----- >>> defClkXilinx "clkwiz50" "CLOCK[0]" "~ KEY[0]"+-- >>> clockWizard "clkwiz50" "CLOCK[0]" "~ KEY[0]" -- ClockSource {c_name = "clkwiz50", c_inp = Just ("CLK_IN1","CLOCK[0]"), c_outp = [("CLK_OUT1","system1000")], c_reset = Just ("RESET","~ KEY[0]"), c_lock = "LOCKED", c_sync = False} -- -- so that the following (System)Verilog is created:@@ -342,11 +381,11 @@ -- > ,.CLK_OUT1 (system1000) -- > ,.RESET (~ KEY0[0]) -- > ,.LOCKED (altpll50_locked));-defClkXilinx :: String -- ^ Name of the component.-             -> String -- ^ Clock Pin/Expression of the free running clock.-             -> String -- ^ Reset Pin/Expression controlling the reset of the PLL.-             -> ClockSource-defClkXilinx pllName clkExpr resExpr = ClockSource+clockWizard :: String -- ^ Name of the component.+            -> String -- ^ Clock Pin/Expression of the free running clock.+            -> String -- ^ Reset Pin/Expression controlling the reset of the PLL.+            -> ClockSource+clockWizard pllName clkExpr resExpr = ClockSource   { c_name  = pllName   , c_inp   = Just ("CLK_IN1",clkExpr)   , c_outp  = [("CLK_OUT1",show systemClock)]
src/CLaSH/Prelude.hs view
@@ -40,9 +40,25 @@   , moore   , mooreB   , registerB+    -- * ROMs+  , asyncRom+  , asyncRomPow2+  , rom+  , romPow2+    -- ** ROMs initialised with a data file+  , asyncRomFile+  , asyncRomFilePow2+  , romFile+  , romFilePow2+    -- * RAM primitives with a combinational read port+  , asyncRam+  , asyncRamPow2     -- * BlockRAM primitives   , blockRam   , blockRamPow2+    -- ** BlockRAM primitives initialised with a data file+  , blockRamFile+  , blockRamFilePow2     -- * Utility functions   , window   , windowD@@ -115,12 +131,12 @@ import CLaSH.Class.Resize import CLaSH.Prelude.BitIndex import CLaSH.Prelude.BitReduction-import CLaSH.Prelude.BlockRam      (blockRam, blockRamPow2)-import CLaSH.Prelude.Explicit      (registerB', window', windowD', isRising',-                                    isFalling')-import CLaSH.Prelude.Mealy         (mealy, mealyB, (<^>))-import CLaSH.Prelude.Moore         (moore, mooreB)+import CLaSH.Prelude.BlockRam.File (blockRamFile, blockRamFilePow2) import CLaSH.Prelude.DataFlow+import CLaSH.Prelude.Explicit      (window', windowD')+import CLaSH.Prelude.ROM.File      (asyncRomFile,asyncRomFilePow2,romFile,+                                    romFilePow2)+import CLaSH.Prelude.Safe import CLaSH.Prelude.Testbench     (assert, stimuliGenerator, outputVerifier) import CLaSH.Promoted.Nat import CLaSH.Promoted.Nat.TH@@ -177,30 +193,3 @@         => Signal a               -- ^ Signal to create a window over         -> Vec (n + 1) (Signal a) -- ^ Window of at least size 1 windowD = windowD' systemClock--{-# INLINE registerB #-}--- | Create a 'register' function for product-type like signals (e.g. '(Signal a, Signal b)')------ > rP :: (Signal Int,Signal Int) -> (Signal Int, Signal Int)--- > rP = registerB (8,8)------ >>> simulateB rP [(1,1),(2,2),(3,3)] :: [(Int,Int)]--- [(8,8),(1,1),(2,2),(3,3)...-registerB :: Bundle a => a -> Unbundled a -> Unbundled a-registerB = registerB' systemClock--{-# INLINE isRising #-}--- | Give a pulse when the 'Signal' goes from 'minBound' to 'maxBound'-isRising :: (Bounded a, Eq a)-         => a -- ^ Starting value-         -> Signal a-         -> Signal Bool-isRising = isRising' systemClock--{-# INLINE isFalling #-}--- | Give a pulse when the 'Signal' goes from 'maxBound' to 'minBound'-isFalling :: (Bounded a, Eq a)-          => a -- ^ Starting value-          -> Signal a-          -> Signal Bool-isFalling = isFalling' systemClock
src/CLaSH/Prelude/BitIndex.hs view
@@ -39,8 +39,8 @@ -- 0 -- >>> (7 :: Unsigned 6) ! 6 -- *** Exception: (!): 6 is out of range [5..0]-(!) :: (BitPack a, KnownNat (BitSize a), Integral i) => a -> i -> Bit-(!) v i = index# (pack v) (fromIntegral i)+(!) :: (BitPack a, KnownNat (BitSize a), Enum i) => a -> i -> Bit+(!) v i = index# (pack v) (fromEnum i)  {-# INLINE slice #-} -- | Get a slice between bit index @m@ and and bit index @n@.@@ -93,9 +93,9 @@ -- 01_1011 -- >>> replaceBit 6 0 (-5 :: Signed 6) -- *** Exception: replaceBit: 6 is out of range [5..0]-replaceBit :: (BitPack a, KnownNat (BitSize a), Integral i) => i -> Bit -> a+replaceBit :: (BitPack a, KnownNat (BitSize a), Enum i) => i -> Bit -> a            -> a-replaceBit i b v = unpack (replaceBit# (pack v) (fromIntegral i) b)+replaceBit i b v = unpack (replaceBit# (pack v) (fromEnum i) b)  {-# INLINE setSlice #-} -- | Set the bits between bit index @m@ and bit index @n@.
src/CLaSH/Prelude/BlockRam.hs view
@@ -1,25 +1,371 @@ {-# LANGUAGE DataKinds        #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MagicHash        #-} {-# LANGUAGE TypeOperators    #-}  {-# LANGUAGE Safe #-} +{-# OPTIONS_HADDOCK show-extensions #-}+ {-| Copyright  :  (C) 2013-2015, University of Twente License    :  BSD2 (see the file LICENSE) Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>++BlockRAM primitives++= Using RAMs #usingrams#++We will show a rather elaborate example on how you can, and why you might want+to use 'blockRam's. We will build a \"small\" CPU+Memory+Program ROM where we+will slowly evolve to using blockRams. Note that the code is /not/ meant as a+de-facto standard on how to do CPU design in CλaSH.++We start with the definition of the Instructions, Register names and machine+codes:++@+{\-\# LANGUAGE RecordWildCards \#-\}+module CPU where++import CLaSH.Prelude+import qualified Data.List as L++type InstrAddr = Unsigned 8+type MemAddr   = Unsigned 5+type Value     = Signed 8++data Instruction+  = Compute Operator Reg Reg Reg+  | Branch Reg Value+  | Jump Value+  | Load MemAddr Reg+  | Store Reg MemAddr+  | Nop+  deriving (Eq,Show)++data Reg+  = Zero+  | PC+  | RegA+  | RegB+  | RegC+  | RegD+  | RegE+  deriving (Eq,Show,Enum)++data Operator = Add | Sub | Incr | Imm | CmpGt+  deriving (Eq,Show)++data MachCode+  = MachCode+  { inputX  :: Reg+  , inputY  :: Reg+  , result  :: Reg+  , aluCode :: Operator+  , ldReg   :: Reg+  , rdAddr  :: MemAddr+  , wrAddr  :: MemAddr+  , wrEn    :: Bool+  , jmpM    :: Maybe Value+  }++nullCode = MachCode { inputX = Zero, inputY = Zero, result = Zero, aluCode = Imm+                    , ldReg = Zero, wrAddr = 0, rdAddr = 0, wrEn = False+                    , jmpM = Nothing+                    }+@++Next we define the CPU and its ALU:++@+cpu :: Vec 7 Value          -- ^ Register bank+    -> (Value,Instruction)  -- ^ (Memory output, Current instruction)+    -> ( Vec 7 Value+       , (MemAddr,MemAddr,Bool,Value,InstrAddr)+       )+cpu regbank (memOut,instr) = ((regbank',(rdAddr,wrAddr,wrEn,aluOut,fromIntegral ipntr))+  where+    -- Current instruction pointer+    ipntr = regbank '!!' PC++    -- Decoder+    (MachCode {..}) = case instr of+      Compute op rx ry res -> nullCode {inputX=rx,inputY=ry,result=res,aluCode=op}+      Branch cr a          -> nullCode {inputX=cr,jmpM=Just a}+      Jump a               -> nullCode {aluCode=Incr,jmpM=Just a}+      Load a r             -> nullCode {ldReg=r,rdAddr=a}+      Store r a            -> nullCode {inputX=r,wrAddr=a,wrEn=True}+      Nop                  -> nullCode++    -- ALU+    regX   = regbank '!!' inputX+    regY   = regbank '!!' inputY+    aluOut = alu aluCode regX regY++    -- next instruction+    nextPC = case jmpM of+               Just a | aluOut /= 0 -> ipntr + a+               _                    -> ipntr + 1++    -- update registers+    regbank' = 'replace' Zero   0+             $ 'replace' PC     nextPC+             $ 'replace' result aluOut+             $ 'replace' ldReg  memOut+             $ regbank++alu Add   x y = x + y+alu Sub   x y = x - y+alu Incr  x _ = x + 1+alu Imm   x _ = x+alu CmpGt x y = if x > y then 1 else 0+@++We initially create a memory out of simple registers:++@+dataMem :: Signal MemAddr -- ^ Read address+        -> Signal MemAddr -- ^ Write address+        -> Signal Bool    -- ^ Write enable+        -> Signal Value   -- ^ data in+        -> Signal Value   -- ^ data out+dataMem wr rd en din = 'CLaSH.Prelude.Mealy.mealy' dataMemT ('replicate' d32 0) (bundle (wr,rd,en,din))+  where+    dataMemT mem (wr,rd,en,din) = (mem',dout)+      where+        dout = mem '!!' rd+        mem' | en        = 'replace' wr din mem+             | otherwise = mem+@++And then connect everything:++@+system :: KnownNat n => Vec n Instruction -> Signal Value+system instrs = memOut+  where+    memOut = dataMem wrAddr rdAddr wrEn aluOut+    (rdAddr,wrAddr,wrEn,aluOut,ipntr) = 'CLaSH.Prelude.Mealy.mealyB' cpu (('replicate' d7 0),Zero) (memOut,instr)+    instr  = 'CLaSH.Prelude.ROM.asyncRom' instrs '<$>' ipntr+@++Create a simple program that calculates the GCD of 4 and 6:++@+-- Compute GCD of 4 and 6+prog = -- 0 := 4+       Compute Incr Zero RegA RegA :>+       replicate d3 (Compute Incr RegA Zero RegA) +++       Store RegA 0 :>+       -- 1 := 6+       Compute Incr Zero RegA RegA :>+       replicate d5 (Compute Incr RegA Zero RegA) +++       Store RegA 1 :>+       -- A := 4+       Load 0 RegA :>+       -- B := 6+       Load 1 RegB :>+       -- start+       Compute CmpGt RegA RegB RegC :>+       Branch RegC 4 :>+       Compute CmpGt RegB RegA RegC :>+       Branch RegC 4 :>+       Jump 5 :>+       -- (a > b)+       Compute Sub RegA RegB RegA :>+       Jump (-6) :>+       -- (b > a)+       Compute Sub RegB RegA RegB :>+       Jump (-8) :>+       -- end+       Store RegA 2 :>+       Load 2 RegC :>+       Nil+@++And test our system:++@+__>>> L.take 31 $ sample $ system prog__+[0,0,0,0,0,4,4,4,4,4,4,4,4,4,6,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2]+@++to see that our system indeed calculates that the GCD of 6 and 4 is 2.++=== Improvement 1: using @asyncRam@++As you can see, it's fairly straightforward to build a memory using registers+and read ('!!') and write ('replace') logic. This might however not result in+the most efficient hardware structure, especially when building an ASIC.++Instead it is preferable to use the 'CLaSH.Prelude.RAM.asyncRam' function which+has the potential to be translated to a more efficient structure:++@+system2 :: KnownNat n => Vec n Instruction -> Signal Value+system2 instrs = memOut+  where+    memOut = 'CLaSH.Prelude.RAM.asyncRam' d32 wrAddr rdAddr wrEn aluOut+    (rdAddr,wrAddr,wrEn,aluOut,ipntr) = 'mealyB' cpu (('replicate' d7 0),Zero) (memOut,instr)+    instr  = 'CLaSH.Prelude.ROM.asyncRom' instrs '<$>' ipntr+@++Again, we can simulate our system and see that it works. This time however,+we need to drop the first few output samples, because the initial content of an+'CLaSH.Prelude.RAM.asyncRam' is 'undefined', and consequently, the first few+output samples are also 'undefined'.++@+__>>> L.take 26 $ L.drop 5 $ sample $ system2 prog__+[4,4,4,4,4,4,4,4,4,6,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2]+@++=== Improvement 2: using @blockRam@++Finally we get to using 'blockRam'. On FPGAs, 'CLaSH.Prelude.RAM.asyncRam' will+be implemented in terms of LUTs, and therefore take up logic resources. FPGAs+also have large(r) memory structures called /Block RAMs/, which are preferred,+especially as the memories we need for our application get bigger. The+'blockRam' function will be translated to such a /Block RAM/.++One important aspect of Block RAMs have a /synchronous/ read port, meaning that,+unlike the behaviour of 'CLaSH.Prelude.RAM.asyncRam', given a read address @r@+at time @t@, the value @v@ in the RAM at address @r@ is only available at time+@t+1@.++For us that means we need to change the design of our CPU. Right now, upon a+load instruction we generate a read address for the memory, and the value at+that read address is immediately available to be put in the register bank.+Because we will be using a BlockRAM, the value is delayed until the next cycle.+We hence need to also delay the register address to which the memory address+is loaded:++@+cpu2 :: (Vec 7 Value,Reg)    -- ^ (Register bank, Load reg addr)+     -> (Value,Instruction)  -- ^ (Memory output, Current instruction)+     -> ( (Vec 7 Value,Reg)+        , (MemAddr,MemAddr,Bool,Value,InstrAddr)+        )+cpu2 (regbank,ldRegD) (memOut,instr) = (((regbank',ldRegD'),(rdAddr,wrAddr,wrEn,aluOut,fromIntegral ipntr))+  where+    -- Current instruction pointer+    ipntr = regbank '!!' PC++    -- Decoder+    (MachCode {..}) = case instr of+      Compute op rx ry res -> nullCode {inputX=rx,inputY=ry,result=res,aluCode=op}+      Branch cr a          -> nullCode {inputX=cr,jmpM=Just a}+      Jump a               -> nullCode {aluCode=Incr,jmpM=Just a}+      Load a r             -> nullCode {ldReg=r,rdAddr=a}+      Store r a            -> nullCode {inputX=r,wrAddr=a,wrEn=True}+      Nop                  -> nullCode++    -- ALU+    regX   = regbank '!!' inputX+    regY   = regbank '!!' inputY+    aluOut = alu aluCode regX regY++    -- next instruction+    nextPC = case jmpM of+               Just a | aluOut /= 0 -> ipntr + a+               _                    -> ipntr + 1++    -- update registers+    ldRegD'  = ldReg -- Delay the ldReg by 1 cycle+    regbank' = 'replace' Zero   0+             $ 'replace' PC     nextPC+             $ 'replace' result aluOut+             $ 'replace' ldRegD memOut+             $ regbank+@++We can now finally instantiate our system with a 'blockRam':++@+system3 :: KnownNat n => Vec n Instruction -> Signal Value+system3 instrs = memOut+  where+    memOut = 'blockRam' (replicate d32 0) wrAddr rdAddr wrEn aluOut+    (rdAddr,wrAddr,wrEn,aluOut,ipntr) = 'mealyB' cpu (('replicate' d7 0),Zero) (memOut,instr)+    instr  = 'CLaSH.Prelude.ROM.asyncRom' instrs '<$>' ipntr+@++We are, however, not done. We will also need to update our program. The reason+being that values that we try to load in our registers won't be loaded into the+register until the next cycle. This is a problem when the next instruction+immediately depended on this memory value. In our case, this was only the case+when the loaded the value @6@, which was stored at address @1@, into @RegB@.+Our updated program is thus:++@+prog2 = -- 0 := 4+       Compute Incr Zero RegA RegA :>+       replicate d3 (Compute Incr RegA Zero RegA) +++       Store RegA 0 :>+       -- 1 := 6+       Compute Incr Zero RegA RegA :>+       replicate d5 (Compute Incr RegA Zero RegA) +++       Store RegA 1 :>+       -- A := 4+       Load 0 RegA :>+       -- B := 6+       Load 1 RegB :>+       Nop :> -- Extra NOP+       -- start+       Compute CmpGt RegA RegB RegC :>+       Branch RegC 4 :>+       Compute CmpGt RegB RegA RegC :>+       Branch RegC 4 :>+       Jump 5 :>+       -- (a > b)+       Compute Sub RegA RegB RegA :>+       Jump (-6) :>+       -- (b > a)+       Compute Sub RegB RegA RegB :>+       Jump (-8) :>+       -- end+       Store RegA 2 :>+       Load 2 RegC :>+       Nil+@++When we simulate our system we see that it works. This time however,+we need to drop the first few sample, because the initial output of a+'blockRam' is 'undefined', and consequently, the first output sample is+also 'undefined'.++@+__>>> L.take 33 $ L.tail $ sample $ system3 prog2__+[4,4,4,4,4,4,4,4,4,6,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,2]+@++This concludes the short introduction to using 'blockRam'.+ -}-module CLaSH.Prelude.BlockRam where+module CLaSH.Prelude.BlockRam+  ( -- * BlockRAM synchronised to the system clock+    blockRam+  , blockRamPow2+    -- * BlockRAM synchronised to an arbitrary clock+  , blockRam'+  , blockRamPow2'+    -- * Internal+  , blockRam#+  )+where +import Control.Monad          (when)+import Control.Monad.ST.Lazy  (ST,runST)+import Data.Array.MArray.Safe (newListArray,readArray,writeArray)+import Data.Array.ST.Safe     (STArray) import GHC.TypeLits           (KnownNat, type (^))-import Prelude                hiding ((!!)) -import CLaSH.Prelude.Moore    (moore') import CLaSH.Signal           (Signal)-import CLaSH.Signal.Explicit  (Signal', SClock, systemClock)+import CLaSH.Signal.Explicit  (Signal', SClock, register', systemClock) import CLaSH.Signal.Bundle    (bundle') import CLaSH.Sized.Unsigned   (Unsigned)-import CLaSH.Sized.Vector     (Vec, (!!), replace)+import CLaSH.Sized.Vector     (Vec, maxIndex, toList)  {-# INLINE blockRam #-} -- | Create a blockRAM with space for @n@ elements.@@ -32,15 +378,20 @@ --        -> 'Signal' 'CLaSH.Sized.BitVector.Bit' -> Signal 'CLaSH.Sized.BitVector.Bit' -- bram40 = 'blockRam' ('CLaSH.Sized.Vector.replicate' d40 1) -- @-blockRam :: (KnownNat n, KnownNat m)-         => Vec n a             -- ^ Initial content of the BRAM, also-                                -- determines the size, @n@, of the BRAM.-                                ---                                -- __NB__: __MUST__ be a constant.-         -> Signal (Unsigned m) -- ^ Write address @w@-         -> Signal (Unsigned m) -- ^ Read address @r@-         -> Signal Bool         -- ^ Write enable-         -> Signal a            -- ^ Value to write (at address @w@)+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- Block RAM.+blockRam :: (KnownNat n, Enum addr)+         => Vec n a     -- ^ Initial content of the BRAM, also+                        -- determines the size, @n@, of the BRAM.+                        --+                        -- __NB__: __MUST__ be a constant.+         -> Signal addr -- ^ Write address @w@+         -> Signal addr -- ^ Read address @r@+         -> Signal Bool -- ^ Write enable+         -> Signal a    -- ^ Value to write (at address @w@)          -> Signal a          -- ^ Value of the @blockRAM@ at address @r@ from the previous clock          -- cycle@@ -57,6 +408,11 @@ --        -> 'Signal' 'CLaSH.Sized.BitVector.Bit' -> 'Signal' 'CLaSH.Sized.BitVector.Bit' -- bram32 = 'blockRamPow2' ('CLaSH.Sized.Vector.replicate' d32 1) -- @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- Block RAM. blockRamPow2 :: (KnownNat (2^n), KnownNat n)              => Vec (2^n) a         -- ^ Initial content of the BRAM, also                                     -- determines the size, @2^n@, of the BRAM.@@ -71,7 +427,7 @@              -- cycle blockRamPow2 = blockRam -{-# NOINLINE blockRam' #-}+{-# INLINE blockRam' #-} -- | Create a blockRAM with space for @n@ elements -- -- * __NB__: Read value is delayed by 1 cycle@@ -87,27 +443,26 @@ --        -> 'Signal'' ClkA Bool -> 'Signal'' ClkA 'CLaSH.Sized.BitVector.Bit' -> ClkA 'Signal'' 'CLaSH.Sized.BitVector.Bit' -- bram40 = 'blockRam'' clkA100 ('CLaSH.Sized.Vector.replicate' d40 1) -- @-blockRam' :: (KnownNat n, KnownNat m)-          => SClock clk               -- ^ 'Clock' to synchronize to-          -> Vec n a                  -- ^ Initial content of the BRAM, also-                                      -- determines the size, @n@, of the BRAM.-                                      ---                                      -- __NB__: __MUST__ be a constant.-          -> Signal' clk (Unsigned m) -- ^ Write address @w@-          -> Signal' clk (Unsigned m) -- ^ Read address @r@-          -> Signal' clk Bool         -- ^ Write enable-          -> Signal' clk a            -- ^ Value to write (at address @w@)+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- Block RAM.+blockRam' :: (KnownNat n, Enum addr)+          => SClock clk       -- ^ 'Clock' to synchronize to+          -> Vec n a          -- ^ Initial content of the BRAM, also+                              -- determines the size, @n@, of the BRAM.+                              --+                              -- __NB__: __MUST__ be a constant.+          -> Signal' clk addr -- ^ Write address @w@+          -> Signal' clk addr -- ^ Read address @r@+          -> Signal' clk Bool -- ^ Write enable+          -> Signal' clk a    -- ^ Value to write (at address @w@)           -> Signal' clk a           -- ^ Value of the @blockRAM@ at address @r@ from the previous clock           -- cycle-blockRam' clk binit wr rd en din =-    moore' clk bram' snd (binit,undefined) (bundle' clk (wr,rd,en,din))-  where-    bram' (ram,_) (w,r,e,d) = (ram',o')-      where-        ram' | e         = replace w d ram-             | otherwise = ram-        o'               = ram !! r+blockRam' clk content wr rd en din = blockRam# clk content (fromEnum <$> wr)+                                               (fromEnum <$> rd) en din  {-# INLINE blockRamPow2' #-} -- | Create a blockRAM with space for 2^@n@ elements@@ -125,6 +480,11 @@ --        -> 'Signal'' ClkA Bool -> 'Signal'' ClkA 'CLaSH.Sized.BitVector.Bit' -> Signal' ClkA 'CLaSH.Sized.BitVector.Bit' -- bram32 = 'blockRamPow2'' clkA100 ('CLaSH.Sized.Vector.replicate' d32 1) -- @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- Block RAM. blockRamPow2' :: (KnownNat n, KnownNat (2^n))               => SClock clk               -- ^ 'Clock' to synchronize to               -> Vec (2^n) a              -- ^ Initial content of the BRAM, also@@ -140,3 +500,31 @@               -- ^ Value of the @blockRAM@ at address @r@ from the previous               -- clock cycle blockRamPow2' = blockRam'++{-# NOINLINE blockRam# #-}+-- | blockRAM primitive+blockRam# :: KnownNat n+          => SClock clk       -- ^ 'Clock' to synchronize to+          -> Vec n a          -- ^ Initial content of the BRAM, also+                              -- determines the size, @n@, of the BRAM.+                              --+                              -- __NB__: __MUST__ be a constant.+          -> Signal' clk Int  -- ^ Write address @w@+          -> Signal' clk Int  -- ^ Read address @r@+          -> Signal' clk Bool -- ^ Write enable+          -> Signal' clk a    -- ^ Value to write (at address @w@)+          -> Signal' clk a+          -- ^ Value of the @blockRAM@ at address @r@ from the previous clock+          -- cycle+blockRam# clk content wr rd en din = register' clk undefined dout+  where+    szI  = fromInteger $ maxIndex content+    dout = runST $ do+      arr <- newListArray (0,szI) (toList content)+      traverse (ramT arr) (bundle' clk (wr,rd,en,din))++    ramT :: STArray s Int e -> (Int,Int,Bool,e) -> ST s e+    ramT ram (w,r,e,d) = do+      d' <- readArray ram r+      when e (writeArray ram w d)+      return d'
+ src/CLaSH/Prelude/BlockRam/File.hs view
@@ -0,0 +1,300 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE MagicHash           #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators       #-}++{-# LANGUAGE Unsafe #-}++{-# OPTIONS_HADDOCK show-extensions #-}++{-|+Copyright  :  (C) 2015, University of Twente+License    :  BSD2 (see the file LICENSE)+Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>++= Initialising a BlockRAM with a data file #usingramfiles#++BlockRAM primitives that can be initialised with a data file. The BNF grammar+for this data file is simple:++@+FILE = LINE++LINE = BIT++BIT  = '0'+     | '1'+@++Consecutive @LINE@s correspond to consecutive memory addresses starting at @0@.+For example, a data file @memory.bin@ containing the 9-bit unsigned number+@7@ to @13@ looks like:++@+000000111+000001000+000001001+000001010+000001011+000001100+000001101+@++We can instantiate a BlockRAM using the content of the above file like so:++@+topEntity :: Signal (Unsigned 3) -> Signal (Unsigned 9)+topEntity rd = 'CLaSH.Class.BitPack.unpack' '<$>' 'blockRamFile' d7 \"memory.bin\" 0 rd (signal False) 0+@++In the example above, we basically treat the BlockRAM as an synchronous ROM.+We can see that it works as expected:++@+__>>> import qualified Data.List as L__+__>>> L.tail $ sampleN 4 $ topEntity (fromList [3..5])__+[10,11,12]+@++However, we can also interpret the same data as a tuple of a 6-bit unsigned+number, and a 3-bit signed number:++@+topEntity2 :: Signal (Unsigned 3) -> Signal (Unsigned 6,Signed 3)+topEntity2 rd = 'CLaSH.Class.BitPack.unpack' '<$>' 'blockRamFile' d7 \"memory.bin\" 0 rd (signal False) 0+@++And then we would see:++@+__>>> import qualified Data.List as L__+__>>> L.tail $ sampleN 4 $ topEntity2 (fromList [3..5])__+[(1,2),(1,3)(1,-4)]+@++-}+module CLaSH.Prelude.BlockRam.File+  ( -- * BlockRAM synchronised to the system clock+    blockRamFile+  , blockRamFilePow2+    -- * BlockRAM synchronised to an arbitrary clock+  , blockRamFile'+  , blockRamFilePow2'+    -- * Internal+  , blockRamFile#+  , initMem+  )+where+++import Control.Monad         (when)+import Control.Monad.ST.Lazy (ST,runST)+import Data.Array.MArray     (newListArray,readArray,writeArray)+import Data.Array.ST         (STArray)+import Data.Char             (digitToInt)+import Data.Maybe            (listToMaybe)+import GHC.TypeLits          (KnownNat, type (^))+import Numeric               (readInt)+import System.IO.Unsafe      (unsafePerformIO)++import CLaSH.Promoted.Nat    (SNat,snat,snatToInteger)+import CLaSH.Sized.BitVector (BitVector)+import CLaSH.Signal          (Signal)+import CLaSH.Signal.Explicit (Signal', SClock, register', systemClock)+import CLaSH.Signal.Bundle   (bundle')+import CLaSH.Sized.Unsigned  (Unsigned)++{-# INLINE blockRamFile #-}+-- | Create a blockRAM with space for @n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- Block RAM.+-- * See "CLaSH.Prelude.BlockRam.File#usingramfiles" for more information on how+-- to instantiate a Block RAM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+blockRamFile :: (KnownNat m, Enum addr)+             => SNat n               -- ^ Size of the blockRAM+             -> FilePath             -- ^ File describing the initial content+                                     -- of the blockRAM+             -> Signal addr          -- ^ Write address @w@+             -> Signal addr          -- ^ Read address @r@+             -> Signal Bool          -- ^ Write enable+             -> Signal (BitVector m) -- ^ Value to write (at address @w@)+             -> Signal (BitVector m)+             -- ^ Value of the @blockRAM@ at address @r@ from the previous clock+             -- cycle+blockRamFile = blockRamFile' systemClock++{-# INLINE blockRamFilePow2 #-}+-- | Create a blockRAM with space for 2^@n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- Block RAM.+-- * See "CLaSH.Prelude.BlockRam.File#usingramfiles" for more information on how+-- to instantiate a Block RAM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+blockRamFilePow2 :: forall n m . (KnownNat m, KnownNat n, KnownNat (2^n))+                 => FilePath             -- ^ File describing the initial+                                         -- content of the blockRAM+                 -> Signal (Unsigned n)  -- ^ Write address @w@+                 -> Signal (Unsigned n)  -- ^ Read address @r@+                 -> Signal Bool          -- ^ Write enable+                 -> Signal (BitVector m) -- ^ Value to write (at address @w@)+                 -> Signal (BitVector m)+                 -- ^ Value of the @blockRAM@ at address @r@ from the previous+                 -- clock cycle+blockRamFilePow2 = blockRamFile' systemClock (snat :: SNat (2^n))++{-# INLINE blockRamFilePow2' #-}+-- | Create a blockRAM with space for 2^@n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- Block RAM.+-- * See "CLaSH.Prelude.BlockRam.File#usingramfiles" for more information on how+-- to instantiate a Block RAM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+blockRamFilePow2' :: forall clk n m . (KnownNat m, KnownNat n, KnownNat (2^n))+                  => SClock clk                -- ^ 'Clock' to synchronize to+                  -> FilePath                  -- ^ File describing the initial+                                               -- content of the blockRAM+                  -> Signal' clk (Unsigned n)  -- ^ Write address @w@+                  -> Signal' clk (Unsigned n)  -- ^ Read address @r@+                  -> Signal' clk Bool          -- ^ Write enable+                  -> Signal' clk (BitVector m) -- ^ Value to write (at address @w@)+                  -> Signal' clk (BitVector m)+                  -- ^ Value of the @blockRAM@ at address @r@ from the previous+                  -- clock cycle+blockRamFilePow2' clk = blockRamFile' clk (snat :: SNat (2^n))++{-# INLINE blockRamFile' #-}+-- | Create a blockRAM with space for @n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- Block RAM.+-- * See "CLaSH.Prelude.BlockRam.File#usingramfiles" for more information on how+-- to instantiate a Block RAM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+blockRamFile' :: (KnownNat m, Enum addr)+              => SClock clk                -- ^ 'Clock' to synchronize to+              -> SNat n                    -- ^ Size of the blockRAM+              -> FilePath                  -- ^ File describing the initial+                                           -- content of the blockRAM+              -> Signal' clk addr          -- ^ Write address @w@+              -> Signal' clk addr          -- ^ Read address @r@+              -> Signal' clk Bool          -- ^ Write enable+              -> Signal' clk (BitVector m) -- ^ Value to write (at address @w@)+              -> Signal' clk (BitVector m)+              -- ^ Value of the @blockRAM@ at address @r@ from the previous+              -- clock cycle+blockRamFile' clk sz file wr rd en din = blockRamFile# clk sz file+                                                       (fromEnum <$> wr)+                                                       (fromEnum <$> rd)+                                                       en din++{-# NOINLINE blockRamFile# #-}+-- | blockRamFile primitive+blockRamFile# :: KnownNat m+              => SClock clk                -- ^ 'Clock' to synchronize to+              -> SNat n                    -- ^ Size of the blockRAM+              -> FilePath                  -- ^ File describing the initial+                                           -- content of the blockRAM+              -> Signal' clk Int           -- ^ Write address @w@+              -> Signal' clk Int           -- ^ Read address @r@+              -> Signal' clk Bool          -- ^ Write enable+              -> Signal' clk (BitVector m) -- ^ Value to write (at address @w@)+              -> Signal' clk (BitVector m)+              -- ^ Value of the @blockRAM@ at address @r@ from the previous+              -- clock cycle+blockRamFile# clk sz file wr rd en din = register' clk undefined dout+  where+    szI  = fromInteger $ snatToInteger sz+    dout = runST $ do+      arr <- newListArray (0,szI-1) (initMem file)+      traverse (ramT arr) (bundle' clk (wr,rd,en,din))++    ramT :: STArray s Int e -> (Int,Int,Bool,e) -> ST s e+    ramT ram (w,r,e,d) = do+      d' <- readArray ram r+      when e (writeArray ram w d)+      return d'++{-# NOINLINE initMem #-}+-- | __NB:__ Not synthesisable+initMem :: KnownNat n => FilePath -> [BitVector n]+initMem = unsafePerformIO . fmap (map parseBV . lines) . readFile+  where+    parseBV s = case parseBV' s of+                  Just i  -> fromInteger i+                  Nothing -> error ("Failed to parse: " ++ s)+    parseBV' = fmap fst . listToMaybe . readInt 2 (`elem` "01") digitToInt
src/CLaSH/Prelude/Explicit.hs view
@@ -26,15 +26,31 @@   , moore'   , mooreB'   , registerB'+    -- * Synchronizer circuits for safe clock domain crossings+  , dualFlipFlopSynchronizer+  , asyncFIFOSynchronizer+    -- * ROMs+  , rom'+  , romPow2'+    -- ** ROMs initialised with a data file+  , romFile'+  , romFilePow2'+    -- * RAM primitives with a combinational read port+  , asyncRam'+  , asyncRamPow2'     -- * BlockRAM primitives   , blockRam'   , blockRamPow2'+    -- ** BlockRAM primitives initialised with a data file+  , blockRamFile'+  , blockRamFilePow2'     -- * Utility functions   , window'   , windowD'   , isRising'   , isFalling'     -- * Testbench functions+  , assert'   , stimuliGenerator'   , outputVerifier'     -- * Exported modules@@ -43,45 +59,24 @@   ) where -import Control.Applicative     (liftA2)-import Data.Default            (Default (..))-import GHC.TypeLits            (KnownNat, type (+), natVal)-import Prelude                 hiding (repeat)+import Data.Default                 (Default (..))+import GHC.TypeLits                 (KnownNat, type (+), natVal)+import Prelude                      hiding (repeat) -import CLaSH.Prelude.BlockRam  (blockRam', blockRamPow2')-import CLaSH.Prelude.Mealy     (mealy', mealyB')-import CLaSH.Prelude.Moore     (moore', mooreB')-import CLaSH.Prelude.Testbench (stimuliGenerator', outputVerifier')+import CLaSH.Prelude.Explicit.Safe+import CLaSH.Prelude.BlockRam.File (blockRamFile', blockRamFilePow2')+import CLaSH.Prelude.ROM.File      (romFile', romFilePow2')+import CLaSH.Prelude.Testbench     (assert', stimuliGenerator', outputVerifier') import CLaSH.Signal.Explicit-import CLaSH.Sized.Vector      (Vec (..), (+>>), asNatProxy, repeat)+import CLaSH.Sized.Vector          (Vec (..), (+>>), asNatProxy, repeat)  -- $setup -- >>> :set -XDataKinds -- >>> type ClkA = Clk "A" 100 -- >>> let clkA = sclock :: SClock ClkA--- >>> let rP = registerB' clkA (8::Int,8::Int) -- >>> let window4 = window' clkA :: Signal' ClkA Int -> Vec 4 (Signal' ClkA Int) -- >>> let windowD3 = windowD' clkA :: Signal' ClkA Int -> Vec 3 (Signal' ClkA Int) -{-# INLINE registerB' #-}--- | Create a 'register' function for product-type like signals (e.g.--- @('Signal' a, 'Signal' b)@)------ @--- type ClkA = 'Clk' \"A\" 100------ clkA :: 'SClock' ClkA--- clkA = 'sclock'------ rP :: ('Signal'' ClkA Int, 'Signal'' ClkA Int) -> ('Signal'' ClkA Int, 'Signal'' ClkA Int)--- rP = 'registerB'' clkA (8,8)--- @------ >>> simulateB' clkA clkA rP [(1,1),(2,2),(3,3)] :: [(Int,Int)]--- [(8,8),(1,1),(2,2),(3,3)...-registerB' :: Bundle a => SClock clk -> a -> Unbundled' clk a -> Unbundled' clk a-registerB' clk i = unbundle' clk Prelude.. register' clk i Prelude.. bundle' clk- {-# INLINABLE window' #-} -- | Give a window over a 'Signal'' --@@ -134,27 +129,3 @@   where     prev = registerB' clk (repeat def) next     next = x +>> prev--{-# INLINABLE isRising' #-}--- | Give a pulse when the 'Signal'' goes from 'minBound' to 'maxBound'-isRising' :: (Bounded a, Eq a)-          => SClock clk-          -> a -- ^ Starting value-          -> Signal' clk a-          -> Signal' clk Bool-isRising' clk is s = liftA2 edgeDetect prev s-  where-    prev = register' clk is s-    edgeDetect old new = old == minBound && new == maxBound--{-# INLINABLE isFalling' #-}--- | Give a pulse when the 'Signal'' goes from 'maxBound' to 'minBound'-isFalling' :: (Bounded a, Eq a)-           => SClock clk-           -> a -- ^ Starting value-           -> Signal' clk a-           -> Signal' clk Bool-isFalling' clk is s = liftA2 edgeDetect prev s-  where-    prev = register' clk is s-    edgeDetect old new = old == maxBound && new == minBound
+ src/CLaSH/Prelude/Explicit/Safe.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE DataKinds        #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators    #-}++{-# LANGUAGE Safe #-}++{-# OPTIONS_HADDOCK show-extensions #-}++{-|+Copyright  :  (C) 2013-2015, University of Twente+License    :  BSD2 (see the file LICENSE)+Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>++__This is the <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/safe-haskell.html Safe> API only of "CLaSH.Prelude.Explicit"__++This module defines the explicitly clocked counterparts of the functions+defined in "CLaSH.Prelude".++This module uses the explicitly clocked 'Signal'' synchronous signals, as+opposed to the implicitly clocked 'Signal' used in "CLaSH.Prelude". Take a+look at "CLaSH.Signal.Explicit" to see how you can make multi-clock designs+using explicitly clocked signals.+-}+module CLaSH.Prelude.Explicit.Safe+  ( -- * Creating synchronous sequential circuits+    mealy'+  , mealyB'+  , moore'+  , mooreB'+  , registerB'+    -- * Synchronizer circuits for safe clock domain crossing+  , dualFlipFlopSynchronizer+  , asyncFIFOSynchronizer+    -- * ROMs+  , rom'+  , romPow2'+    -- * RAM primitives with a combinational read port+  , asyncRam'+  , asyncRamPow2'+    -- * BlockRAM primitives+  , blockRam'+  , blockRamPow2'+    -- * Utility functions+  , isRising'+  , isFalling'+    -- * Exported modules+    -- ** Explicitly clocked synchronous signals+  , module CLaSH.Signal.Explicit+  )+where++import Control.Applicative        (liftA2)+import Prelude                    hiding (repeat)++import CLaSH.Prelude.BlockRam     (blockRam', blockRamPow2')+import CLaSH.Prelude.Mealy        (mealy', mealyB')+import CLaSH.Prelude.Moore        (moore', mooreB')+import CLaSH.Prelude.RAM          (asyncRam',asyncRamPow2')+import CLaSH.Prelude.ROM          (rom', romPow2')+import CLaSH.Prelude.Synchronizer (dualFlipFlopSynchronizer,+                                   asyncFIFOSynchronizer)+import CLaSH.Signal.Explicit++-- $setup+-- >>> :set -XDataKinds+-- >>> type ClkA = Clk "A" 100+-- >>> let clkA = sclock :: SClock ClkA+-- >>> let rP = registerB' clkA (8::Int,8::Int)++{-# INLINE registerB' #-}+-- | Create a 'register' function for product-type like signals (e.g.+-- @('Signal' a, 'Signal' b)@)+--+-- @+-- type ClkA = 'Clk' \"A\" 100+--+-- clkA :: 'SClock' ClkA+-- clkA = 'sclock'+--+-- rP :: ('Signal'' ClkA Int, 'Signal'' ClkA Int) -> ('Signal'' ClkA Int, 'Signal'' ClkA Int)+-- rP = 'registerB'' clkA (8,8)+-- @+--+-- >>> simulateB' clkA clkA rP [(1,1),(2,2),(3,3)] :: [(Int,Int)]+-- [(8,8),(1,1),(2,2),(3,3)...+registerB' :: Bundle a => SClock clk -> a -> Unbundled' clk a -> Unbundled' clk a+registerB' clk i = unbundle' clk Prelude.. register' clk i Prelude.. bundle' clk++{-# INLINABLE isRising' #-}+-- | Give a pulse when the 'Signal'' goes from 'minBound' to 'maxBound'+isRising' :: (Bounded a, Eq a)+          => SClock clk+          -> a -- ^ Starting value+          -> Signal' clk a+          -> Signal' clk Bool+isRising' clk is s = liftA2 edgeDetect prev s+  where+    prev = register' clk is s+    edgeDetect old new = old == minBound && new == maxBound++{-# INLINABLE isFalling' #-}+-- | Give a pulse when the 'Signal'' goes from 'maxBound' to 'minBound'+isFalling' :: (Bounded a, Eq a)+           => SClock clk+           -> a -- ^ Starting value+           -> Signal' clk a+           -> Signal' clk Bool+isFalling' clk is s = liftA2 edgeDetect prev s+  where+    prev = register' clk is s+    edgeDetect old new = old == maxBound && new == minBound
+ src/CLaSH/Prelude/RAM.hs view
@@ -0,0 +1,149 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE MagicHash           #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies        #-}+{-# LANGUAGE TypeOperators       #-}++{-# LANGUAGE Safe #-}++{-# OPTIONS_HADDOCK show-extensions #-}++{-|+Copyright  :  (C) 2015, University of Twente+License    :  BSD2 (see the file LICENSE)+Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>++RAM primitives with a combinational read port.+-}+module CLaSH.Prelude.RAM+  ( -- * RAM synchronised to the system clock+    asyncRam+  , asyncRamPow2+    -- * RAM synchronised to an arbitrary clock+  , asyncRam'+  , asyncRamPow2'+    -- * Internal+  , asyncRam#+  )+where++import Control.Monad          (when)+import Control.Monad.ST.Lazy  (ST,runST)+import Data.Array.MArray.Safe (newArray_,readArray,writeArray)+import Data.Array.ST.Safe     (STArray)+import GHC.TypeLits           (KnownNat, type (^))++import CLaSH.Promoted.Nat     (SNat,snat,snatToInteger)+import CLaSH.Signal           (Signal)+import CLaSH.Signal.Bundle    (bundle')+import CLaSH.Signal.Explicit  (Signal', SClock, systemClock, unsafeSynchronizer)+import CLaSH.Sized.Unsigned   (Unsigned)++{-# INLINE asyncRam #-}+-- | Create a RAM with space for @n@ elements.+--+-- * __NB__: Initial content of the RAM is 'undefined'+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- RAM.+asyncRam :: (KnownNat n, Enum addr)+         => SNat n      -- ^ Size @n@ of the RAM+         -> Signal addr -- ^ Write address @w@+         -> Signal addr -- ^ Read address @r@+         -> Signal Bool -- ^ Write enable+         -> Signal a    -- ^ Value to write (at address @w@)+         -> Signal a    -- ^ Value of the @RAM@ at address @r@+asyncRam = asyncRam' systemClock systemClock++{-# INLINE asyncRamPow2 #-}+-- | Create a RAM with space for 2^@n@ elements+--+-- * __NB__: Initial content of the RAM is 'undefined'+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- RAM.+asyncRamPow2 :: forall n a . (KnownNat (2^n), KnownNat n)+             => Signal (Unsigned n) -- ^ Write address @w@+             -> Signal (Unsigned n) -- ^ Read address @r@+             -> Signal Bool         -- ^ Write enable+             -> Signal a            -- ^ Value to write (at address @w@)+             -> Signal a            -- ^ Value of the @RAM@ at address @r@+asyncRamPow2 = asyncRam' systemClock systemClock (snat :: SNat (2^n))++{-# INLINE asyncRamPow2' #-}+-- | Create a RAM with space for 2^@n@ elements+--+-- * __NB__: Initial content of the RAM is 'undefined'+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- RAM.+asyncRamPow2' :: forall wclk rclk n a .+                 (KnownNat n, KnownNat (2^n))+              => SClock wclk               -- ^ 'Clock' to which to synchronise+                                           -- the write port of the RAM+              -> SClock rclk               -- ^ 'Clock' to which the read+                                           -- address signal, @r@, is+                                           -- synchronised+              -> Signal' wclk (Unsigned n) -- ^ Write address @w@+              -> Signal' rclk (Unsigned n) -- ^ Read address @r@+              -> Signal' wclk Bool         -- ^ Write enable+              -> Signal' wclk a            -- ^ Value to write (at address @w@)+              -> Signal' rclk a+              -- ^ Value of the @RAM@ at address @r@+asyncRamPow2' wclk rclk = asyncRam' wclk rclk (snat :: SNat (2^n))++{-# INLINE asyncRam' #-}+-- | Create a RAM with space for @n@ elements+--+-- * __NB__: Initial content of the RAM is 'undefined'+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.BlockRam#usingrams" for more information on how to use a+-- RAM.+asyncRam' :: (KnownNat n, Enum addr)+          => SClock wclk       -- ^ 'Clock' to which to synchronise the write+                               -- port of the RAM+          -> SClock rclk       -- ^ 'Clock' to which the read address signal,+                               -- @r@, is synchronised+          -> SNat n            -- ^ Size @n@ of the RAM+          -> Signal' wclk addr -- ^ Write address @w@+          -> Signal' rclk addr -- ^ Read address @r@+          -> Signal' wclk Bool -- ^ Write enable+          -> Signal' wclk a    -- ^ Value to write (at address @w@)+          -> Signal' rclk a    -- ^ Value of the @RAM@ at address @r@+asyncRam' wclk rclk sz wr rd en din = asyncRam# wclk rclk sz (fromEnum <$> wr)+                                                (fromEnum <$> rd) en din++{-# NOINLINE asyncRam# #-}+-- | RAM primitive+asyncRam# :: SClock wclk       -- ^ 'Clock' to which to synchronise the write+                               -- port of the RAM+          -> SClock rclk       -- ^ 'Clock' to which the read address signal,+                               -- @r@, is synchronised+          -> SNat n            -- ^ Size @n@ of the RAM+          -> Signal' wclk Int  -- ^ Write address @w@+          -> Signal' rclk Int  -- ^ Read address @r@+          -> Signal' wclk Bool -- ^ Write enable+          -> Signal' wclk a    -- ^ Value to write (at address @w@)+          -> Signal' rclk a    -- ^ Value of the @RAM@ at address @r@+asyncRam# wclk rclk sz wr rd en din = unsafeSynchronizer wclk rclk dout+  where+    szI  = fromInteger $ snatToInteger sz+    rd'  = unsafeSynchronizer rclk wclk rd+    dout = runST $ do+      arr <- newArray_ (0,szI-1)+      traverse (ramT arr) (bundle' wclk (wr,rd',en,din))++    ramT :: STArray s Int e -> (Int,Int,Bool,e) -> ST s e+    ramT ram (w,r,e,d) = do+      d' <- readArray ram r+      when e (writeArray ram w d)+      return d'
+ src/CLaSH/Prelude/ROM.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE DataKinds        #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MagicHash        #-}+{-# LANGUAGE TypeOperators    #-}++{-# LANGUAGE Safe #-}++{-# OPTIONS_HADDOCK show-extensions #-}++{-|+Copyright  :  (C) 2015, University of Twente+License    :  BSD2 (see the file LICENSE)+Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>++ROMs+-}+module CLaSH.Prelude.ROM+  ( -- * Asynchronous ROM+    asyncRom+  , asyncRomPow2+    -- * Synchronous ROM synchronised to the system clock+  , rom+  , romPow2+    -- * Synchronous ROM synchronised to an arbitrary clock+  , rom'+  , romPow2'+    -- * Internal+  , asyncRom#+  , rom#+  )+where++import Data.Array             ((!),listArray)+import GHC.TypeLits           (KnownNat, type (^))++import CLaSH.Signal           (Signal)+import CLaSH.Signal.Explicit  (Signal', SClock, systemClock)+import CLaSH.Sized.Unsigned   (Unsigned)+import CLaSH.Signal.Explicit  (register')+import CLaSH.Sized.Vector     (Vec, maxIndex, toList)++{-# INLINE asyncRom #-}+-- | An asynchronous/combinational ROM with space for @n@ elements+--+-- Additional helpful information:+--+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams"+-- for ideas on how to use ROMs and RAMs+asyncRom :: (KnownNat n, Enum addr)+         => Vec n a -- ^ ROM content+                    --+                    -- __NB:__ must be a constant+         -> addr    -- ^ Read address @rd@+         -> a       -- ^ The value of the ROM at address @rd@+asyncRom content rd = asyncRom# content (fromEnum rd)++{-# INLINE asyncRomPow2 #-}+-- | An asynchronous/combinational ROM with space for 2^@n@ elements+--+-- Additional helpful information:+--+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams"+-- for ideas on how to use ROMs and RAMs+asyncRomPow2 :: (KnownNat (2^n), KnownNat n)+             => Vec (2^n) a -- ^ ROM content+                            --+                            -- __NB:__ must be a constant+             -> Unsigned n  -- ^ Read address @rd@+             -> a           -- ^ The value of the ROM at address @rd@+asyncRomPow2 = asyncRom++{-# NOINLINE asyncRom# #-}+-- | asyncROM primitive+asyncRom# :: KnownNat n+          => Vec n a  -- ^ ROM content+                      --+                      -- __NB:__ must be a constant+          -> Int      -- ^ Read address @rd@+          -> a        -- ^ The value of the ROM at address @rd@+asyncRom# content rd = arr ! rd+  where+    szI = fromInteger (maxIndex content)+    arr = listArray (0,szI) (toList content)++{-# INLINE rom #-}+-- | A ROM with a synchronous read port, with space for @n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+--+-- Additional helpful information:+--+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams"+-- for ideas on how to use ROMs and RAMs+rom :: (KnownNat n, KnownNat m)+    => Vec n a               -- ^ ROM content+                             --+                             -- __NB:__ must be a constant+    -> Signal (Unsigned m)   -- ^ Read address @rd@+    -> Signal a              -- ^ The value of the ROM at address @rd@+rom = rom' systemClock++{-# INLINE romPow2 #-}+-- | A ROM with a synchronous read port, with space for 2^@n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+--+-- Additional helpful information:+--+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams"+-- for ideas on how to use ROMs and RAMs+romPow2 :: (KnownNat (2^n), KnownNat n)+        => Vec (2^n) a         -- ^ ROM content+                               --+                               -- __NB:__ must be a constant+        -> Signal (Unsigned n) -- ^ Read address @rd@+        -> Signal a            -- ^ The value of the ROM at address @rd@+romPow2 = rom' systemClock++{-# INLINE romPow2' #-}+-- | A ROM with a synchronous read port, with space for 2^@n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+--+-- Additional helpful information:+--+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams"+-- for ideas on how to use ROMs and RAMs+romPow2' :: (KnownNat (2^n), KnownNat n)+         => SClock clk               -- ^ 'Clock' to synchronize to+         -> Vec (2^n) a              -- ^ ROM content+                                     --+                                     -- __NB:__ must be a constant+         -> Signal' clk (Unsigned n) -- ^ Read address @rd@+         -> Signal' clk a            -- ^ The value of the ROM at address @rd@+romPow2' = rom'++{-# INLINE rom' #-}+-- | A ROM with a synchronous read port, with space for @n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+--+-- Additional helpful information:+--+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" and "CLaSH.Prelude.BlockRam#usingrams"+-- for ideas on how to use ROMs and RAMs+rom' :: (KnownNat n, Enum addr)+     => SClock clk       -- ^ 'Clock' to synchronize to+     -> Vec n a          -- ^ ROM content+                         --+                         -- __NB:__ must be a constant+     -> Signal' clk addr -- ^ Read address @rd@+     -> Signal' clk a+     -- ^ The value of the ROM at address @rd@ from the previous clock cycle+rom' clk content rd = rom# clk content (fromEnum <$> rd)++{-# NOINLINE rom# #-}+-- | ROM primitive+rom# :: KnownNat n+     => SClock clk      -- ^ 'Clock' to synchronize to+     -> Vec n a         -- ^ ROM content+                        --+                        -- __NB:__ must be a constant+     -> Signal' clk Int -- ^ Read address @rd@+     -> Signal' clk a+     -- ^ The value of the ROM at address @rd@ from the previous clock cycle+rom# clk content rd = register' clk undefined ((arr !) <$> rd)+  where+    szI = fromInteger (maxIndex content)+    arr = listArray (0,szI) (toList content)
+ src/CLaSH/Prelude/ROM/File.hs view
@@ -0,0 +1,312 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE MagicHash           #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators       #-}++{-# LANGUAGE Unsafe #-}++{-# OPTIONS_HADDOCK show-extensions #-}++{-|+Copyright  :  (C) 2015, University of Twente+License    :  BSD2 (see the file LICENSE)+Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>++= Initialising a ROM with a data file #usingromfiles#++ROMs initialised with a data file. The BNF grammar for this data file is simple:++@+FILE = LINE++LINE = BIT++BIT  = '0'+     | '1'+@++Consecutive @LINE@s correspond to consecutive memory addresses starting at @0@.+For example, a data file @memory.bin@ containing the 9-bit unsigned number+@7@ to @13@ looks like:++@+000000111+000001000+000001001+000001010+000001011+000001100+000001101+@++We can instantiate a synchronous ROM using the content of the above file like+so:++@+topEntity :: Signal (Unsigned 3) -> Signal (Unsigned 9)+topEntity rd = 'CLaSH.Class.BitPack.unpack' '<$>' 'romFile' d7 \"memory.bin\" rd+@++And see that it works as expected:++@+__>>> import qualified Data.List as L__+__>>> L.tail $ sampleN 4 $ topEntity (fromList [3..5])__+[10,11,12]+@++However, we can also interpret the same data as a tuple of a 6-bit unsigned+number, and a 3-bit signed number:++@+topEntity2 :: Signal (Unsigned 3) -> Signal (Unsigned 6,Signed 3)+topEntity2 rd = 'CLaSH.Class.BitPack.unpack' '<$>' 'romFile' d7 \"memory.bin\" rd+@++And then we would see:++@+__>>> import qualified Data.List as L__+__>>> L.tail $ sampleN 4 $ topEntity2 (fromList [3..5])__+[(1,2),(1,3)(1,-4)]+@+-}+module CLaSH.Prelude.ROM.File+  ( -- * Asynchronous ROM+    asyncRomFile+  , asyncRomFilePow2+    -- * Synchronous ROM synchronised to the system clock+  , romFile+  , romFilePow2+    -- * Synchronous ROM synchronised to an arbitrary clock+  , romFile'+  , romFilePow2'+    -- * Internal+  , asyncRomFile#+  , romFile#+  )+where++import Data.Array                  (listArray,(!))+import GHC.TypeLits                (KnownNat, type (^))++import CLaSH.Prelude.BlockRam.File (initMem)+import CLaSH.Promoted.Nat          (SNat,snat,snatToInteger)+import CLaSH.Sized.BitVector       (BitVector)+import CLaSH.Signal                (Signal)+import CLaSH.Signal.Explicit       (Signal', SClock, register', systemClock)+import CLaSH.Sized.Unsigned        (Unsigned)++{-# INLINE asyncRomFile #-}+-- | An asynchronous/combinational ROM with space for @n@ elements+--+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how+-- to instantiate a ROM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+asyncRomFile :: (KnownNat m, Enum addr)+             => SNat n      -- ^ Size of the ROM+             -> FilePath    -- ^ File describing the content of the ROM+             -> addr        -- ^ Read address @rd@+             -> BitVector m -- ^ The value of the ROM at address @rd@+asyncRomFile sz file rd = asyncRomFile# sz file (fromEnum rd)++{-# INLINE asyncRomFilePow2 #-}+-- | An asynchronous/combinational ROM with space for 2^@n@ elements+--+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how+-- to instantiate a ROM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+asyncRomFilePow2 :: forall n m . (KnownNat m, KnownNat n, KnownNat (2^n))+                 => FilePath    -- ^ File describing the content of the ROM+                 -> Unsigned n  -- ^ Read address @rd@+                 -> BitVector m -- ^ The value of the ROM at address @rd@+asyncRomFilePow2 = asyncRomFile (snat :: SNat (2^n))++{-# NOINLINE asyncRomFile# #-}+-- | asyncROMFile primitive+asyncRomFile# :: KnownNat m+              => SNat n       -- ^ Size of the ROM+              -> FilePath     -- ^ File describing the content of the ROM+              -> Int          -- ^ Read address @rd@+              -> BitVector m  -- ^ The value of the ROM at address @rd@+asyncRomFile# sz file rd = content ! rd+  where+    content = listArray (0,szI-1) (initMem file)+    szI     = fromInteger (snatToInteger sz)++{-# INLINE romFile #-}+-- | A ROM with a synchronous read port, with space for @n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how+-- to instantiate a ROM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+romFile :: (KnownNat m, KnownNat k)+        => SNat n               -- ^ Size of the ROM+        -> FilePath             -- ^ File describing the content of the ROM+        -> Signal (Unsigned k)  -- ^ Read address @rd@+        -> Signal (BitVector m)+        -- ^ The value of the ROM at address @rd@ from the previous clock cycle+romFile = romFile' systemClock++{-# INLINE romFilePow2 #-}+-- | A ROM with a synchronous read port, with space for 2^@n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how+-- to instantiate a ROM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+romFilePow2 :: forall n m . (KnownNat m, KnownNat n, KnownNat (2^n))+            => FilePath             -- ^ File describing the content of the ROM+            -> Signal (Unsigned n)  -- ^ Read address @rd@+            -> Signal (BitVector m)+            -- ^ The value of the ROM at address @rd@ from the previous clock cycle+romFilePow2 = romFile' systemClock (snat :: SNat (2^n))++{-# INLINE romFilePow2' #-}+-- | A ROM with a synchronous read port, with space for 2^@n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how+-- to instantiate a ROM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+romFilePow2' :: forall clk n m . (KnownNat m, KnownNat n, KnownNat (2^n))+             => SClock clk                -- ^ 'Clock' to synchronize to+             -> FilePath                  -- ^ File describing the content of+                                          -- the ROM+             -> Signal' clk (Unsigned n)  -- ^ Read address @rd@+             -> Signal' clk (BitVector m)+             -- ^ The value of the ROM at address @rd@ from the previous clock+             -- cycle+romFilePow2' clk = romFile' clk (snat :: SNat (2^n))++{-# INLINE romFile' #-}+-- | A ROM with a synchronous read port, with space for @n@ elements+--+-- * __NB__: Read value is delayed by 1 cycle+-- * __NB__: Initial output value is 'undefined'+-- * __NB__: This function might not work for specific combinations of+-- code-generation backends and hardware targets. Please check the support table+-- below:+--+--     @+--                    | VHDL     | Verilog                 | SystemVerilog |+--     ===============+==========+=========================+===============++--     Altera/Quartus | Broken   | No Verilog-2005 support | Works         |+--     Xilinx/ISE     | Works    | Works                   | Works         |+--     ASIC           | Untested | Untested                | Untested      |+--     ===============+==========+=========================+===============++--     @+--+-- Additional helpful information:+--+-- * See "CLaSH.Prelude.ROM.File#usingromfiles" for more information on how+-- to instantiate a ROM with the contents of a data file.+-- * See "CLaSH.Sized.Fixed#creatingdatafiles" for ideas on how to create your+-- own data files.+romFile' :: (KnownNat m, Enum addr)+         => SClock clk                -- ^ 'Clock' to synchronize to+         -> SNat n                    -- ^ Size of the ROM+         -> FilePath                  -- ^ File describing the content of the+                                      -- ROM+         -> Signal' clk addr          -- ^ Read address @rd@+         -> Signal' clk (BitVector m)+         -- ^ The value of the ROM at address @rd@ from the previous clock cycle+romFile' clk sz file rd = romFile# clk sz file (fromEnum <$> rd)++{-# NOINLINE romFile# #-}+-- | romFile primitive+romFile# :: KnownNat m+         => SClock clk                -- ^ 'Clock' to synchronize to+         -> SNat n                    -- ^ Size of the ROM+         -> FilePath                  -- ^ File describing the content of the+                                      -- ROM+         -> Signal' clk Int           -- ^ Read address @rd@+         -> Signal' clk (BitVector m)+         -- ^ The value of the ROM at address @rd@ from the previous clock cycle+romFile# clk sz file rd = register' clk undefined ((content !) <$> rd)+  where+    content = listArray (0,szI-1) (initMem file)+    szI     = fromInteger (snatToInteger sz)
+ src/CLaSH/Prelude/Safe.hs view
@@ -0,0 +1,176 @@+{-# LANGUAGE DataKinds        #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeOperators    #-}++{-# LANGUAGE Safe #-}++{-# OPTIONS_HADDOCK show-extensions #-}++{-|+  Copyright   :  (C) 2013-2015, University of Twente+  License     :  BSD2 (see the file LICENSE)+  Maintainer  :  Christiaan Baaij <christiaan.baaij@gmail.com>++  __This is the <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/safe-haskell.html Safe> API only of "CLaSH.Prelude"__++  CλaSH (pronounced ‘clash’) is a functional hardware description language that+  borrows both its syntax and semantics from the functional programming language+  Haskell. The merits of using a functional language to describe hardware comes+  from the fact that combinational circuits can be directly modeled as+  mathematical functions and that functional languages lend themselves very well+  at describing and (de-)composing mathematical functions.++  This package provides:++  * Prelude library containing datatypes and functions for circuit design++  To use the library:++  * Import "CLaSH.Prelude"+  * Additionally import "CLaSH.Prelude.Explicit" if you want to design+    explicitly clocked circuits in a multi-clock setting++  For now, "CLaSH.Prelude" is also the best starting point for exploring the+  library. A preliminary version of a tutorial can be found in "CLaSH.Tutorial".+  Some circuit examples can be found in "CLaSH.Examples".+-}+module CLaSH.Prelude.Safe+  ( -- * Creating synchronous sequential circuits+    mealy+  , mealyB+  , (<^>)+  , moore+  , mooreB+  , registerB+    -- * ROMs+  , asyncRom+  , asyncRomPow2+  , rom+  , romPow2+    -- * RAM primitives with a combinational read port+  , asyncRam+  , asyncRamPow2+    -- * BlockRAM primitives+  , blockRam+  , blockRamPow2+    -- * Utility functions+  , isRising+  , isFalling+    -- * Exported modules+    -- ** Synchronous signals+  , module CLaSH.Signal+  , module CLaSH.Signal.Delayed+    -- ** DataFlow interface+  , module CLaSH.Prelude.DataFlow+    -- ** Datatypes+    -- *** Bit vectors+  , module CLaSH.Sized.BitVector+  , module CLaSH.Prelude.BitIndex+  , module CLaSH.Prelude.BitReduction+    -- *** Arbitrary-width numbers+  , module CLaSH.Sized.Signed+  , module CLaSH.Sized.Unsigned+  , module CLaSH.Sized.Index+    -- *** Fixed point numbers+  , module CLaSH.Sized.Fixed+    -- *** Fixed size vectors+  , module CLaSH.Sized.Vector+    -- ** Annotations+  , module CLaSH.Annotations.TopEntity+    -- ** Type-level natural numbers+  , module GHC.TypeLits+  , module CLaSH.Promoted.Nat+  , module CLaSH.Promoted.Nat.Literals+  , module CLaSH.Promoted.Nat.TH+    -- ** Type-level functions+  , module CLaSH.Promoted.Ord+    -- ** Type classes+    -- *** CLaSH+  , module CLaSH.Class.BitPack+  , module CLaSH.Class.Num+  , module CLaSH.Class.Resize+    -- *** Other+  , module Control.Applicative+  , module Data.Bits+    -- ** Haskell Prelude+    -- $hiding+  , module Prelude+  )+where++import Control.Applicative+import Data.Bits+import GHC.TypeLits+import Prelude                     hiding ((++), (!!), concat, drop, foldl,+                                           foldl1, foldr, foldr1, head, init,+                                           iterate, last, length, map, repeat,+                                           replicate, reverse, scanl, scanr,+                                           splitAt, tail, take, unzip, unzip3,+                                           zip, zip3, zipWith, zipWith3)++import CLaSH.Annotations.TopEntity+import CLaSH.Class.BitPack+import CLaSH.Class.Num+import CLaSH.Class.Resize+import CLaSH.Prelude.BitIndex+import CLaSH.Prelude.BitReduction+import CLaSH.Prelude.BlockRam      (blockRam, blockRamPow2)+import CLaSH.Prelude.Explicit.Safe (registerB', isRising', isFalling')+import CLaSH.Prelude.Mealy         (mealy, mealyB, (<^>))+import CLaSH.Prelude.Moore         (moore, mooreB)+import CLaSH.Prelude.RAM           (asyncRam,asyncRamPow2)+import CLaSH.Prelude.ROM           (asyncRom,asyncRomPow2,rom,romPow2)+import CLaSH.Prelude.DataFlow+import CLaSH.Promoted.Nat+import CLaSH.Promoted.Nat.TH+import CLaSH.Promoted.Nat.Literals+import CLaSH.Promoted.Ord+import CLaSH.Sized.BitVector+import CLaSH.Sized.Fixed+import CLaSH.Sized.Index+import CLaSH.Sized.Signed+import CLaSH.Sized.Unsigned+import CLaSH.Sized.Vector+import CLaSH.Signal+import CLaSH.Signal.Delayed+import CLaSH.Signal.Explicit       (systemClock)++-- $setup+-- >>> let rP = registerB (8,8)++{- $hiding+"CLaSH.Prelude" re-exports most of the Haskell "Prelude" with the exception of+the following: (++), (!!), concat, drop, foldl, foldl1, foldr, foldr1, head,+init, iterate, last, length, map, repeat, replicate, reverse, scanl, scanr,+splitAt, tail, take, unzip, unzip3, zip, zip3, zipWith, zipWith3.++It instead exports the identically named functions defined in terms of+'CLaSH.Sized.Vector.Vec' at "CLaSH.Sized.Vector".+-}++{-# INLINE registerB #-}+-- | Create a 'register' function for product-type like signals (e.g. '(Signal a, Signal b)')+--+-- > rP :: (Signal Int,Signal Int) -> (Signal Int, Signal Int)+-- > rP = registerB (8,8)+--+-- >>> simulateB rP [(1,1),(2,2),(3,3)] :: [(Int,Int)]+-- [(8,8),(1,1),(2,2),(3,3)...+registerB :: Bundle a => a -> Unbundled a -> Unbundled a+registerB = registerB' systemClock++{-# INLINE isRising #-}+-- | Give a pulse when the 'Signal' goes from 'minBound' to 'maxBound'+isRising :: (Bounded a, Eq a)+         => a -- ^ Starting value+         -> Signal a+         -> Signal Bool+isRising = isRising' systemClock++{-# INLINE isFalling #-}+-- | Give a pulse when the 'Signal' goes from 'maxBound' to 'minBound'+isFalling :: (Bounded a, Eq a)+          => a -- ^ Starting value+          -> Signal a+          -> Signal Bool+isFalling = isFalling' systemClock
+ src/CLaSH/Prelude/Synchronizer.hs view
@@ -0,0 +1,157 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE PartialTypeSignatures #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}++{-# LANGUAGE Safe #-}++{-# OPTIONS_GHC -fno-warn-partial-type-signatures #-}+{-# OPTIONS_HADDOCK show-extensions #-}++{-|+Copyright   :  (C) 2015, University of Twente+License     :  BSD2 (see the file LICENSE)+Maintainer  :  Christiaan Baaij <christiaan.baaij@gmail.com>++Synchronizer circuits for safe clock domain crossings+-}+module CLaSH.Prelude.Synchronizer+  ( -- * Bit-synchronizers+    dualFlipFlopSynchronizer+    -- * Word-synchronizers+  , asyncFIFOSynchronizer+  )+where++import Data.Bits                   (complement, shiftR, xor)+import GHC.TypeLits                (KnownNat, type (+))++import CLaSH.Class.BitPack         (pack)+import CLaSH.Class.Resize          (zeroExtend)+import CLaSH.Prelude.BitIndex      (slice)+import CLaSH.Prelude.Mealy         (mealyB')+import CLaSH.Prelude.RAM           (asyncRam')+import CLaSH.Promoted.Nat          (SNat, powSNat, subSNat)+import CLaSH.Promoted.Nat.Literals (d0, d1, d2)+import CLaSH.Signal                ((.&&.), not1)+import CLaSH.Signal.Explicit       (Signal', SClock, register',+                                    unsafeSynchronizer)+import CLaSH.Sized.BitVector       (BitVector, (++#))++-- * Dual flip-flop synchronizer++-- | Synchroniser based on two sequentially connected flip-flops.+--+--  * __NB__: This synchroniser can be used for __bit__-synchronization.+--+--  * __NB__: Although this synchroniser does reduce metastability, it does+--  not guarantee the proper synchronisation of a whole __word__. For+--  example, given that the output is sampled twice as fast as the input is+--  running, and we have two samples in the input stream that look like:+--+--      @[0111,1000]@+--+--      But the circuit driving the input stream has a longer propagation delay+--      on __msb__ compared to the __lsb__s. What can happen is an output stream+--      that looks like this:+--+--      @[0111,0111,0000,1000]@+--+--      Where the level-change of the __msb__ was not captured, but the level+--      change of the __lsb__s were.+--+--      If you want to have /safe/ __word__-synchronisation use+--      'asyncFIFOSynchronizer'.+dualFlipFlopSynchronizer :: SClock clk1    -- ^ 'Clock' to which the incoming+                                           -- data is synchronised+                         -> SClock clk2    -- ^ 'Clock' to which the outgoing+                                           -- data is synchronised+                         -> a              -- ^ Initial value of the two+                                           -- synchronisation registers+                         -> Signal' clk1 a -- ^ Incoming data+                         -> Signal' clk2 a -- ^ Outgoing, synchronised, data+dualFlipFlopSynchronizer clk1 clk2 i = register' clk2 i+                                     . register' clk2 i+                                     . unsafeSynchronizer clk1 clk2++-- * Asynchronous FIFO synchronizer++fifoMem :: _+        => SClock wclk+        -> SClock rclk+        -> SNat addrSize+        -> Signal' wclk (BitVector addrSize)+        -> Signal' rclk (BitVector addrSize)+        -> Signal' wclk Bool+        -> Signal' wclk Bool+        -> Signal' wclk a+        -> Signal' rclk a+fifoMem wclk rclk addrSize waddr raddr winc wfull wdata =+  asyncRam' wclk rclk+            (d2 `powSNat` addrSize)+            waddr raddr+            (winc .&&. not1 wfull)+            wdata++boolToBV :: (KnownNat n, KnownNat (n+1)) => Bool -> BitVector (n + 1)+boolToBV = zeroExtend . pack++ptrCompareT :: _+            => SNat addrSize+            -> (BitVector (addrSize + 1) -> BitVector (addrSize + 1) -> Bool)+            -> (BitVector (addrSize + 1), BitVector (addrSize + 1), Bool)+            -> (BitVector (addrSize + 1), Bool)+            -> ((BitVector (addrSize + 1), BitVector (addrSize + 1), Bool)+               ,(Bool, BitVector addrSize, BitVector (addrSize + 1)))+ptrCompareT addrSize flagGen (bin,ptr,flag) (s_ptr,inc) = ((bin',ptr',flag')+                                                          ,(flag,addr,ptr))+  where+    -- GRAYSTYLE2 pointer+    bin' = bin + boolToBV (inc && not flag)+    ptr' = (bin' `shiftR` 1) `xor` bin'+    addr = slice (addrSize `subSNat` d1) d0 bin++    flag' = flagGen ptr' s_ptr+++-- FIFO full: when next pntr == synchonized {~wptr[addrSize:addrSize-1],wptr[addrSize-1:0]}+isFull :: _+       => SNat addrSize+       -> BitVector (addrSize + 1)+       -> BitVector (addrSize + 1)+       -> Bool+isFull addrSize ptr s_ptr =+  ptr == (complement (slice addrSize (addrSize `subSNat` d1) s_ptr) ++#+         slice (addrSize `subSNat` d2) d0 s_ptr)++-- | Synchroniser implemented as a FIFO around an asynchronous RAM. Based on the+-- design described in "CLaSH.Tutorial#multiclock", which is itself based on the+-- design described in <http://www.sunburst-design.com/papers/CummingsSNUG2002SJ_FIFO1.pdf>.+--+-- __NB__: This synchroniser can be used for __word__-synchronization.+asyncFIFOSynchronizer :: _+                      => SNat addrSize     -- ^ Size of the internally used+                                           -- addresses, the FIFO contains+                                           -- @2^addrSize@ elements.+                      -> SClock wclk       -- ^ 'Clock' to which the write port+                                           -- is synchronised+                      -> SClock rclk       -- ^ 'Clock' to which the read port+                                           -- is synchronised+                      -> Signal' wclk a    -- ^ Element to insert+                      -> Signal' wclk Bool -- ^ Write request+                      -> Signal' rclk Bool -- ^ Read request+                      -> (Signal' rclk a, Signal' rclk Bool, Signal' wclk Bool)+                      -- ^ (Oldest element in the FIFO, @empty@ flag, @full@ flag)+asyncFIFOSynchronizer addrSize wclk rclk wdata winc rinc = (rdata,rempty,wfull)+  where+    s_rptr = dualFlipFlopSynchronizer rclk wclk 0 rptr+    s_wptr = dualFlipFlopSynchronizer wclk rclk 0 wptr++    rdata = fifoMem wclk rclk addrSize waddr raddr winc wfull wdata++    (rempty,raddr,rptr) = mealyB' rclk (ptrCompareT addrSize (==)) (0,0,True)+                                  (s_wptr,rinc)++    (wfull,waddr,wptr)  = mealyB' wclk (ptrCompareT addrSize (isFull addrSize))+                                  (0,0,False) (s_rptr,winc)
src/CLaSH/Prelude/Testbench.hs view
@@ -15,17 +15,17 @@   , stimuliGenerator   , outputVerifier     -- * Testbench functions for circuits synchronised to arbitrary clocks+  , assert'   , stimuliGenerator'   , outputVerifier'   ) where -import Control.Applicative   (liftA3) import Debug.Trace           (trace) import GHC.TypeLits          (KnownNat) import Prelude               hiding ((!!)) -import CLaSH.Signal          (Signal)+import CLaSH.Signal          (Signal, fromList) import CLaSH.Signal.Explicit (Signal', SClock, register', systemClock) import CLaSH.Signal.Bundle   (unbundle') import CLaSH.Sized.Index     (Index)@@ -43,6 +43,22 @@ -- >>> let testInput' = stimuliGenerator' clkA $(v [(1::Int),3..21]) -- >>> let expectedOutput' = outputVerifier' clkA $(v ([70,99,2,3,4,5,7,8,9,10]::[Int])) +{-# INLINE assert #-}+-- | Compares the first two 'Signal's for equality and logs a warning when they+-- are not equal. The second 'Signal' is considered the expected value. This+-- function simply returns the third 'Signal' unaltered as its result. This+-- function is used by 'outputVerifier'.+--+--+-- __NB__: This function is /can/ be used in synthesizable designs.+assert :: (Eq a,Show a)+       => String   -- ^ Additional message+       -> Signal a -- ^ Checked value+       -> Signal a -- ^ Expected value+       -> Signal b -- ^ Return valued+       -> Signal b+assert = assert' systemClock+ {-# INLINE stimuliGenerator #-} -- | To be used as a one of the functions to create the \"magical\" 'testInput' -- value, which the CλaSH compilers looks for to create the stimulus generator@@ -77,16 +93,22 @@ -- >>> import qualified Data.List as List -- >>> sampleN 12 (expectedOutput (fromList ([0..10] List.++ [10,10,10]))) -- [+-- cycle(system1000): 0, outputVerifier -- expected value: 70, not equal to actual value: 0 -- False,+-- cycle(system1000): 1, outputVerifier -- expected value: 99, not equal to actual value: 1 -- False,False,False,False,False,+-- cycle(system1000): 6, outputVerifier -- expected value: 7, not equal to actual value: 6 -- False,+-- cycle(system1000): 7, outputVerifier -- expected value: 8, not equal to actual value: 7 -- False,+-- cycle(system1000): 8, outputVerifier -- expected value: 9, not equal to actual value: 8 -- False,+-- cycle(system1000): 9, outputVerifier -- expected value: 10, not equal to actual value: 9 -- False,True,True] outputVerifier :: forall l a . (KnownNat l, Eq a, Show a)@@ -95,26 +117,34 @@                -> Signal Bool -- ^ Indicator that all samples are verified outputVerifier = outputVerifier' systemClock -{-# NOINLINE assert #-}--- | Compares the first two arguments for equality and logs a warning when they--- are not equal. The second argument is considered the expected value. This--- function simply returns the third argument unaltered as its result. This--- function is used by 'coutputVerifier'.+{-# NOINLINE assert' #-}+-- | Compares the first two 'Signal''s for equality and logs a warning when they+-- are not equal. The second 'Signal'' is considered the expected value. This+-- function simply returns the third 'Signal'' unaltered as its result. This+-- function is used by 'outputVerifier''. -- -- -- __NB__: This function is /can/ be used in synthesizable designs.-assert :: (Eq a,Show a)-       => Signal' t a -- ^ Checked value-       -> Signal' t a -- ^ Expected value-       -> Signal' t b -- ^ Return valued-       -> Signal' t b-assert = liftA3-  (\a' b' c' -> if a' == b' then c'-                            else trace (concat [ "\nexpected value: "-                                               , show b'-                                               , ", not equal to actual value: "-                                               , show a'-                                               ]) c')+assert' :: (Eq a,Show a)+        => SClock t+        -> String      -- ^ Additional message+        -> Signal' t a -- ^ Checked value+        -> Signal' t a -- ^ Expected value+        -> Signal' t b -- ^ Return valued+        -> Signal' t b+assert' clk msg checked expected returned =+  (\c e cnt r ->+      if c == e then r+                else trace (concat [ "\ncycle(" ++ show clk ++ "): "+                                   , show cnt+                                   , ", "+                                   , msg+                                   , "\nexpected value: "+                                   , show e+                                   , ", not equal to actual value: "+                                   , show c+                                   ]) r)+  <$> checked <*> expected <*> fromList [(0::Integer)..] <*> returned  {-# INLINABLE stimuliGenerator' #-} -- | To be used as a one of the functions to create the \"magical\" 'testInput'@@ -173,16 +203,22 @@ -- >>> import qualified Data.List as List -- >>> sampleN 12 (expectedOutput' (fromList ([0..10] List.++ [10,10,10]))) -- [+-- cycle(A100): 0, outputVerifier -- expected value: 70, not equal to actual value: 0 -- False,+-- cycle(A100): 1, outputVerifier -- expected value: 99, not equal to actual value: 1 -- False,False,False,False,False,+-- cycle(A100): 6, outputVerifier -- expected value: 7, not equal to actual value: 6 -- False,+-- cycle(A100): 7, outputVerifier -- expected value: 8, not equal to actual value: 7 -- False,+-- cycle(A100): 8, outputVerifier -- expected value: 9, not equal to actual value: 8 -- False,+-- cycle(A100): 9, outputVerifier -- expected value: 10, not equal to actual value: 9 -- False,True,True] outputVerifier' :: forall l clk a . (KnownNat l, Eq a, Show a)@@ -194,7 +230,7 @@ outputVerifier' clk samples i =     let (s,o) = unbundle' clk (genT <$> register' clk 0 s)         (e,f) = unbundle' clk o-    in  assert i e (register' clk False f)+    in  assert' clk "outputVerifier" i e (register' clk False f)   where     genT :: Index l -> (Index l,(a,Bool))     genT s = (s',(samples !! s,finished))
src/CLaSH/Promoted/Nat.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-} {-# LANGUAGE GADTs               #-} {-# LANGUAGE KindSignatures      #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -15,7 +16,7 @@ Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com> -} module CLaSH.Promoted.Nat-  ( SNat (..), snat, withSNat, snatToInteger+  ( SNat (..), snat, withSNat, snatToInteger, addSNat, subSNat, mulSNat, powSNat   , UNat (..), toUNat, addUNat, multUNat, powUNat   ) where@@ -66,7 +67,7 @@     fromI 0 = unsafeCoerce UZero     fromI n = unsafeCoerce (USucc (fromI (n - 1))) --- | Add two singleton natural numbers+-- | Add two unary singleton natural numbers -- -- __NB__: Not synthesisable addUNat :: UNat n -> UNat m -> UNat (n + m)@@ -74,7 +75,7 @@ addUNat x         UZero = x addUNat (USucc x) y     = USucc (addUNat x y) --- | Multiply two singleton natural numbers+-- | Multiply two unary singleton natural numbers -- -- __NB__: Not synthesisable multUNat :: UNat n -> UNat m -> UNat (n * m)@@ -82,9 +83,25 @@ multUNat _          UZero = UZero multUNat (USucc x) y      = addUNat y (multUNat x y) --- | Exponential of two singleton natural numbers+-- | Power of two unary singleton natural numbers -- -- __NB__: Not synthesisable powUNat :: UNat n -> UNat m -> UNat (n ^ m) powUNat _ UZero     = USucc UZero powUNat x (USucc y) = multUNat x (powUNat x y)++-- | Add two singleton natural numbers+addSNat :: KnownNat (a + b) => SNat a -> SNat b -> SNat (a+b)+addSNat _ _ = snat++-- | Subtract two singleton natural numbers+subSNat :: KnownNat (a - b) => SNat a -> SNat b -> SNat (a-b)+subSNat _ _ = snat++-- | Multiply two singleton natural numbers+mulSNat :: KnownNat (a * b) => SNat a -> SNat b -> SNat (a*b)+mulSNat _ _ = snat++-- | Power of two singleton natural numbers+powSNat :: KnownNat (a ^ b) => SNat a -> SNat b -> SNat (a^b)+powSNat _ _ = snat
src/CLaSH/Signal/Delayed.hs view
@@ -40,7 +40,7 @@ import Data.Coerce                (coerce) import Data.Default               (Default(..)) import Control.Applicative        (liftA2)-import GHC.TypeLits               (KnownNat, Nat, type (-))+import GHC.TypeLits               (KnownNat, Nat, type (+)) import Language.Haskell.TH.Syntax (Lift) import Prelude                    hiding (head, length, repeat) import Test.QuickCheck            (Arbitrary, CoArbitrary)@@ -56,7 +56,7 @@ -- >>> :set -XTypeOperators -- >>> import CLaSH.Prelude -- >>> let delay3 = delay (0 :> 0 :> 0 :> Nil)--- >>> let delay2 = delayI :: DSignal (n - 2) Int -> DSignal n Int+-- >>> let delay2 = delayI :: DSignal n Int -> DSignal (n + 2) Int -- >>> :{ -- let mac :: DSignal 0 Int -> DSignal 0 Int -> DSignal 0 Int --     mac x y = feedback (mac' x y)@@ -98,19 +98,19 @@ dfromList :: [a] -> DSignal 0 a dfromList = coerce . fromList --- | Delay a 'DSignal' for @m@ periods.+-- | Delay a 'DSignal' for @d@ periods. -- -- @--- delay3 :: 'DSignal' (n - 3) Int -> 'DSignal' n Int+-- delay3 :: 'DSignal' n Int -> 'DSignal' (n + 3) Int -- delay3 = 'delay' (0 ':>' 0 ':>' 0 ':>' 'Nil') -- @ -- -- >>> sampleN 6 (delay3 (dfromList [1..])) -- [0,0,0,1,2,3]-delay :: forall a n m . KnownNat m-      => Vec m a-      -> DSignal (n - m) a+delay :: forall a n d . KnownNat d+      => Vec d a       -> DSignal n a+      -> DSignal (n + d) a delay m ds = coerce (delay' (coerce ds))   where     delay' :: Signal a -> Signal a@@ -123,15 +123,15 @@ -- | Delay a 'DSignal' for @m@ periods, where @m@ is derived from the context. -- -- @--- delay2 :: 'DSignal' (n - 2) Int -> 'DSignal' n Int+-- delay2 :: 'DSignal' n Int -> 'DSignal' (n + 2) Int -- delay2 = 'delayI' -- @ -- -- >>> sampleN 6 (delay2 (dfromList [1..])) -- [0,0,1,2,3,4]-delayI :: (Default a, KnownNat m)-       => DSignal (n - m) a-       -> DSignal n a+delayI :: (Default a, KnownNat d)+       => DSignal n a+       -> DSignal (n + d) a delayI = delay (repeat def)  -- | Feed the delayed result of a function back to its input:@@ -148,8 +148,8 @@ -- -- >>> sampleN 6 (mac (dfromList [1..]) (dfromList [1..])) -- [0,1,5,14,30,55]-feedback :: (DSignal (n - m - 1) a -> (DSignal (n - m - 1) a,DSignal n a))-         -> DSignal (n - m - 1) a+feedback :: (DSignal n a -> (DSignal n a,DSignal (n + m + 1) a))+         -> DSignal n a feedback f = let (o,r) = f (coerce r) in o  -- | 'Signal's are not delayed@@ -178,5 +178,5 @@ --     acc' = (x * y) + 'antiDelay' d1 acc --     acc  = 'delay' ('singleton' 0) acc' -- @-antiDelay :: SNat d -> DSignal n a -> DSignal (n - d) a+antiDelay :: SNat d -> DSignal (n + d) a -> DSignal n a antiDelay _ = coerce
src/CLaSH/Signal/Explicit.hs view
@@ -23,6 +23,7 @@   , withSClock   , SystemClock   , systemClock+  , freqCalc     -- ** Synchronisation primitive   , unsafeSynchronizer     -- * Basic circuit functions@@ -136,6 +137,44 @@ -- | The singleton clock for 'SystemClock' systemClock :: SClock SystemClock systemClock = sclock++-- | Calculate relative periods given a list of frequencies.+--+-- So for example, you have one part of your design connected to an ADC running+-- at 20 MHz, one part of your design connected to a DAC running at 36 MHz, and+-- the rest of your system is running at 50 MHz. What are the relative+-- (integer) clock periods in CλaSH, such that their ratios correspond to the+-- ratios between the actual clock frequencies.+--+-- For this we use 'freqCalc':+--+-- >>> freqCalc [20,36,50]+-- [45,25,18]+--+-- So that we create the proper clocks:+--+-- @+-- type ADC20 = 'Clk' \"ADC\" 45+-- type DAC36 = 'Clk' \"DAC\" 25+-- type Sys50 = 'Clk' \"Sys\" 18+--+-- sys50 :: SClock System50+-- sys50 = 'sclock'+--+-- adc20 :: SClock ADC20+-- adc20 = 'sclock'+--+-- dac36 :: SClock DAC36+-- dac36 = 'sclock'+-- @+--+-- __NB__: This function is /not/ synthesisable+freqCalc :: [Integer] -> [Integer]+freqCalc xs = map (`div` g) ys+  where+    p  = product xs+    ys = map (p `div`) xs+    g  = foldr1 gcd ys  -- ** Synchronisation primitive {-# NOINLINE unsafeSynchronizer #-}
src/CLaSH/Signal/Internal.hs view
@@ -70,6 +70,8 @@   , unsafeShiftR1   , rotateL1   , rotateR1+  -- * EXTREMELY EXPERIMENTAL+  , joinSignal#   ) where @@ -140,6 +142,19 @@ appSignal# :: Signal' clk (a -> b) -> Signal' clk a -> Signal' clk b appSignal# (f :- fs) ~(a :- as) = f a :- appSignal# fs as +{-# NOINLINE joinSignal# #-}+-- | __WARNING: EXTREMELY EXPERIMENTAL__+--+-- The circuit semantics of this operation are unclear and/or non-existent.+-- There is a good reason there is no 'Monad' instance for 'Signal''.+--+-- Is currently treated as 'id' by the CLaSH compiler.+joinSignal# :: Signal' clk (Signal' clk a) -> Signal' clk a+joinSignal# ~(xs :- xss) = head# xs :- joinSignal# (mapSignal# tail# xss)+  where+    head# (x' :- _ )  = x'+    tail# (_  :- xs') = xs'+ instance Num a => Num (Signal' clk a) where   (+)         = liftA2 (+)   (-)         = liftA2 (-)@@ -219,9 +234,15 @@     s' = mux b s r  {-# INLINE mux #-}--- | A multiplexer. Given "@'mux' b t f@", output @t@ when @b@ is 'True', and @f@+-- | The above type is a generalisation for:+--+-- @+-- __mux__ :: 'CLaSH.Signal.Signal' 'Bool' -> 'CLaSH.Signal.Signal' a -> 'CLaSH.Signal.Signal' a -> 'CLaSH.Signal.Signal' a+-- @+--+-- A multiplexer. Given "@'mux' b t f@", output @t@ when @b@ is 'True', and @f@ -- when @b@ is 'False'.-mux :: Signal' clk Bool -> Signal' clk a -> Signal' clk a -> Signal' clk a+mux :: Applicative f => f Bool -> f a -> f a -> f a mux = liftA3 (\b t f -> if b then t else f)  {-# INLINE signal #-}
src/CLaSH/Sized/Fixed.hs view
@@ -47,6 +47,8 @@   , divide     -- * Compile-time 'Double' conversion   , fLit+    -- * Run-time 'Double' conversion (not synthesisable)+  , fLitR     -- * 'Fixed' point wrapper   , Fixed (..), resizeF, fracShift     -- * Constraint synonyms@@ -591,6 +593,170 @@     truncated = truncate shifted :: Integer     shifted   = a * (2 ^ (natVal (Proxy :: Proxy frac))) +-- | Convert, at run-time, a 'Double' to a 'Fixed'-point.+--+-- __NB__: this functions is /not/ synthesisable+--+-- = Creating data-files #creatingdatafiles#+--+-- An example usage of this function is for example to convert a data file+-- containing 'Double's to a data file with ASCI-encoded binary numbers to be+-- used by a synthesisable function like 'CLaSH.Prelude.ROM.File.asyncRomFile'.+-- For example, given a file @Data.txt@ containing:+--+-- @+-- 1.2 2.0 3.0 4.0+-- -1.0 -2.0 -3.5 -4.0+-- @+--+-- which we want to put in a ROM, interpreting them as @8.8@ signed fixed point+-- numbers. What we do is that we first create a conversion utility,+-- @createRomFile@, which uses 'fLitR':+--+-- @createRomFile.hs@:+--+-- @+-- module Main where+--+-- import CLaSH.Prelude+-- import System.Environment+-- import qualified Data.List as L+--+-- createRomFile :: KnownNat n => (Double -> BitVector n)+--               -> FilePath -> FilePath -> IO ()+-- createRomFile convert fileR fileW = do+--   f <- readFile fileR+--   let ds :: [Double]+--       ds = L.concat . (L.map . L.map) read . L.map words $ lines f+--       bvs = L.map (filter (/= '_') . show . convert) ds+--   writeFile fileW (unlines bvs)+--+-- toSFixed8_8 :: Double -> SFixed 8 8+-- toSFixed8_8 = 'fLitR'+--+-- main :: IO ()+-- main = do+--   [fileR,fileW] <- getArgs+--   createRomFile ('pack' . toSFixed8_8) fileR fileW+-- @+--+-- We then compile this to an executable:+--+-- @+-- $ clash --make createRomFile.hs+-- @+--+-- We can then use this utility to convert our @Data.txt@ file which contains+-- 'Double's to a @Data.bin@ file which will containing the desired ASCI-encoded+-- binary data:+--+-- @+-- $ ./createRomFile \"Data.txt\" \"Data.bin\"+-- @+--+-- Which results in a @Data.bin@ file containing:+--+-- @+-- 0000000100110011+-- 0000001000000000+-- 0000001100000000+-- 0000010000000000+-- 1111111100000000+-- 1111111000000000+-- 1111110010000000+-- 1111110000000000+-- @+--+-- We can then use this @Data.bin@ file in for our ROM:+--+-- @+-- romF :: Unsigned 3 -> Unsigned 3 -> SFixed 8 8+-- romF rowAddr colAddr = 'unpack'+--                      $ 'CLaSH.Prelude.ROM.File.asyncRomFile' d8 "Data.bin" ((rowAddr * 4) + colAddr)+-- @+--+-- And see that it works as expected:+--+-- @+-- __>>> romF 1 2__+-- -3.5+-- __>>> romF 0 0__+-- 1.19921875+-- @+--+-- == Using Template Haskell+--+-- For those of us who like to live on the edge, another option is to convert+-- our @Data.txt@ at compile-time using+-- <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/template-haskell.html Template Haskell>.+-- For this we first create a module @CreateRomFileTH.hs@:+--+-- @+-- module CreateRomFileTH (romDataFromFile) where+--+-- import CLaSH.Prelude+-- import qualified Data.List        as L+-- import Language.Haskell.TH        (ExpQ, litE, stringL)+-- import Language.Haskell.TH.Syntax (qRunIO)+--+-- createRomFile :: KnownNat n => (Double -> BitVector n)+--               -> FilePath -> FilePath -> IO ()+-- createRomFile convert fileR fileW = do+--   f <- readFile fileR+--   let ds :: [Double]+--       ds = L.concat . (L.map . L.map) read . L.map words $ lines f+--       bvs = L.map (filter (/= '_') . show . convert) ds+--   writeFile fileW (unlines bvs)+--+-- romDataFromFile :: KnownNat n => (Double -> BitVector n) -> String -> ExpQ+-- romDataFromFile convert fileR = do+--   let fileW = fileR L.++ ".bin"+--   bvF <- qRunIO (createRomFile convert fileR fileW)+--   litE (stringL fileW)+-- @+--+-- Instead of first converting @Data.txt@ to @Data.bin@, we will now use the+-- @romDataFromFile@ function to convert @Data.txt@ to a new file in the proper+-- format at compile-time of our new @romF'@ function:+--+-- @+-- import CLaSH.Prelude+-- import CreateRomFileTH+--+-- toSFixed8_8 :: Double -> SFixed 8 8+-- toSFixed8_8 = 'fLitR'+--+-- romF' :: Unsigned 3 -> Unsigned 3 -> SFixed 8 8+-- romF' rowAddr colAddr = unpack $+--   asyncRomFile d8+--                $(romDataFromFile (pack . toSFixed8_8) "Data.txt") -- Template Haskell splice+--                ((rowAddr * 4) + colAddr)+-- @+--+-- And see that it works just like the @romF@ function from earlier:+--+-- @+-- __>>> romF' 1 2__+-- -3.5+-- __>>> romF' 0 0__+-- 1.19921875+-- @+fLitR :: forall rep int frac size .+         ( size ~ (int + frac), KnownNat frac, Bounded (rep size)+         , Integral (rep size))+      => Double+      -> Fixed rep int frac+fLitR a = Fixed (fromInteger sat)+  where+    rMax      = toInteger (maxBound :: rep size)+    rMin      = toInteger (minBound :: rep size)+    sat       = if truncated > rMax+                   then rMax+                   else if truncated < rMin+                           then rMin+                           else truncated+    truncated = truncate shifted :: Integer+    shifted   = a * (2 ^ (natVal (Proxy :: Proxy frac)))  instance NumFixedC rep int frac => SaturatingNum (Fixed rep int frac) where   satPlus w (Fixed a) (Fixed b) = Fixed (satPlus w a b)
src/CLaSH/Sized/Internal/BitVector.hs view
@@ -74,7 +74,6 @@     -- ** Integral   , quot#   , rem#-  , mod#   , toInteger#     -- ** Bits   , and#@@ -299,18 +298,16 @@   quot        = quot#   rem         = rem#   div         = quot#-  mod         = mod#+  mod         = rem#   quotRem n d = (n `quot#` d,n `rem#` d)-  divMod  n d = (n `quot#` d,n `mod#` d)+  divMod  n d = (n `quot#` d,n `rem#` d)   toInteger   = toInteger# -quot#,rem#,mod# :: BitVector n -> BitVector n -> BitVector n+quot#,rem# :: BitVector n -> BitVector n -> BitVector n {-# NOINLINE quot# #-} quot# (BV i) (BV j) = BV (i `quot` j) {-# NOINLINE rem# #-} rem# (BV i) (BV j) = BV (i `rem` j)-{-# NOINLINE mod# #-}-mod# (BV i) (BV j) = BV (i `mod` j)  {-# NOINLINE toInteger# #-} toInteger# :: BitVector n -> Integer
src/CLaSH/Sized/Internal/Index.hs view
@@ -40,7 +40,6 @@     -- ** Integral   , quot#   , rem#-  , mod#   , toInteger#   ) where@@ -175,18 +174,16 @@   quot        = quot#   rem         = rem#   div         = quot#-  mod         = mod#+  mod         = rem#   quotRem n d = (n `quot#` d,n `rem#` d)-  divMod  n d = (n `quot#` d,n `mod#` d)+  divMod  n d = (n `quot#` d,n `rem#` d)   toInteger   = toInteger# -quot#,rem#,mod# :: Index n -> Index n -> Index n+quot#,rem# :: Index n -> Index n -> Index n {-# NOINLINE quot# #-} (I a) `quot#` (I b) = I (a `div` b) {-# NOINLINE rem# #-} (I a) `rem#` (I b) = I (a `rem` b)-{-# NOINLINE mod# #-}-(I a) `mod#` (I b) = I (a `mod` b)  {-# NOINLINE toInteger# #-} toInteger# :: Index n -> Integer
src/CLaSH/Sized/Internal/Unsigned.hs view
@@ -55,7 +55,6 @@     -- ** Integral   , quot#   , rem#-  , mod#   , toInteger#     -- ** Bits   , and#@@ -122,9 +121,9 @@ -- >>> satMin SatSymmetric 2 3 :: Unsigned 3 -- 0 newtype Unsigned (n :: Nat) =-    -- | The constructor, 'U', and the field, 'unsafeToBitVector', are not+    -- | The constructor, 'U', and the field, 'unsafeToInteger', are not     -- synthesisable.-    U { unsafeToBitVector :: Integer }+    U { unsafeToInteger :: Integer }  {-# NOINLINE size# #-} size# :: KnownNat n => Unsigned n -> Int@@ -272,18 +271,16 @@   quot        = quot#   rem         = rem#   div         = quot#-  mod         = mod#+  mod         = rem#   quotRem n d = (n `quot#` d,n `rem#` d)-  divMod  n d = (n `quot#` d,n `mod#` d)+  divMod  n d = (n `quot#` d,n `rem#` d)   toInteger   = toInteger# -quot#,rem#,mod# :: Unsigned n -> Unsigned n -> Unsigned n+quot#,rem# :: Unsigned n -> Unsigned n -> Unsigned n {-# NOINLINE quot# #-} quot# (U i) (U j) = U (i `quot` j) {-# NOINLINE rem# #-} rem# (U i) (U j) = U (i `rem` j)-{-# NOINLINE mod# #-}-mod# (U i) (U j) = U (i `mod` j)  {-# NOINLINE toInteger# #-} toInteger# :: Unsigned n -> Integer
src/CLaSH/Sized/Vector.hs view
@@ -790,8 +790,8 @@ -- 2 -- >>> (1:>2:>3:>4:>5:>Nil) !! 14 -- *** Exception: CLaSH.Sized.Vector.(!!): index 14 is larger than maximum index 4-(!!) :: (KnownNat n, Integral i) => Vec n a -> i -> a-xs !! i = index_int xs (fromIntegral i)+(!!) :: (KnownNat n, Enum i) => Vec n a -> i -> a+xs !! i = index_int xs (fromEnum i)  {-# NOINLINE maxIndex #-} -- | Index (subscript) of the last element in a 'Vec'tor@@ -837,8 +837,8 @@ -- <7,2,3,4,5> -- >>> replace 9 7 (1:>2:>3:>4:>5:>Nil) -- <1,2,3,4,*** Exception: CLaSH.Sized.Vector.replace: index 9 is larger than maximum index 4-replace :: (KnownNat n, Integral i) => i -> a -> Vec n a -> Vec n a-replace i y xs = replace_int xs (fromIntegral i) y+replace :: (KnownNat n, Enum i) => i -> a -> Vec n a -> Vec n a+replace i y xs = replace_int xs (fromEnum i) y  {-# INLINABLE take #-} -- | 'take' @n@, applied to a vector @xs@, returns the @n@-length prefix of @xs@
src/CLaSH/Tutorial.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE NoImplicitPrelude, MagicHash #-} {-# OPTIONS_GHC -fno-warn-unused-imports #-}  {-|@@ -27,7 +27,7 @@   -- *** Circuit testbench   -- $mac4 -  -- *** Generating SystemVerilog+  -- *** Generating Verilog and SystemVerilog   -- $mac5    -- *** Alternative specifications@@ -42,6 +42,9 @@   -- * TopEntity annotations: controlling the VHDL\/Verilog\/SystemVerilog generation.   -- $annotations +  -- * Multiple clock domains+  -- $multiclock+   -- * Advanced: Primitives   -- $primitives @@ -67,9 +70,11 @@  import CLaSH.Prelude import CLaSH.Prelude.Explicit+import CLaSH.Prelude.BlockRam import Data.Char import Data.Int import GHC.Word+import Data.Default  -- $setup -- >>> :set -XTemplateHaskell@@ -524,10 +529,13 @@  >>> sampleN 7 $ expectedOutput (topEntity testInput) [False,False,False,False,+cycle(system1000): 4, outputVerifier expected value: 14, not equal to actual value: 30 True,+cycle(system1000): 5, outputVerifier expected value: 14, not equal to actual value: 46 True,+cycle(system1000): 6, outputVerifier expected value: 14, not equal to actual value: 62 True] @@ -713,7 +721,7 @@ which, together with 'bundle' and 'unbundle' defines the isomorphism between a product type of 'Signal's and a 'Signal' of a product type. That is, while @(Signal a, Signal b)@ and @Signal (a,b)@ are not equal, they are /isomorphic/-and can be converted from on to the other using 'bundle' and 'unbundle'.+and can be converted from, or to, the other using 'bundle' and 'unbundle'.  Instances of this 'Bundle' type-class are defined as /isomorphisms/ for: @@ -999,72 +1007,73 @@ is actually just like a @newtype@ wrapper for 'Integer'.  The second kind of primitive that we will explore is the /declaration/ primitive.-We will use 'cblockRam' as an example, for which the Haskell/CλaSH code is:+We will use 'blockRam#' as an example, for which the Haskell/CλaSH code is:  @-{\-\# NOINLINE blockRam' \#-\}--- | Create a blockRAM with space for @n@ elements------ * \_\_NB\_\_: Read value is delayed by 1 cycle--- * \_\_NB\_\_: Initial output value is \'undefined\'------ \@--- type ClkA = Clk \\\"A\\\" 100------ clkA100 :: SClock ClkA--- clkA100 = sclock------ bram40 :: Signal' ClkA (Unsigned 6) -> Signal' ClkA (Unsigned 6)---        -> Signal' ClkA Bool -> Signal' ClkA Bit -> Signal' ClkA Bit--- bram40 = \'blockRam'' clkA100 (\'CLaSH.Sized.Vector.replicate\' d40 1)--- \@-blockRam' :: ('GHC.TypeLits.KnownNat' n, 'GHC.TypeLits.KnownNat' m)-          => 'SClock' clk               -- ^ \'Clock\' to synchronize to-          -> 'Vec' n a                  -- ^ Initial content of the BRAM, also-                                      -- determines the size, \@n\@, of the BRAM.-                                      ---                                      -- \_\_NB\_\_: \_\_MUST\_\_ be a constant.-          -> 'Signal'' clk ('Unsigned' m) -- ^ Write address \@w\@-          -> 'Signal'' clk ('Unsigned' m) -- ^ Read address \@r\@-          -> 'Signal'' clk Bool         -- ^ Write enable-          -> 'Signal'' clk a            -- ^ Value to write (at address \@w\@)+{\-\# NOINLINE blockRam# \#-\}+-- | blockRAM primitive+blockRam' :: 'GHC.TypeLits.KnownNat' n+          => 'SClock' clk       -- ^ \'Clock\' to synchronize to+          -> 'Vec' n a          -- ^ Initial content of the BRAM, also+                              -- determines the size, \@n\@, of the BRAM.+                              --+                              -- \_\_NB\_\_: \_\_MUST\_\_ be a constant.+          -> 'Signal'' clk 'Int'  -- ^ Write address \@w\@+          -> 'Signal'' clk 'Int'  -- ^ Read address \@r\@+          -> 'Signal'' clk Bool -- ^ Write enable+          -> 'Signal'' clk a    -- ^ Value to write (at address \@w\@)           -> 'Signal'' clk a           -- ^ Value of the \@blockRAM\@ at address \@r\@ from the previous clock           -- cycle-blockRam' clk binit wr rd en din =-    'mealy'' clk bram' (binit,undefined) ('bundle'' clk (wr,rd,en,din))+blockRam' clk binit wr rd en din = 'register'' clk undefined dout   where-    bram' (ram,o) (w,r,e,d) = ((ram',o'),o)-      where-        ram' | e         = 'replace' ram w d-             | otherwise = ram-        o'               = ram '!!' r+    szI  = fromInteger $ 'maxIndex' content+    dout = runST $ do+      arr <- newListArray (0,szI) ('toList' content)+      traverse (ramT arr) ('bundle'' clk (wr,rd,en,din))++    ramT :: STArray s Int e -> (Int,Int,Bool,e) -> ST s e+    ramT ram (w,r,e,d) = do+      d' <- readArray ram r+      when e (writeArray ram w d)+      return d' @  And for which the /definition/ primitive is:  @ { \"BlackBox\" :-    { "name"      : "CLaSH.Prelude.BlockRam.blockRam'"+    { "name"      : "CLaSH.Prelude.BlockRam.blockRam#"     , "templateD" : "blockRam_~COMPNAME_~SYM[0] : block-  signal ~SYM[1] : ~TYP[3] := ~LIT[3]; -- ram-  signal ~SYM[2] : ~TYP[7]; -- inp-  signal ~SYM[3] : ~TYP[7]; -- outp+  signal RAM  : ~TYP[2] := ~LIT[2];+  signal dout : ~TYP[6];+  signal wr   : integer range 0 to ~LIT[0] - 1;+  signal rd   : integer range 0 to ~LIT[0] - 1; begin-  ~SYM[2] <= ~ARG[7];+  wr <= ~ARG[3]+  -- pragma translate_off+        mod ~LIT[0]+  -- pragma translate_on+        ; -  process(~CLK[2])+  rd <= ~ARG[4]+  -- pragma translate_off+        mod ~LIT[0]+  -- pragma translate_on+        ;++  blockRam_~SYM[1] : process(~CLK[1])   begin-    if rising_edge(~CLK[2]) then-      if ~ARG[6] then-        ~SYM[1](to_integer(~ARG[4])) <= ~SYM[2];+    if rising_edge(~CLK[1]) then+      if ~ARG[5] then+        RAM(wr) <= ~ARG[6];       end if;-      ~SYM[3] <= ~SYM[1](to_integer(~ARG[5]));+      dout <= RAM(rd);     end if;   end process; -  ~RESULT <= ~SYM[3];+  ~RESULT <= dout; end block;"     }   }@@ -1138,29 +1147,30 @@  @ { \"BlackBox\" :-    { "name"      : "CLaSH.Prelude.BlockRam.blockRam'"+    { "name"      : "CLaSH.Prelude.BlockRam.blockRam#"     , "templateD" :-"// blockRam-reg ~TYPO ~SYM[0] [0:~LIT[0]-1];-reg ~SIGD[~SYM[1]][7];+"// blockRam begin+reg ~TYPO RAM_~SYM[0] [0:~LIT[0]-1];+reg ~TYPO dout_~SYM[1]; -reg ~TYP[3] ~SYM[2];+reg ~TYP[2] ram_init_~SYM[2]; integer ~SYM[3]; initial begin-  ~SYM[2] = ~ARG[3];+  ram_init_~SYM[2] = ~ARG[2];   for (~SYM[3]=0; ~SYM[3] < ~LIT[0]; ~SYM[3] = ~SYM[3] + 1) begin-    ~SYM[0][~LIT[0]-1-~SYM[3]] = ~SYM[2][~SYM[3]*~SIZE[~TYPO]+:~SIZE[~TYPO]];+    RAM_~SYM[0][~LIT[0]-1-~SYM[3]] = ram_init_~SYM[2][~SYM[3]*~SIZE[~TYPO]+:~SIZE[~TYPO]];   end end -always @(posedge ~CLK[2]) begin : blockRam_~COMPNAME_~SYM[4]-  if (~ARG[6]) begin-    ~SYM[0][~ARG[4]] <= ~ARG[7];+always @(posedge ~CLK[1]) begin : blockRam_~COMPNAME_~SYM[4]+  if (~ARG[5]) begin+    RAM_~SYM[0][~ARG[3]] <= ~ARG[6];   end-  ~SYM[1] <= ~SYM[0][~ARG[5]];+  dout_~SYM[1] <= RAM_~SYM[0][~ARG[4]]; end -assign ~RESULT = ~SYM[1];"+assign ~RESULT = dout_~SYM[1];+// blockRam end"     }   } @@@ -1184,23 +1194,304 @@     { "name"      : "CLaSH.Prelude.BlockRam.blockRam'"     , "templateD" : "// blockRam-~SIGD[~SYM[0]][3];-~SIGD[~SYM[1]][7];+~SIGD[RAM_~SYM[0]][2];+~SIGD[dout_~SYM[1]][6];  initial begin   ~SYM[0] = ~LIT[3]; end -always @(posedge ~CLK[2]) begin-  if (~ARG[6]) begin-    ~SYM[0][~ARG[4]] <= ~ARG[7];+always @(posedge ~CLK[1]) begin : blockRam_~COMPNAME_~SYM[3]+  if (~ARG[5]) begin+    RAM_~SYM[0][~ARG[3]] <= ~ARG[6];   end-  ~SYM[1] <= ~SYM[0][~ARG[5]];+  dout_~SYM[1] <= RAM_~SYM[0][~ARG[4]]; end -assign ~RESULT = ~SYM[1];"+assign ~RESULT = dout_~SYM[1];"     }   }+@++-}++{- $multiclock #multiclock#+CλaSH supports multi-clock designs, though perhaps in a slightly limited form.+What is possible is:++* Explicitly assign clocks to memory primitives.+* Synchronise between differently-clocked parts of your design in a type-safe+  way.++What is /not/ possible is:++* Generate a clock signal in module A, and assign this clock signal to a memory+  primitive in module B.++What this means is that when CλaSH converts your design to VHDL/(System)Verilog,+you end up with a top-level module/entity with multiple clock and reset ports+for the different clock domains. If you're targeting an FPGA, you can use e.g. a+<https://www.altera.com/literature/ug/ug_altpll.pdf PPL> or+<http://www.xilinx.com/support/documentation/user_guides/ug472_7Series_Clocking.pdf MMCM>+to provide the clock signals.++== Building a FIFO synchroniser++This part of the tutorial assumes you know what <https://en.wikipedia.org/wiki/Metastability_in_electronics metastability>+is, and how it can never truly be avoided in any asynchronous circuit. Also+it assumes that you are familiar with the design of synchronizer circuits, and+why a dual flip-flop synchroniser only works for bit-synchronisation and not+word-synchronisation.+The explicitly clocked versions of all synchronous functions and primitives can+be found in "CLaSH.Prelude.Explicit", which also re-exports the functions in+"CLaSH.Signal.Explicit". We will use those functions to create a FIFO where+the read and write port are synchronised to different clocks. Below you can find+the code to build the FIFO synchroniser based on the design described in:+<http://www.sunburst-design.com/papers/CummingsSNUG2002SJ_FIFO1.pdf>++We start with enable a few options that will make wring the type-signatures for+our components a bit easier. We'll also import the standard "CLaSH.Prelude"+module, and the "CLaSH.Prelude.Explicit" module for our explicitly clocked+synchronous functions:++@+{\-\# LANGUAGE PartialTypeSignatures \#-\}+{\-\# OPTIONS_GHC -fno-warn-partial-type-signatures \#-\}+module MultiClockFifo where++import CLaSH.Prelude+import CLaSH.Prelude.Explicit+@++Then we'll start with the /hart/ of the FIFO synchroniser, an asynchronous RAM+in the form of 'asyncRam''. It's called an asynchronous RAM because the read+port is not synchronised to any clock (though the write port is). Note that in+CλaSH we don't really have asynchronous logic, there is only combinational and+synchronous logic. As a consequence, we see in the type signature of 'asyncRam'':++    *++    @+    __asyncRam'__ :: _ => SClock wclk        -- ^ Clock to which to synchronise the write port of the RAM+                   -> SClock rclk        -- ^ Clock to which the read address signal __r__ is synchronised+                   -> SNat n             -- ^ Size __n__ of the RAM+                   -> Signal' wclk addr  -- ^ Write address __w__+                   -> Signal' rclk addr  -- ^ Read address __r__+                   -> Signal' wclk Bool  -- ^ Write enable+                   -> Signal' wclk a     -- ^ Value to write (at address __w__)+                   -> Signal' rclk a     -- ^ Value of the RAM at address __r__+    @++that the signal containing the read address __r__ is synchronised to a different+clock. That is, there is __no__ such thing as an @AsyncSignal@ in CλaSH.++We continue by instantiating the 'asyncRam'':++@+fifoMem wclk rclk addrSize waddr raddr winc wfull wdata =+  'asyncRam'' wclk rclk+            (d2 ``powSNat`` addrSize)+            waddr raddr+            (winc '.&&.' 'not1' wfull)+            wdata+@++We see that we give it @2^addrSize@ elements, where @addrSize@ is the bit-size+of the address. Also, we only write new values to the ram when a new write is+requested, indicated by @winc@, and the buffer is not full, indicated by+@wfull@.++The next part of the design calculates the read and write address for the+asynchronous RAM, and creates the flags indicating whether the FIFO is full+or empty. We start with a function that converts 'Bool'eans to @n + 1@ bit+bitvectors:++@+boolToBV :: (KnownNat n, KnownNat (n+1)) => Bool -> BitVector (n + 1)+boolToBV = 'zeroExtend' . 'pack'+@++followed by the actual address and flag generator in 'mealy' machine style:++@+ptrCompareT addrSize flagGen (bin,ptr,flag) (s_ptr,inc) = ((bin',ptr',flag')+                                                          ,(flag,addr,ptr))+  where+    -- GRAYSTYLE2 pointer+    bin' = bin + boolToBV (inc && not flag)+    ptr' = (bin' \`shiftR\` 1) \`xor\` bin'+    addr = 'slice' (addrSize ``subSNat``  d1) d0 bin++    flag' = flagGen ptr' s_ptr+@++It is parametrised in both address size, @addrSize@, and status flag generator,+@flagGen@. It has two inputs, @s_ptr@, the synchronised pointer from the other+clock domain, and @inc@, which indicates we want to perform a write or read of+the FIFO. It creates three outputs: @flag@, the full or empty flag, @addr@, the+read or write address into the RAM, and @ptr@, the Gray-encoded version of the+read or write address which will be synchronised between the two clock domains.++Next follow the initial states of address generators, and the flag generators+for the empty and full flags:++@+-- FIFO empty: when next pntr == synchronized wptr or on reset+isEmpty       = (==)+rptrEmptyInit = (0,0,True)++-- FIFO full: when next pntr == synchonized {~wptr[addrSize:addrSize-1],wptr[addrSize-1:0]}+isFull addrSize ptr s_ptr = ptr == ('complement' ('slice' addrSize (addrSize ``subSNat`` d1) s_ptr) '++#'+                                   'slice' (addrSize ``subSNat`` d2) d0 s_ptr)+wptrFullInit        = (0,0,False)+@++We create a dual flip-flop synchroniser to be used to synchronise the+Gray-encoded pointers between the two clock domains:++@+ptrSync clk1 clk2 = 'register'' clk2 0+                  . 'register'' clk2 0+                  . 'unsafeSynchronizer' clk1 clk2+@++It uses the 'unsafeSynchroniser' primitive, which is needed to go from one clock+domain to the other. All synchronizers are specified in terms of+'unsafeSynchronizer' (see for example the <src/CLaSH-Prelude-RAM.html#line-103 source of asyncRam#>).+The 'unsafeSynchronizer' primitive is turned into a (bundle of) wire(s) by the+CλaSH compiler, so developers must ensure that it is only used as part of a+proper synchronizer.++Finally we combine all the component in:++@+fifo :: _+     => SNat addrSize -> SClock wclk -> SClock rclk+     -> Signal' wclk a -> Signal' wclk Bool+     -> Signal' rclk Bool+     -> (Signal' rclk a, Signal' rclk Bool, Signal' wclk Bool)+fifo addrSize wclk rclk wdata winc rinc = (rdata,rempty,wfull)+  where+    s_rptr = ptrSync wclk rclk rptr+    s_wptr = ptrSync rclk wclk wptr++    rdata = fifoMem wclk rclk addrSize waddr raddr winc wfull wdata++    (rempty,raddr,rptr) = 'mealyB'' rclk (ptrCompareT addrSize isEmpty) rptrEmptyInit+                                  (s_wptr,rinc)++    (wfull,waddr,wptr)  = 'mealyB'' wclk (ptrCompareT addrSize (isFull addrSize))+                                  wptrFullInit (s_rptr,winc)+@++where we first specify the synchronisation of the read and the write pointers,+instantiate the asynchronous RAM, and instantiate the read address/pointer/flag+generator and write address/pointer/flag generator.++Ultimately, the whole file containing our FIFO design will look like this:++@+{\-\# LANGUAGE PartialTypeSignatures \#-\}+{\-\# OPTIONS_GHC -fno-warn-partial-type-signatures \#-\}+module MultiClockFifo where++import CLaSH.Prelude+import CLaSH.Prelude.Explicit++fifoMem wclk rclk addrSize waddr raddr winc wfull wdata =+  'asyncRam'' wclk rclk+            (d2 ``powSNat`` addrSize)+            waddr raddr+            (winc '.&&.' 'not1' wfull)+            wdata++boolToBV :: (KnownNat n, KnownNat (n+1)) => Bool -> BitVector (n + 1)+boolToBV = 'zeroExtend' . 'pack'++ptrCompareT addrSize flagGen (bin,ptr,flag) (s_ptr,inc) = ((bin',ptr',flag')+                                                          ,(flag,addr,ptr))+  where+    -- GRAYSTYLE2 pointer+    bin' = bin + boolToBV (inc && not flag)+    ptr' = (bin' \`shiftR\` 1) \`xor\` bin'+    addr = 'slice' (addrSize ``subSNat`` d1) d0 bin++    flag' = flagGen ptr' s_ptr++-- FIFO empty: when next pntr == synchronized wptr or on reset+isEmpty       = (==)+rptrEmptyInit = (0,0,True)++-- FIFO full: when next pntr == synchonized {~wptr[addrSize:addrSize-1],wptr[addrSize-1:0]}+isFull addrSize ptr s_ptr = ptr == ('complement' ('slice' addrSize (addrSize ``subSNat`` d1) s_ptr) '++#'+                                   'slice' (addrSize ``subSNat`` d2) d0 s_ptr)+wptrFullInit        = (0,0,False)++-- Dual flip-flip synchroniser+ptrSync clk1 clk2 = 'register'' clk2 0+                  . 'register'' clk2 0+                  . 'unsafeSynchronizer' clk1 clk2++-- Async FIFO synchroniser+fifo :: _+     => SNat addrSize -> SClock wclk -> SClock rclk+     -> Signal' wclk a -> Signal' wclk Bool+     -> Signal' rclk Bool+     -> (Signal' rclk a, Signal' rclk Bool, Signal' wclk Bool)+fifo addrSize wclk rclk wdata winc rinc = (rdata,rempty,wfull)+  where+    s_rptr = ptrSync rclk wclk rptr+    s_wptr = ptrSync wclk rclk wptr++    rdata = fifoMem wclk rclk addrSize waddr raddr winc wfull wdata++    (rempty,raddr,rptr) = 'mealyB'' rclk (ptrCompareT addrSize isEmpty) rptrEmptyInit+                                  (s_wptr,rinc)++    (wfull,waddr,wptr)  = 'mealyB'' wclk (ptrCompareT addrSize (isFull addrSize))+                                  wptrFullInit (s_rptr,winc)+@++== Instantiating a FIFO synchroniser++Having finished our FIFO synchroniser it's time to instantiate with concrete+clock domains. Let us assume we have part of our system connected to an ADC+which runs at 20 MHz, and we have created an FFT component running at only 9 MHz,+while the rest of our system runs at 50 MHz. What we want to do connect part+of our design connected to the ADC, and running at 20 MHz, to part of our design+connected to the FFT running at 9 MHz.++First, we must calculate the relative clock periods using 'freqCalc':++>>> freqCalc [20,9,50]+[45,100,18]++We can then create the clocks:++@+type ClkADC = 'Clk \"ADC\"    45+type ClkFFT = 'Clk \"FFT\"    100+type ClkSys = 'Clk \"System\" 18++clkADC :: SClock ClkADC+clkADC = sclock++clkFFT :: SClock ClkFFT+clkFFT = sclock++clkSys :: SClock ClkSys+clkSys = sclock+@++and subsequently a 256-space FIFO synchroniser that safely bridges the ADC clock+domain and to the FFT clock domain:++@+adcToFFT :: Signal' ClkADC (SFixed 8 8)+         -> Signal' ClkADC Bool+         -> Signal' ClkFFT Bool+         -> (Signal' ClkFFT (SFixed 8 8), Signal' ClkFFT Bool, Signal' ClkADC Bool)+adcToFFT = fifo d8 clkADC clkFFT @  -}