In this tutorial we will see how to design a VHDL block. We will start with a very simple block and we will gradually add features to it. We will also simulate it and test its output with Matlab. Over the process we will see:
- How to start a design with a simple block and gradually add features and improvements
- How to add a test bench (for simulation)
- Adding parameters to the VHDL block
- Saving the block data output to files (from simulation)
- Exporting the files to Matlab in order to:
- Verify the results (Formal testing), and
- Analyze the results (in this case, using FFT)
For this tutorial it is assumed that you already have basic knowledge of the VHDL language and know how to use simulation tools (Modelsim will be used, but you can easily adapt the tutorial to other tools you may be familiar with).
Chapter 1 – Initial implementation
We are going to generate random numbers by Hardware. One popular way of generating pseudo-random numbers in HW is by means of an LFSR. LFSR stands for Linear-Feedback Shift Register.
The input bit to the shift register of the LFSR is a linear function of its previous value. The theory used to generate these sequences is based on linear algebra, where the register is interpreted as a polynomial. Each bit in the register is the coefficient of order ‘n’ of such a polynomial.
A register of length n can generate a pseudo-random sequence of maximum length 2[SUP]n[/SUP]-1. There are ‘recipes’ for the linear feedback function needed to generate maximum length sequences for any register length. See the references at the end of the article for more details.
So let’s see our first version of a pseudo-random generator written in VHDL.
For this first example, the polynomial order is very low, i.e. 3 (the shift register has 4 bits), which generates an optimum sequence consisting of 15 values. When we simulate the LFSR, if we keep running the simulation, these 15-values pseudo-random sequence will repeat indefinitely.
That is the reason that these sequences are called pseudo-random. They have a certain variability, but on the other hand, they are repetitive, and even if they are not a trivial sequence, they always will be the same sequence. After the number ‘3’ in this sequence, we will always get the number ‘7’. Of course a real random number does not behave in this way. But we will see later that even with this limitation, pseudo-number sequences can approximate quite well the behavior of white noise.
entity lfsr1 is
reset : in std_logic;
clk : in std_logic;
count : out std_logic_vector (14 downto 0) — lfsr output
architecture rtl of lfsr1 is
signal count_i : std_logic_vector (14 downto 0);
signal feedback : std_logic;
feedback <= not(count_i(14) xor count_i(13)); — LFSR size 4
process (reset, clk)
if (reset = ‘1’) then
elsif (rising_edge(clk)) then
count_i <= count_i(13 downto 0) & feedback;
count <= count_i;
Early VHDL versions didn’t support reading back outputs, that’s why I use count_i as a working signal, which at the end of the block is copied to the output count.
I always use this convention (suffix “_i” for internal signals) and you may want to adopt these and other conventions (like using the ‘_n’ suffix for active low signals) for code clarity and standardization.
The process implements a shift register. The feedback input to the shift register is a linear combination of some of its own bits.
Chapter 2 – Adding a test-bench
Now let’s examine the test-bench for the LFSR we have just created:
entity tb_lfsr1 is
architecture test of tb_lfsr1 is
constant PERIOD : time := 20 ns;
signal clk : std_logic := ‘0’;
signal reset : std_logic := ‘1’;
signal count : std_logic_vector (14 downto 0);
signal endSim : boolean := false;
component lfsr1 is
reset : in std_logic;
clk : in std_logic;
count : out std_logic_vector (14 downto 0)
clk <= not clk after PERIOD/2;
reset <= '0' after PERIOD*10;
endSim <= true after PERIOD*8000;
— End the simulation
if (endSim) then
report “End of simulation.”
wait until (clk = ‘1’);
lfrs1_inst : lfsr1
port map (
clk => clk,
reset => reset,
count => count
A test-bench is always an entity with no ports, that instantiates the device under test (DUT) as a component. The test-bench has signals that are used to exercise the block under test:
- A 50MHz (20 nsec period) clock.
- The reset signal which is asserted at the beginning of the test and de-asserted after some time (PERIOD*10).
This block is so simple that it is enough to provide a clock and de-assert reset to get it going.
The process checks the endsimsignal and stops the simulation after some time. In this way, the simulation can be run with the run -all command and will stop by itself.
Let’s see two screenshots of the simulation:
The signal looks (remotely) as a noise signal. It doesn’t look so well since the sequence we used, of only fifteen steps, is very short. We can see that the signal repeats itself each 15 clock cycles. On next entries of this tutorial we will see how to improve the signal.
On the following waveform we can see with more clarity a single cycle with all the 15 values of the output signal:
On the following chapters we will improve this basic code, export the output data of the simulation to files, and analyze this output data with Matlab. See you again!
LFSR design – Xilinx application note
Pseudo random generator tutorial part 2
Pseudo random generator tutorial part 3
My blog:FPGA Site
P.S. The source files are attached as .txt files. Rename the suffix as .vhd to synthesize or simulate.