clash-prelude-0.10.7: 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
  • DataKinds
  • FlexibleContexts
  • TypeOperators
  • ExplicitNamespaces

CLaSH.Prelude.Explicit

Contents

Description

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.

Synopsis

Creating synchronous sequential circuits

mealy' Source

Arguments

:: SClock clk

Clock to synchronize to

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

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

-> s

Initial state

-> Signal' clk i -> Signal' clk 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

type ClkA = Clk "A" 100

clkA :: SClock ClkA
clkA = sclock

topEntity :: Signal' ClkA (Int, Int) -> Signal' ClkA Int
topEntity = mealy' clkA 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' clkA100 Int, Signal' clkA100 Int)
        -> (Signal' clkA100 Int, Signal' clkA100 Int)
        -> Signal' clkA100 Int
dualMac (a,b) (x,y) = s1 + s2
  where
    s1 = mealy' clkA100 mac 0 (bundle' clkA100 (a,x))
    s2 = mealy' clkA100 mac 0 (bundle' clkA100 (b,y))

mealyB' Source

Arguments

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

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

-> s

Initial state

-> Unbundled' clk i -> Unbundled' clk 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 clk a b c = (b1,b2,i2)
  where
    (i1,b1) = unbundle' clk (mealy' clk f 0 (bundle' clk (a,b)))
    (i2,b2) = unbundle' clk (mealy' clk f 3 (bundle' clk (i1,c)))

Using mealyB' however we can write:

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

moore' Source

Arguments

:: SClock clk

Clock to synchronize to

-> (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' clk i -> Signal' clk 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,Int)  -- Updated state
mac s (x,y) = x * y + s

type ClkA = Clk "A" 100

clkA :: SClock ClkA
clkA = sclock

topEntity :: Signal' ClkA (Int, Int) -> Signal' ClkA Int
topEntity = moore' clkA 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' clkA Int, Signal' clkA Int)
        -> (Signal' clkA Int, Signal' clkA Int)
        -> Signal' clkA Int
dualMac (a,b) (x,y) = s1 + s2
  where
    s1 = moore' clkA mac id 0 (bundle' clkA (a,x))
    s2 = moore' clkA mac id 0 (bundle' clkA (b,y))

mooreB' Source

Arguments

:: (Bundle i, Bundle o) 
=> SClock clk 
-> (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' clk i -> Unbundled' clk 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 clk a b c = (b1,b2,i2)
  where
    (i1,b1) = unbundle' clk (moore' clk t o 0 (bundle' clk (a,b)))
    (i2,b2) = unbundle' clk (moore' clk t o 3 (bundle' clk (i1,c)))

Using mooreB' however we can write:

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

registerB' :: Bundle a => SClock clk -> a -> Unbundled' clk a -> Unbundled' clk a Source

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

Synchronizer circuits for safe clock domain crossings

dualFlipFlopSynchronizer Source

Arguments

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

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 lsbs. 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 lsbs were.

    If you want to have safe word-synchronisation use asyncFIFOSynchronizer.

asyncFIFOSynchronizer Source

Arguments

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

Synchroniser implemented as a FIFO around an asynchronous RAM. Based on the design described in CLaSH.Tutorial, 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.

ROMs

rom' Source

Arguments

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

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

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

romFile' Source

Arguments

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

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

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

Create a RAM with space for n elements

Additional helpful information:

asyncRamPow2' Source

Arguments

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

Create a RAM with space for 2^n elements

Additional helpful information:

BlockRAM primitives

blockRam' Source

Arguments

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

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 -> ClkA Signal' Bit
bram40 = blockRam' clkA100 (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' clk (blockRam' clk inits) wr rd en dt.

blockRamPow2' Source

Arguments

:: (KnownNat n, KnownNat (2 ^ n)) 
=> SClock clk

Clock to synchronize to

-> Vec (2 ^ n) a

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

NB: MUST be a constant.

-> Signal' clk (Unsigned n)

Write address w

-> Signal' clk (Unsigned n)

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

Create a blockRAM with space for 2^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

bram32 :: Signal' ClkA (Unsigned 5) -> Signal' ClkA (Unsigned 5)
       -> Signal' ClkA Bool -> Signal' ClkA Bit -> Signal' ClkA Bit
bram32 = blockRamPow2' clkA100 (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' clk (blockRamPow2' clk inits) wr rd en dt.

BlockRAM primitives initialised with a data file

blockRamFile' Source

Arguments

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

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' clk (blockRamFile' clk 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)) 
=> 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

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' clk (blockRamFilePow2' clk 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.

Utility functions

window' Source

Arguments

:: (KnownNat n, Default a) 
=> SClock clk

Clock to which the incoming signal is synchronized

-> Signal' clk a

Signal to create a window over

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

Window of at least size 1

Give a window over a Signal'

type ClkA = Clk "A" 100

clkA :: SClock ClkA
clkA = sclock

window4 :: Signal' ClkA Int -> Vec 4 (Signal' ClkA Int)
window4 = window' clkA
>>> simulateB' clkA clkA 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) 
=> SClock clk

Clock to which the incoming signal is synchronized

-> Signal' clk a

Signal to create a window over

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

Window of at least size 1

Give a delayed window over a Signal'

type ClkA = Clk "A" 100

clkA :: SClock ClkA
clkA = sclock

windowD3 :: Signal' ClkA Int -> Vec 3 (Signal' ClkA Int)
windowD3 = windowD' clkA
>>> simulateB' clkA clkA 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) 
=> SClock clk 
-> a

Starting value

-> Signal' clk a 
-> Signal' clk Bool 

Give a pulse when the Signal' goes from minBound to maxBound

isFalling' Source

Arguments

:: (Bounded a, Eq a) 
=> SClock clk 
-> a

Starting value

-> Signal' clk a 
-> Signal' clk Bool 

Give a pulse when the Signal' goes from maxBound to minBound

Testbench functions

assert' Source

Arguments

:: (Eq a, Show a) 
=> SClock t 
-> String

Additional message

-> Signal' t a

Checked value

-> Signal' t a

Expected value

-> Signal' t b

Return value

-> Signal' t b 

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 can be used in synthesizable designs.

stimuliGenerator' Source

Arguments

:: KnownNat l 
=> SClock clk

Clock to which to synchronize the output signal

-> Vec l a

Samples to generate

-> Signal' clk 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:

type ClkA = Clk "A" 100

clkA :: SClock ClkA
clkA = sclock

testInput' :: Signal' clkA Int
testInput' = stimuliGenerator' clkA $(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) 
=> SClock clk

Clock to which the input signal is synchronized to

-> Vec l a

Samples to compare with

-> Signal' clk a

Signal to verify

-> Signal' clk 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:

type ClkA = Clk "A" 100

clkA :: SClock ClkA
clkA = sclock

expectedOutput' :: Signal' ClkA Int -> Signal' ClkA Bool
expectedOutput' = outputVerifier' clkA $(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(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]

Exported modules

Explicitly clocked synchronous signals