Would you like to be notified by email when Christopher Felton publishes a new blog?
Have you seen the latest FPGA offerings from 'X' and 'A'. These latest devices are huge! Even the devices that one can get for sub $10 are relatively large. Because of the size of these FPGAs they are implemented using an HDL. To manually configure each circuit would be a long and tedious task. It is not feasible to program an FPGA by manually defining the logic for each LUT and manually connecting the logic blocks. To implement (configure) an FPGA it is required to use an HDL or other high-level description or tool. Software will translate the hardware descriptions to the bit configurations required to program the FPGA.
Note: Yes, it is possible to program an FPGA schematically and build a hierarchy (similar to structural HDL). This is rarely used, schematic design is used for small "glue" logic or top-level stitching of the blocks together.
As mentioned majority of FPGA designers and FPGA hobbyist will define their FPGA designs with an HDL (hardware description language). For many people doing an FPGA project, if they have been introduced to an HDL in the past, they will choose Verilog or VHDL as their HDL. They will select Verilog/VHDL because that is what they were taught. But doing so they are missing out on another excellent HDL called MyHDL. MyHDL is a Python package that allows digital hardware description in Python.
The following is a tutorial using MyHDL to implement a design and run the FPGA tools generating a bit-stream for a development board. This tutorial contains project files for the DSPtronics SignaX1 (SX1), Digilent Nexsys2, teraAsic DE2, and USBP boards. The design of the HDL is board independent, for this design all that is required is a bank of LEDs and a clock. The only board dependent constraints are the pin mappings and the clock frequency. The generation of the constraints is handled by the conversion script, creating the FPGA specific constraints and running the tools are handled via Python as well (one-stop language for this tutorial).
Each of the development boards used in this tutorial have medium sized FPGAs and a bank of LEDs available. The boards are development boards that I had laying around that made it easy to download the designs once the bit files were created. As mentioned, for this tutorial everything after the design entry has been automated. There is one script to create a bit file. This does require that the FPGA tools be installed and accessible (path to the tools is in your PATH so that the script can access the tools). Thanks to Guenter Dannoritzer for creating the Python script to run the Xilinx tools. The script has been modified for this tutorial and the modified script can be found in the repository with the rest of the design files.
To walk through this tutorial it is presumed that the MyHDL manual has been reviewed and/or one is familiar with digital circuit design, HDL design, and Python and willing to jump in head first!
The circuit that will be described here is a simple LED control circuit. The module we want to define will strobe the LEDs on an FPGA development board. If you are familiar with the 80s pop-icon David Hasselhoff's Pontiac Trans Am (or the recent version of KnightRider) this might look familiar.
To implement the design we are going to define the behavior of the circuit in MyHDL. We want to describe the behavior to strobe the LEDs back and forth at a constant rate. We will outline the main components that need to be described.
On the development boards we have a clock. This clock will usually run at some 10s of mega-hertz (MHz). On the SX1 board the main clock is 48MHz, ufo400 48MHz, the Nexsys2 50MHz, and the DE2 50MHz. The clock is the only input to our circuit. Based on this single input we will describe the behavior to create this strobe effect. The strobe will not operate at the frequency of the clock, the LEDs will shift at some rate much slower than the circuit clock. One of the components that needs to be described is a clock counter. A piece of logic that will count clock cycles and generate a pulse -much slower pulse- periodically. This will indicate when the LEDs should shift.
At this point we will take a slight detour and take a quick look at a MyHDL module. We will use the shift register as an example. Describing a shift register in MyHDL is straight-forward. We need to declare a signal of n bits. And use the shift operator. The following gives the anatomy of a MyHDL module and implements the shift register logic.
The above code snip will simply set the collection of flip-flops to 1 (0001b in the above example) and shift the 1 to the left 1 bit on each clock cycle.
I did not implement a self checking testbench in the above example but I will below for the complete example.
The previous section was a short introduction to MyHDL modules, that is, what is involved to describe a hardware block using MyHDL/Python. We want to continue on with our basic design example. We are defining a digital hardware block that will "strobe" a bank of LEDs. The digital hardware will turn an LED on for a period of time and then move to the next LED. A strobe is defined as the "ON" LED moving left or right at a defined rate.
The above, each line, is a snapshot in time. The on LED will move one to the left or right. When the on LED is the most left or right the direction will change. The dummy LEDs are used so no LEDs are on when the LED goes off the end (the on is a dummy bit). The number of dummies are the delay that will occur (x2) at each end. In the above example 4 dummy bits are defined and the LEDs are on for .3 seconds. The off delay will be 2*4*.3 = 2.4 seconds on each end.
At this point we have enough description of our design to capture important design parameters.
- Frequency of the input clock
- The rate the LEDs strobe
- The number of LEDs in the LED bank (number of LEDs on the hardware development board)
- The number of dummy bits (delay on the ends)
The above defines the parameters to our module and the following is the module definition using the design parameters.
clk, # input : sync clock
srst, # input : sync reset
led, # output : to IO ports, LED drivers
CLK_FREQ = 48e6, # clock frequency
LED_RATE = 333e-3, # strobe rate of 333ms
NUM_DUMB = 4 # the number of dummy bits on each side
From the above definition two inputs are defined, clk and srst. Also the LED bit-vector output. Finally, the parameters for the module. We have described the functionality, ports, parameters to the design. Now lets look at testing the design.
One of the big benefits of using Python/MyHDL as the HDL is that all the tools of the Python language are available for verification. We are going to define a test before we actually code up the design. The tests are basic, verify that the logic moves the "ON" LED to the right or left. The test will monitor the LED port and verify that the LED is shifting. The following code-snip shows the generator function to verify the LED movement and configured delay.
The above will monitor for one of the LEDs to be "ON". When one of the ends is on it will determine the direction and keep track of the time (ticks) between the current led being on and the next on.
The complete test code-listing is here. An object is used to wrap the design under test (DUT) and provide some common functions, e.g. clock generation. The object will take the same parameters as the design (clock frequency, led rate, number of leds, number of blank leds). The object will have a method that returns the generators needs to run the simulation, this includes the main design generator
The code referenced is the simulation testbench. This will instantiate the design and verify that the LED is shifting back and forth. The testbench uses a generic template so that it can be used with the py.test unit test framework. The instantiation of the device under test (DUT) is wrapped in an object so each test can share (not repeat) the instantiation code. Also the portion of the code that verifies the LED and count is wrapped in a generator, this way different tests (configurations) can utilize the same functionality. In other words, additional tests can easily be added.
Also, notice in the test_random it includes constraint random testing. Python is a full-blown modern programming language and, essentially, is unlimited in the tools available for verification.
At this point if we copy the module def to a file called stroby.py (use pass in the body for now) and copy the test functions to test_stropy.py and include the import stroby at the top of test_stropy.py we can run py.test and it should fail. If the test does not fail we have a problem. Next we will fill in the logic for the design.
To describe our functionally we need our storage elements that we will call led_bit_mem. We also need a counter to divide our FPGA clock down and generate an event to shift. Basically, we need to describe a counter and a shifter with some states (shift left, shift right, change direction).
Below is the complete code listing for our behavioral model.
Now we have a couple other tasks to complete before we can download the design to the FPGA development boards.
- Convert the design to Verilog/VHDL
- Run the FPGA vendor tool chain (synthesis, PaR, bit-stream generation)
- Download the design to the FPGA development board
Each of these steps can be run by the stroby_run_tools.py script. This script will convert the design to HDL. And using the Guenter Dannoritzer's Xilinx scripts running synthesis, mapping, place and route, and bit file generation is all automated. This was only tested on a Linux machine with Xilinx ISE 13.2.
We are not going to specifically review how to use the vendor FPGA tools in this tutorial. If you are unfamiliar with the FPGA vendor tools the following link might be useful.
Project for each of the development boards can be found here.
Downloading the design will depend on the board and software tools used. The USBP and SX1 have separate software programs to load the bit-files. The nexsys2 and DE2 can be programmed with the vendor design software.
This was an introductory tutorial to use MyHDL as the design language for FPGA designs. Questions on this tutorial can be submitted in the comments section of this blog post. As mentioned the full source code can be found in the BitBucket Repository.
If you have any questions or issues feel free to leave a comment in the "comment" section below.
Add a Comment