clash-prelude-0.10.13: CAES Language for Synchronous Hardware - Prelude library

Copyright(C) 2013-2016, University of Twente
LicenseBSD2 (see the file LICENSE)
MaintainerChristiaan Baaij <christiaan.baaij@gmail.com>
Safe HaskellUnsafe
LanguageHaskell2010
Extensions
  • Cpp
  • DataKinds
  • FlexibleContexts
  • TypeOperators
  • ExplicitNamespaces

CLaSH.Prelude

Contents

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:

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.

Synopsis

Creating synchronous sequential circuits

mealy Source

Arguments

:: (s -> i -> (s, o))

Transfer function in mealy machine form: state -> input -> (newstate,output)

-> s

Initial state

-> Signal i -> Signal o

Synchronous sequential function with input and output matching that of the mealy machine

Create a synchronous function from a combinational function describing a mealy machine

mac :: Int        -- Current state
    -> (Int,Int)  -- Input
    -> (Int,Int)  -- (Updated state, output)
mac s (x,y) = (s',s)
  where
    s' = x * y + s

topEntity :: Signal (Int, Int) -> Signal Int
topEntity = mealy mac 0
>>> simulate topEntity [(1,1),(2,2),(3,3),(4,4)]
[0,1,5,14...

Synchronous sequential functions can be composed just like their combinational counterpart:

dualMac :: (Signal Int, Signal Int)
        -> (Signal Int, Signal Int)
        -> Signal Int
dualMac (a,b) (x,y) = s1 + s2
  where
    s1 = mealy mac 0 (bundle (a,x))
    s2 = mealy mac 0 (bundle (b,y))

mealyB Source

Arguments

:: (Bundle i, Bundle o) 
=> (s -> i -> (s, o))

Transfer function in mealy machine form: state -> input -> (newstate,output)

-> s

Initial state

-> Unbundled i -> Unbundled o

Synchronous sequential function with input and output matching that of the mealy machine

A version of mealy that does automatic Bundleing

Given a function f of type:

f :: Int -> (Bool, Int) -> (Int, (Int, Bool))

When we want to make compositions of f in g using mealy, we have to write:

g a b c = (b1,b2,i2)
  where
    (i1,b1) = unbundle (mealy f 0 (bundle (a,b)))
    (i2,b2) = unbundle (mealy f 3 (bundle (i1,c)))

Using mealyB however we can write:

g a b c = (b1,b2,i2)
  where
    (i1,b1) = mealyB f 0 (a,b)
    (i2,b2) = mealyB f 3 (i1,c)

(<^>) Source

Arguments

:: (Bundle i, Bundle o) 
=> (s -> i -> (s, o))

Transfer function in mealy machine form: state -> input -> (newstate,output)

-> s

Initial state

-> Unbundled i -> Unbundled o

Synchronous sequential function with input and output matching that of the mealy machine

Infix version of mealyB

moore Source

Arguments

:: (s -> i -> s)

Transfer function in moore machine form: state -> input -> newstate

-> (s -> o)

Output function in moore machine form: state -> output

-> s

Initial state

-> Signal i -> Signal o

Synchronous sequential function with input and output matching that of the moore machine

Create a synchronous function from a combinational function describing a moore machine

mac :: Int        -- Current state
    -> (Int,Int)  -- Input
    -> Int        -- Updated state
mac s (x,y) = x * y + s

topEntity :: Signal (Int, Int) -> Signal Int
topEntity = moore mac id 0
>>> simulate topEntity [(1,1),(2,2),(3,3),(4,4)]
[0,1,5,14...

Synchronous sequential functions can be composed just like their combinational counterpart:

dualMac :: (Signal Int, Signal Int)
        -> (Signal Int, Signal Int)
        -> Signal Int
dualMac (a,b) (x,y) = s1 + s2
  where
    s1 = moore mac id 0 (bundle (a,x))
    s2 = moore mac id 0 (bundle (b,y))

mooreB Source

Arguments

:: (Bundle i, Bundle o) 
=> (s -> i -> s)

Transfer function in moore machine form: state -> input -> newstate

-> (s -> o)

Output function in moore machine form: state -> output

-> s

Initial state

-> Unbundled i -> Unbundled o

Synchronous sequential function with input and output matching that of the moore machine

A version of moore that does automatic Bundleing

Given a functions t and o of types:

t :: Int -> (Bool, Int) -> Int
o :: Int -> (Int, Bool)

When we want to make compositions of t and o in g using moore, we have to write:

g a b c = (b1,b2,i2)
  where
    (i1,b1) = unbundle (moore t o 0 (bundle (a,b)))
    (i2,b2) = unbundle (moore t o 3 (bundle (i1,c)))

Using mooreB however we can write:

g a b c = (b1,b2,i2)
  where
    (i1,b1) = mooreB t o 0 (a,b)
    (i2,b2) = mooreB t o 3 (i1,c)

registerB :: Bundle a => a -> Unbundled a -> Unbundled a Source

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)...

ROMs

asyncRom Source

Arguments

:: (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

An asynchronous/combinational ROM with space for n elements

Additional helpful information:

asyncRomPow2 Source

Arguments

:: (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

An asynchronous/combinational ROM with space for 2^n elements

Additional helpful information:

rom Source

Arguments

:: (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

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:

romPow2 Source

Arguments

:: (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

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:

ROMs initialised with a data file

asyncRomFile Source

Arguments

:: (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

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   | Works    | Works         |
    Xilinx/ISE     | Works    | Works    | Works         |
    ASIC           | Untested | Untested | Untested      |
    ===============+==========+==========+===============+
    

Additional helpful information:

  • See CLaSH.Prelude.ROM.File for more information on how to instantiate a ROM with the contents of a data file.
  • See CLaSH.Sized.Fixed for ideas on how to create your own data files.
  • When you notice that asyncRomFile is significantly slowing down your simulation, give it a monomorphic type signature. So instead of leaving the type to be inferred:

    myRomData = asyncRomFile d512 "memory.bin"
    

    or giving it a polymorphic type signature:

    myRomData :: Enum addr => addr -> BitVector 16
    myRomData = asyncRomFile d512 "memory.bin"
    

    you should give it a monomorphic type signature:

    myRomData :: Unsigned 9 -> BitVector 16
    myRomData = asyncRomFile d512 "memory.bin"
    

asyncRomFilePow2 Source

Arguments

:: (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

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   | Works    | Works         |
    Xilinx/ISE     | Works    | Works    | Works         |
    ASIC           | Untested | Untested | Untested      |
    ===============+==========+==========+===============+
    

Additional helpful information:

  • See CLaSH.Prelude.ROM.File for more information on how to instantiate a ROM with the contents of a data file.
  • See CLaSH.Sized.Fixed for ideas on how to create your own data files.
  • When you notice that asyncRomFilePow2 is significantly slowing down your simulation, give it a monomorphic type signature. So instead of leaving the type to be inferred:

    myRomData = asyncRomFilePow2 "memory.bin"
    

    you should give it a monomorphic type signature:

    myRomData :: Unsigned 9 -> BitVector 16
    myRomData = asyncRomFilePow2 "memory.bin"
    

romFile Source

Arguments

:: (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

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   | Works    | Works         |
    Xilinx/ISE     | Works    | Works    | Works         |
    ASIC           | Untested | Untested | Untested      |
    ===============+==========+==========+===============+
    

Additional helpful information:

romFilePow2 Source

Arguments

:: (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

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   | Works    | Works         |
    Xilinx/ISE     | Works    | Works    | Works         |
    ASIC           | Untested | Untested | Untested      |
    ===============+==========+==========+===============+
    

Additional helpful information:

RAM primitives with a combinational read port

asyncRam Source

Arguments

:: 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

Create a RAM with space for n elements.

Additional helpful information:

asyncRamPow2 Source

Arguments

:: (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

Create a RAM with space for 2^n elements

Additional helpful information:

BlockRAM primitives

blockRam Source

Arguments

:: (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

Create a blockRAM with space for n elements.

  • NB: Read value is delayed by 1 cycle
  • NB: Initial output value is undefined
bram40 :: Signal (Unsigned 6) -> Signal (Unsigned 6) -> Signal Bool
       -> Signal Bit -> Signal Bit
bram40 = blockRam (replicate d40 1)

Additional helpful information:

  • See CLaSH.Prelude.BlockRam for more information on how to use a Block RAM.
  • Use the adapter readNew for obtaining write-before-read semantics like this: readNew (blockRam inits) wr rd en dt.

blockRamPow2 Source

Arguments

:: (KnownNat (2 ^ n), KnownNat n) 
=> Vec (2 ^ n) a

Initial content of the BRAM, also determines the size, 2^n, of the BRAM.

NB: MUST be a constant.

-> 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 blockRAM at address r from the previous clock cycle

Create a blockRAM with space for 2^n elements

  • NB: Read value is delayed by 1 cycle
  • NB: Initial output value is undefined
bram32 :: Signal (Unsigned 5) -> Signal (Unsigned 5) -> Signal Bool
       -> Signal Bit -> Signal Bit
bram32 = blockRamPow2 (replicate d32 1)

Additional helpful information:

  • See CLaSH.Prelude.BlockRam for more information on how to use a Block RAM.
  • Use the adapter readNew for obtaining write-before-read semantics like this: readNew (blockRamPow2 inits) wr rd en dt.

BlockRAM primitives initialised with a data file

blockRamFile Source

Arguments

:: (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

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   | Works    | Works         |
    Xilinx/ISE     | Works    | Works    | Works         |
    ASIC           | Untested | Untested | Untested      |
    ===============+==========+==========+===============+
    

Additional helpful information:

  • See CLaSH.Prelude.BlockRam for more information on how to use a Block RAM.
  • Use the adapter readNew for obtaining write-before-read semantics like this: readNew (blockRamFile size file) wr rd en dt.
  • See CLaSH.Prelude.BlockRam.File for more information on how to instantiate a Block RAM with the contents of a data file.
  • See CLaSH.Sized.Fixed for ideas on how to create your own data files.

blockRamFilePow2 Source

Arguments

:: (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

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   | Works    | Works         |
    Xilinx/ISE     | Works    | Works    | Works         |
    ASIC           | Untested | Untested | Untested      |
    ===============+==========+==========+===============+
    

Additional helpful information:

  • See CLaSH.Prelude.BlockRam for more information on how to use a Block RAM.
  • Use the adapter readNew for obtaining write-before-read semantics like this: readNew (blockRamFilePow2 file) wr rd en dt.
  • See CLaSH.Prelude.BlockRam.File for more information on how to instantiate a Block RAM with the contents of a data file.
  • See CLaSH.Sized.Fixed for ideas on how to create your own data files.

BlockRAM read/write conflict resolution

readNew :: Eq addr => (Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a) -> Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a Source

Create read-after-write blockRAM from a read-before-write one (synchronised to system clock)

>>> import CLaSH.Prelude
>>> :t readNew (blockRam (0 :> 1 :> Nil))
readNew (blockRam (0 :> 1 :> Nil))
  :: (Enum addr, Eq addr, Num a) =>
     Signal addr -> Signal addr -> Signal Bool -> Signal a -> Signal a

readNew' :: Eq addr => SClock clk -> (Signal' clk addr -> Signal' clk addr -> Signal' clk Bool -> Signal' clk a -> Signal' clk a) -> Signal' clk addr -> Signal' clk addr -> Signal' clk Bool -> Signal' clk a -> Signal' clk a Source

Create read-after-write blockRAM from a read-before-write one (synchronised to specified clock)

Utility functions

window Source

Arguments

:: (KnownNat n, Default a) 
=> Signal a

Signal to create a window over

-> Vec (n + 1) (Signal a)

Window of at least size 1

Give a window over a Signal

window4 :: Signal Int -> Vec 4 (Signal Int)
window4 = window
>>> simulateB window4 [1::Int,2,3,4,5] :: [Vec 4 Int]
[<1,0,0,0>,<2,1,0,0>,<3,2,1,0>,<4,3,2,1>,<5,4,3,2>...

windowD Source

Arguments

:: (KnownNat (n + 1), Default a) 
=> Signal a

Signal to create a window over

-> Vec (n + 1) (Signal a)

Window of at least size 1

Give a delayed window over a Signal

windowD3 :: Signal Int -> Vec 3 (Signal Int)
windowD3 = windowD
>>> simulateB windowD3 [1::Int,2,3,4] :: [Vec 3 Int]
[<0,0,0>,<1,0,0>,<2,1,0>,<3,2,1>,<4,3,2>...

isRising Source

Arguments

:: (Bounded a, Eq a) 
=> a

Starting value

-> Signal a 
-> Signal Bool 

Give a pulse when the Signal goes from minBound to maxBound

isFalling Source

Arguments

:: (Bounded a, Eq a) 
=> a

Starting value

-> Signal a 
-> Signal Bool 

Give a pulse when the Signal goes from maxBound to minBound

Testbench functions

assert Source

Arguments

:: (Eq a, Show a) 
=> String

Additional message

-> Signal a

Checked value

-> Signal a

Expected value

-> Signal b

Return value

-> Signal b 

Compares the first two Signals 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 can be used in synthesizable designs.

stimuliGenerator Source

Arguments

:: KnownNat l 
=> Vec l a

Samples to generate

-> Signal a

Signal of given samples

To be used as one of the functions to create the "magical" testInput value, which the CλaSH compiler looks for to create the stimulus generator for the generated VHDL testbench.

Example:

testInput :: Signal Int
testInput = stimuliGenerator $(v [(1::Int),3..21])
>>> sampleN 13 testInput
[1,3,5,7,9,11,13,15,17,19,21,21,21]

outputVerifier Source

Arguments

:: (KnownNat l, Eq a, Show a) 
=> Vec l a

Samples to compare with

-> Signal a

Signal to verify

-> Signal Bool

Indicator that all samples are verified

To be used as one of the functions to generate the "magical" expectedOutput function, which the CλaSH compiler looks for to create the signal verifier for the generated VHDL testbench.

Example:

expectedOutput :: Signal Int -> Signal Bool
expectedOutput = outputVerifier $(v ([70,99,2,3,4,5,7,8,9,10]::[Int]))
>>> 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]

Exported modules

Synchronous signals

DataFlow interface

Datatypes

Bit vectors

Arbitrary-width numbers

Fixed point numbers

Fixed size vectors

Perfect depth trees

Annotations

Type-level natural numbers

Type-level functions

Template Haskell

class Lift t where

Methods

lift :: t -> Q Exp

Instances

Lift Bool 
Lift Char 
Lift Double 
Lift Float 
Lift Int 
Lift Int8 
Lift Int16 
Lift Int32 
Lift Int64 
Lift Integer 
Lift Word 
Lift Word8 
Lift Word16 
Lift Word32 
Lift Word64 
Lift () 
Lift Natural 
Lift a => Lift [a] 
Integral a => Lift (Ratio a) 
Lift a => Lift (Maybe a) 
KnownNat n => Lift (Index n) 
KnownNat n => Lift (BitVector n) 
KnownNat n => Lift (Signed n) 
KnownNat n => Lift (Unsigned n) 
(Lift a, Lift b) => Lift (Either a b) 
(Lift a, Lift b) => Lift (a, b) 
Lift a => Lift (Signal' clk a) 
Lift a => Lift (Vec n a) 
(Lift a, Lift b, Lift c) => Lift (a, b, c) 
(Lift (rep ((+) int frac)), KnownNat frac, KnownNat int, Typeable (Nat -> *) rep) => Lift (Fixed rep int frac) 
Lift a => Lift (DSignal' clk delay a) 
(Lift a, Lift b, Lift c, Lift d) => Lift (a, b, c, d) 
(Lift a, Lift b, Lift c, Lift d, Lift e) => Lift (a, b, c, d, e) 
(Lift a, Lift b, Lift c, Lift d, Lift e, Lift f) => Lift (a, b, c, d, e, f) 
(Lift a, Lift b, Lift c, Lift d, Lift e, Lift f, Lift g) => Lift (a, b, c, d, e, f, g) 

deriveLift :: Name -> Q [Dec]

Derive Lift instances for the given datatype.

Type classes

CLaSH

Other

module Data.Bits

Haskell Prelude

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 Vec at CLaSH.Sized.Vector.

module Prelude