CλaSH FPGA Starter

This version of the tutorial is outdated, please follow the new version.

In this tutorial we’ll be programming the Terasic DE0-Nano FPGA development board using the functional hardware description language CλaSH. The end result of this tutorial is demonstrated in the video below:

Watch this video on YouTube.

This tutorial is not a general introduction to CλaSH, nor to programming FPGAs. It is meant to demonstrate how to use of `TopEntity` annotations (added in version `0.5.5` of CλaSH) to configure your CλaSH designs for an FPGA, without writing a single line of VHDL or (System)Verilog. Even then, this tutorial is already almost too long for single blog post, but here goes:

This tutorial used to be specified in terms of `.topentity` files, a method which is now superseded by `TopEntity` annotions. You can still see the old version on github.

Blinker circuit

We start with some general information about the DE0-Nano board:

  • It has a 50 MHz crystal connected to a clock pin of FPGA, which we will connect to one of the PLLs that is on the FPGA to create a stable 50 MHz clock signal.
  • It has 8 green LEDs that turn on when we put a `1` on the FPGA pin connected to the LED.
  • It has two buttons which are already properly debounced by a Schmitt trigger. The buttons are `0` when they are pressed, and `1` when they are not.

The circuit that we are making will repeatedly do one of two things:

  • Invert the state of the LEDs
  • Rotate the state of the LEDs

We switch between these two modes when the `KEY1` button on the board is pressed and subsequently released. We reset the circuit by pressing the `KEY0` button.

CλaSH circuit specification

The `Blinker.hs` file given below implements the behaviour of circuit (sans reset behaviour) we just described. As the clock is running at `50 MHz`, we shouldn’t update the state of the LEDs every clock cycle, as they will just seem to to all be turned on all the time to the human eye. We hence use a counter that counts up to a certain amount of clock cycles, and only update the state of the LEDs when the desired number of cycles is reached and the count is reset.


module Blinker where

import CLaSH.Prelude

{-# ANN topEntity
    { t_name     = "blinker"
    , t_inputs   = ["KEY1"]
    , t_outputs  = ["LED"]
    , t_extraIn  = [ ("CLOCK_50", 1)
                   , ("KEY0"    , 1)
    , t_clocks   = [ (altpll "altpll50"
                             "not KEY0(0)")
    }) #-}
topEntity :: Signal Bit -> Signal (BitVector 8)
topEntity key1 = leds
    key1R = isRising 1 key1
    leds  = mealy blinkerT (1,False,0) key1R

blinkerT (leds,mode,cntr) key1R = ((leds',mode',cntr'),leds)
    – clock frequency = 50e6   (50 MHz)
    – led update rate = 333e-3 (every 333ms)
    cnt_max = 16650000 – 50e6 * 333e-3

    cntr' | cntr == cnt_max = 0
          | otherwise       = cntr + 1

    mode' | key1R     = not mode
          | otherwise = mode

    leds' | cntr == 0 = if mode then complement leds
                                else rotateL leds 1
          | otherwise = leds

`TopEntity` annotations

Now that we’ve created our CλaSH design, it’s time to move on to the important part of this tutorial, elaboration of the `TopEntity` annotation. The TopEntity is a Haskell data type that guides the CλaSH compiler in generating port names and setting up clocks. These annotations are applied using the `ANN` pragma:

`{-# ANN foo (TopEntity {t_name = .., .., ..}) #-}`

In our example, we extend the minimalist defTop annotation with:

  • `t_name`: the name our component should have. In our case: `blinker`
  • `t_inputs`: a list of names our inputs should have. In our case: `KEY1`
  • `t_outputs`: a list of names our outputs should have. In our case: `LED`
  • `t_extraIn`: a list of extra inputs that do not correspond to the arguments of our `topEntity` function.
    These extra inputs are always bit vectors.
    Every item in the `extra_in` list is a tuple (encoded as a 2-element list) of a name, and the number of bits for that input.
    In our case we add an extra 1-bit input `CLOCK_50` which will correspond to the pin to which the 50MHz crystal is attached, and a 1-bit input `KEY0` which is the button we will use as a reset.
  • `t_clocks`: a list of clock sources.

We create a single clock source by instantiating the _default_ template for the Altera PPL component altpll for the Cyclone IV. The first argument of this function is the name, the second an expression corresponding to the clock pin to connect, and the third the expression corresponding to the reset pin to connect. So to elaborate the arguments in order:

  • `name`: the name of the component generating our clock. In our case `”altpll50″`, an instantiated PLL component we will create later on in this tutorial.
  • `clock port`: Now, I lied a bit that we didn’t have to write any VHDL or SystemVerilog. As you can see, we connect the clock port to the expression `CLOCK_50(0)`, which is a VHDL expression. The `altpll50`s `clock port` expects a single bit, but our `CLOCK_50` port is a 1-bit vector. Hence we need to select the first (and only) bit: `”CLOCK_50(0)”`.
  • `reset port`: Again, we have to write some VHDL: `not KEY0(0)`. Remember that our extra inputs are bit vectors, but the `reset port` expects a single bit. Hence we need to select the first (and only) bit: `KEY0(0)`. Additionally, remember that the keys are `0` when they are pressed, but the reset port expects an active-high signal. Hence we need to negate the signal: `”not KEY0(0)”`.

VHDL generation

Now it’s time to generate some VHDL, yay! Make sure that the `Blinker.hs` file is in your current working directory, and then run the CλaSH compiler to generate VHDL:

`clash – vhdl Blinker.hs`

This will create a `./vhdl/Blinker/` directory, of which, for this tutorial, the most interesting file is within that directory is:


 – Automatically generated VHDL
library IEEE;
use work.all;
use work.types.all;

entity blinker is
  port(KEY1     : in std_logic_vector(0 downto 0);
       CLOCK_50 : in std_logic_vector(0 downto 0);
       KEY0     : in std_logic_vector(0 downto 0);
       LED      : out std_logic_vector(7 downto 0));

architecture structural of blinker is
  signal system1000      : std_logic;
  signal system1000_rstn : std_logic;
  signal altpll50_locked : std_logic;
  altpll50_inst : entity altpll50
    port map
      (inclk0 => CLOCK_50(0)
      ,c0     => system1000
      ,areset => not KEY0(0)
      ,locked => altpll50_locked);

  – reset system1000_rstn is asynchronously asserted,
  – but synchronously de-asserted
  resetSync_n_0 : block
    signal n_1 : std_logic;
    signal n_2 : std_logic;
      if altpll50_locked = '0' then
        n_1 <= '0';
        n_2 <= '0';
      elsif rising_edge(system1000) then
        n_1 <= '1';
        n_2 <= n_1;
      end if;
    end process;

    system1000_rstn <= n_2;
  end block;

  topEntity_0_inst : entity topEntity_0
    port map
      (key1_i1         => KEY1
      ,system1000      => system1000
      ,system1000_rstn => system1000_rstn
      ,topLet_o        => LED);

Port/Pin mappings

It’s almost time to start programming our FPGA. But first we need to setup how the component ports are connected to the right pins on the FPGA.
For this we will use the `DE0_Nano_SystemBuilder` which you can find on the DE0-Nano CD-ROM. This will create both a pin/port map file, and a Quartus II project file. Note that I work on OS X, so both `DE0_Nano_SystemBuilder` and `Quartus II` are running inside a VirtualBox VM running Windows 8.


In `DE0_Nano_SystemBuilder`, call the project `blinker`, and ensure that only `CLOCK`, `Button x 2`, and `LED x 8` are selected.
Then press the `Generate` button, this will open a `save` dialog window: select a location where you want to create the project and hit the `save` button.
You can now close `DE0_Nano_SystemBuilder`.

In the directory to which you saved the project you will find the files:

  • `blinker.htm`
  • `blinker.qpf`
  • `blinker.qsf`
  • `blinker.sdc`
  • `blinker.v`

You can delete `blinker.v` as we will be using our `blinker.vhdl`. The port/pin mappings that are generated by `DE0_Nano_SystemBuilder` do not completely correspond to our port names. We will hence need to update the mapping file `blinker.qsf`:

  • Replace every occurrence of `CLOCK_50` by `CLOCK_50[0]`
  • Replace every occurrence of `KEY[0]` by `KEY0[0]`
  • Replace every occurrence of `KEY[1]` by `KEY1[0]`

The final `blinker.qsf` file will look like:

# Build by Terasic System Builder

set_global_assignment -name FAMILY "Cyclone IV E"
set_global_assignment -name DEVICE EP4CE22F17C6
set_global_assignment -name TOP_LEVEL_ENTITY "blinker"
set_global_assignment -name ORIGINAL_QUARTUS_VERSION "12.0"
set_global_assignment -name LAST_QUARTUS_VERSION "12.0"
set_global_assignment -name PROJECT_CREATION_TIME_DATE "12:43:02 MAY 01,2015"
set_global_assignment -name DEVICE_FILTER_PACKAGE FBGA
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 256
set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 6
set_global_assignment -name SDC_FILE blinker.SDC

set_location_assignment PIN_R8 -to CLOCK_50[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLOCK_50[0]

set_location_assignment PIN_A15 -to LED[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[0]
set_location_assignment PIN_A13 -to LED[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[1]
set_location_assignment PIN_B13 -to LED[2]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[2]
set_location_assignment PIN_A11 -to LED[3]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[3]
set_location_assignment PIN_D1 -to LED[4]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[4]
set_location_assignment PIN_F3 -to LED[5]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[5]
set_location_assignment PIN_B1 -to LED[6]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[6]
set_location_assignment PIN_L3 -to LED[7]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED[7]

set_location_assignment PIN_J15 -to KEY0[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to KEY0[0]
set_location_assignment PIN_E1 -to KEY1[0]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to KEY1[0]

# End of pin assignments by Terasic System Builder

Also, since we will be using the `PLL` for clocks, you can replace the entire contents of `blinker.sdc` by:


Quartus II

We now open the `blinker.qpf` file in `Quartus II`. For this tutorial, I will be using version `14.1` of the `Quartus II` software.
The first thing we will do is add the VHDL files generated by CλaSH to our design. In the menu bar, go to, `Project -> Add/Remove Files in Project…`, press the `…` button next to `File name`, in the load dialog, select all the files generated by clash, and press `Open`. Then press `OK` to close the `Settings` dialog.


Next we will create a `PLL` component. On the right of the `Quartus II` main window you will see the `IP Catalog`. Go to `Installed IP > Library > Basic Functions > Clocks; PLLs and Resets > PLL`, and double click on `ALTPLL`.


This opens a dialog called `Save IP Variation`, at the end of the line enter `altpll50` and press `OK`.


This opens the `MegaWizard` dialog for the PLL. Change `What is the frequency of the inclk0 input?` to `50.000`.


Then press `Finish` twice. This closes the `MegaWizard` dialog, and opens a new dialog asking if you want to add this IP block to your project. We want this, so select ‘Yes’.

Synthesis time

Finally, we’re finished with configuration, and we can start creating the configuration file for the FPGA. In the menu bar, click: ‘Processing -> Start Compilation’. In my extremely slow VM this compilation/synthesis process will take a while, if but might be much faster on your machine.

Programming time

After synthesis has finished, it is time to program our FPGA board. Connect the FPGA board to a USB port, and start the programmer from the menu bar: `Tools -> Programmer`. Press the `Start` button on the left to program your FPGA and wait until the progress bar says `100% (Successful)`.


Time to play

Your FPGA should now be fully configured with the CλaSH generated design for you to play with. So yeah, go press those buttons!

This ends the tutorial on the use of `TopEntity` annotations to program your FPGA devices with CλaSH designs. I hope you got the gist of it. If/When I get my hands on a Xilinx FPGA board, I hope to make an alternate version of this tutorial, but then use Xilinx’ ISE/Vivado tool-flow instead.

An FPGA design house delivering "right the first time" solutions.

Design and realisation by:
Comyoo | creatieve studio


Institutenweg 25A
7521 PH Enschede
+31 (0)85 8000 380