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

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

CLaSH.Prelude.Explicit.Safe

Contents

Description

This is the 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.

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 crossing

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:

RAM primitives with a combinational read port

asyncRam' Source

Arguments

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

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:

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:

Utility functions

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

Exported modules

Explicitly clocked synchronous signals