cmod-s7-verilog-examples
cmod-s7-verilog-examples
Search Translate
FPGA Group
1 Introduction
2 The plan
4 The Projects
4.1 Hello FPGA
4.2 Button powered LEDs
4.3 Counting/Blinking LEDs
4.4 Debouncing
4.5 Vector display graphics
5 Final words
6 References
1 Introduction
Lots of FPGAs have been offered for roadtesting, but I never applied to any because I felt intimidated by the
complexity of the FPGAs and was not sure I would be able to properly roadtest them in a 2 months period. Luckily for
me the E14 team gave me the opportunity to play with a Digilent Cmod S7 and blog about my experience.
Even though many FPGA boards have been given to members of the E14 community, I have seen very little content
on how to program these boards through hardware description languages (HDLs). As I have no practical experience
with FPGAs, I'll start my journey into learning how to program these devices from scratch. Hopefully other members of
the community will find this blog interesting and can learn a few things on how to program these devices using a HDL.
2 The plan
My plan is to learn as much as possible on how to program these board through multiple small projects. There are
different ways to program FPGAs such as VHDL, Verilog, visual programming, high level synthesis (HLS) and softcore
programming among others, but here I will mostly focus on the Verilog HDL. There are many good introductory FPGA
articles on the net, so I'll just leave the links at the bottom, and completely skip the basic theory on how FPGAs
operate. I also won't post hundreds of screenshots of how to install Vivado or create a project, it isn't hard and there
are already many posts on E14 that show how to do it. Let's roll!
1 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
3 The board
The Cmod S7 is a Spartan 7th generation FPGA, which is the latest Xilinx FPGA generation, and only one that works
with Vivado, their latest IDE. There are different families of FPGAs in the 7th generation, Spartan FPGAs are the entry
level ones. The board is very small and lean, besides DIP pins and a Pmod interface, it is connected to 4 green LEDs,
1 RGB LED, 2 buttons, SPI Flash memory, an FTDI FT2232H USB-UART bridge, a 12 Mhz crystal oscillator and an
LTC3569 triple output buck regulator (more details can be found in Digilent's page).
4 The Projects
Powering up an LED is probably the simplest thing that can be done with an FPGA. To power up an LED I first need to
select in Vivado the target FPGA chip model from a list and then create two files, a "constraints" file that describes
how the pins of the board are connected to the FPGA , and the Verilog file. Before editing the constraints file I need to
know how the FPGA pins are wired to the LEDs and buttons, so I download the board schematic from Digilent's board
page:
The wiring is defined through Tcl commands in an "XDC" constraints file. For my "Hello FPGA" I just need to write a
single line:
This tells Vivado that the pin "E2" uses 3.3V and that it will be referred as "led" in the Verilog file. The Verilog file is
also very compact:
2 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
Here I defined a module called "Hello" (be aware that his is not the equivalent of function of a typical programming
language) which outputs to the "led" wire (already defined in the constraints file as being pin E2). Within the module I
set the wire to 1 (3.3 V), and the result of the design is:
We can see 4 glowing LEDs in the image, the red (power) and orange (FPGA programming done) are not user
controlled, but LED0 (RGB) and LED1 are. You may be wondering why LED0 is on when I just set LED1 (led) to 1 in
the Verilog code; a quick look into how LEDs are wired to the FPGA pins will probably help you figuring that out.
Unassigned pins are pulled-down (the default behaviour for all pins can be changed in Vivado), and the RGB LED is
turned on by setting each of the component pins to 0. To turn the RGB LED off I need to slightly modify the design:
I added a 3 bit vector wire for the RGB LED. By setting rgb to 3'b111 (3 bits binary 111) I effectively turned off all the
RGB components of the LED:
3 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
Vivado allows us to see the output schematic of our design, which in this case isn't particularly interesting:
Enough of this boring design, let's move to something more interesting and interactive.
A very simple modification to previous code allows us to control the LEDs through button presses:
4 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
The Verilog code uses the "?:" ternary operator to set the state of the LED pins. When BTN0 is pressed, the red
component of the RGB LED (rgb[2]), LED1 (led[0]) and LED2 (led[1]) are powered. When BTN1 is pressed, the
green component of the RGB LED (rgb[1]) , LED3 (led[2]) and LED4 (led[3]) are powered. Pressing both buttons at
the same time powers red and green components and all 4 green LEDs.
When not pressed, button pins are set to 0, when pressed, to 1. Green LED pins take the same value than the button
pins and we can see a direct connection between them. The RGB LED pins work differently, they require a NOT
boolean operator, in other words, when a button pin is set 1, an RGB pin is set to 0, and vice versa.The schematic
shows 2 LUTs (LookUp Tables) between input and output buffers, which in this design are configured to operate as
NOT boolean operators. LUTs of course can be configured to perform any other kind of boolean operations, and they
are the way FPGAs usually handle combinational logic.
5 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
Led Buttons
These simple examples don't use the clock signal, but as we will soon see, more interesting designs require the use of
the clock signal.
Now that you know the basics of how to write your own constraints file based on the schematics of the board, I'll tell
you the truth: Digilent already provides a constraints file for each of its boards where you just have to uncomment the
pins that you require for your design. Why didn't I introduce Digilents constraint file right from the start? Well, if I did
you probably wouldn't know how to write your own constraints files when there are none available, for instance if you
decide to use a custom-made FPGA board or if you decide to design your own board.
In previous projects the output of the FPGA depended solely on its current input signals, this is called combinational
logic, and the output signal is the result of of boolean operations applied to the current input signal. Combinational
logic doesn't allow the use of memory and makes it impossible to produce an output that depends on past signals. To
use memory and be able to produce an output that depends on current and/or past signals we need sequential logic,
and this requires a clock signal.
The Cmod S7 board comes with a 12 MHz clock, but we are not really stuck to that clock frequency, it is possible to
use the mixed-mode clock manager (MMCM) of the FPGA to divide or multiply the clock frequency as needed. To
show how the clock can be used I wrote a simple sequential logic program that counts from 0 to 15 using the 4 green
LEDs. Again, this would not have been possible with combinational logic only, as I would not be able to save and
update states (ie. increment the LED counter).
Since the clock runs at 12 MHz I can’t just update the LED binary counter once per cycle. To slow down the LED
counter, I introduced a delay counter, which increments the LED counter once every 1,200,000 delay counts. This
result in the LED counter to update once every 0.1 s. This design includes many new concepts, let’s see:
6 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
07.
08. reg [$clog2(`DELAY) - 1:0] counter = 0;
09.
10. always @(posedge clk)
11. begin
12. if (counter == `DELAY - 1)
13. begin
14. led <= led + 1;
15. counter <= 0;
16. end
17. else
18. counter <= counter + 1;
19. end
20. endmodule
`define is analog to the C/C++ #define, it’s a macro, and `DELAY gets replaced by 1_200_000. The underscores in-
between are separators and only have meaning to the designer, the synthesizer completely ignores them.
reg variables can store values while wire variables can’t. reg variables are usually implemented as flip-flops, where
for each bit of the reg one flip-flop is required. In some situations, the synthesizer may treat a reg as a wire, as it
occurs in this case with the rgb reg (see the next schematic figure); the synthesizer figured out that value of rgb
doesn’t change and no flip-flop is required, so it just wires each bit to whatever values I initialized the reg to.
$clog2() returns the ceiling of log base 2, so I used it to calculate the number of bits that I need for the delay counter
(21 bits).
The always @(posedge clk) tells the synthesizer to execute the operations within the block once every rising edge of
the clk wire. There two type of assignments that can be used inside of an always block, the blocking (=) and the non-
blocking (<=) assignments. Blocking assignments are guaranteed execute in the same order than the source code
lines, while non-blocking assignments occur in parallel.
if is similar to the C/C++ if, and begin and end are similar to { and } of C/C++.
Led Counter
7 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
Very intimidating, isn't it? I’ll give you an intuition on how it works. We got 3 new blocks here, the BUFG, the FDRE
and the CARRY4. The BUFG block is a high-fanout buffer that connects the signal to global routing resources. This is
especially useful for clock signals as they must be fed into many other blocks with minimum delay between them. The
FDRE block is a D flip-flop with clock enable and synchronous reset, its output is shown in the following table:
The flip-flop outputs its current state all the time to the Q pin. When reset (R) is set to 1, the state of the flip-flop is set
to 0 at the rising edge of the clock (C). If clock enable (CE) is set to 1, the flip-flop state is set at the rising edge of the
clock (C) to the data signal (D). The CARRY4 is a Fast carry logic with look ahead, and here is used in conjunction
with FDRE blocks to implement a 21 bit delay counter.
Let’s take a closer look to how the design works.The clock signal feeds the clock input (C) of all the FDRE blocks of
the schematic directly. The delay counter is made of 21 FDRE, 1 LUT1 and 5 CARRY4 blocks. The single LUT1 and
CARRY4 blocks are responsible of incrementing the values of the counter. 4 LUT4 and 2 LUT5 are used to sample all
the bits of the counter and compare them to 1,199,999. When the delay counter reaches this number, the
counter[20]_i_1 LUT5 outputs a 1 and this has 2 effects. First it sends a reset signal (R) to the delay counter FDRE
blocks, which causes them to reset to 0 at the next clock (C) rising edge; and second, it sets the clock enable (CE) of
the 4 LED counter FDRE blocks to 1, effectively increasing in this way the LED counter to 1 during the clock rising
edge (C). Notice that the LED counter is made of 4 FDRE, 1 LUT1, 1 LUT2, 1 LUT3 and 1 LUT4. These LUTs are
configured to increment the counter, during the clock (C) rising edge only when clock enable (CE) has been set to 1
(once every 1,200,000 clock ticks).
8 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
If such a simple piece of Verilog code is synthesized into such large schematic, just imagine what kind of schematic
the synthesizer would generate from higher complexity designs. Most of the times we don’t really need to know what
kind of schematic is synthesized, but its good to have an intuition of how HDL code is converted into a circuit.
Learning how each of these FPGA primitives operate is also useful for when they need to be use directly from an
HDL. These primitives are presented as modules in Verilog and can be used like any other Verilog module. The
drawback of using these primitives is that they are dependent of each specific FPGA and using them could make the
code non-portable.
Let’s suppose that our Verilog design doesn’t behave as we want it to behave, what can we do? Manually checking
the schematic is very time consuming and in many cases not a practical solution, because of the high number of
primitives and states. An alternative is to simulate the design, simulations allow us to see how signals change with
time, which can be very helpful in figuring out what went wrong in a design.
Let’s see how Vivado’s built-in simulator simulates the module if I set the DELAY macro to 3 (otherwise I would not be
able to show in a single image the coordination of all the signals)!
As expected, the clk clock signal is the fastest changing signal. At every clk rising edge counter increases 1 until it
reaches 2, at which point it resets to 0 and led increases 1. The moment led reaches 15 it wraps around and the
whole process repeats.
And just for fun, lets see the schematic of the design:
9 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
Even though the design looks much simpler than the previous one, it works in a very similar way except for 2 relevant
differences. First, the circuit doesn’t use CARRY4 but LUT2 instead in the delay counter, and second, it doesn’t reset
the delay counter through the FDRE reset (R); the counter is reset through the LUT2 (who also are in charge of
increment the counter).
4.4 Debouncing
When a switch is toggled, contacts have to physically move to settle to their new position. This does not occur
immediately, and before contacts settle to their final position, they bounce, causing the circuit to open and close
several times. If you only care about the current status of a button, like in project 4.2, you can just ignore the bouncing
effect, as it occurs too fast to be visible to the eye. But if you care about button pressing or releasing events, then you
may require debouncing, or otherwise you could end up detecting multiple "fake events".
There are many ways to do debouncing, I decided to solve the bouncing problem like this: If the button changes its
state, I generate a button "state change" event and reset a timer, and unless a defined amount of time has passed
since last reset, any new event gets ignored as its likely caused by bouncing. Here is the code:
10 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
In contrast to previous projects, we now defined 3 modules. Modules are in some way analog to classes of object
oriented programming languages, and except for the top module, they have to be instantiated to be used. Instantiation
syntax is again similar to the C++ syntax, the "Top" module instantiates 2 Debouncer and 2 LedState modules. To
connect them I created 2 2-bit wires (event0 and event1) which are used to communicate the switch events from
each Debouncer instance to their respective LedState instance.
Each of the 2 Debouncer instances debounces a single button as defined in the instantiation. The debouncer outputs
a 0 when no event occurs, a 1 when the button is pressed and a 2 when the button is released. Parameters are
constants typically used to specify the width of variables and time delays. Parameters are evaluated during synthesis,
and can't be wire or reg data types. I defined waitTime as a parameter that stores the amount of time in seconds that
have to pass before a new button event can be generated. I made the default value of the parameter 0.05, but this
value is overridden to 0.1 during the instantiation of the module. Its important to note that Verilog synthesizable code
does not natively support real numbers. To overcome that limitation I defined the localparam waitTicks and set its
value to the waitTime converted from seconds to clock ticks. This was done by multiplying waitTime by
`FREQUENCY, and then using the $rtoi() function to convert the result from real to integer. localparam is similar to
parameter, its only difference is that its value can't be overridden at the instantiation.
The LedState instances receive events from Debouncer instances and set the state of the LEDs depending on the
received button press events.
Debouncer
11 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
The schematic is very lean, because its encapsulating the content of the instances. Vivado allows you see the
contents of the instance by either expanding it by pressing the "+" button at the top left corner of the block, or opening
its content by double clicking it. As you can imagine, the Debouncer instances contain many cells and nets, so I'm not
going to show them. One interesting aspect of the synthesized schematic is that the Debouncer instances connect
directly to the LED wires and also appear to have one extra pin, caused by synthesizer optimizations. Vivado can also
display the pre-optimized design using generic symbols that are independent of the target FPGA device:
Now this schematic is almost a perfect graphical representation of the Top module, Debouncer has only 3 ports now
and the port names are identical to the names in the source code.
Having covered most of the basics, it's time to move to something more interesting and challenging: Vector Display
GPU Project
12 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
5 Final words
In less than a month without having any previous experience with FPGAs I got from roughly knowing basic theory of
how they work, to getting a decent mental model of how to implement different algorithms in the FPGA. In this blog I
skipped many key aspects of FPGAs, such as test benches, metastability, setup and hold time, blocking and non-
blocking assignments, among others, because they would have taken me a great amount of time to explain well, and
also because they aren't that interesting to FPGA beginners. Many of the presented projects were explained in very
general terms, but I still expect the explanations to be of enough depth to give the beginner a good intuition of how to
program FPGAs. If I managed to motivate any reader to get into FPGA programming, I'll consider this post a success!
6 References
Programmable Devices I: Programmable Logic
Programmable Devices II: Programmable SoCs
Programmable Devices III: FPGA / Programmable SoC Programming Languages
Dave Jones FPGA introduction
Digilent Cmod S7 Reference manual
Digilent Cmod S7 Schematic
Verilog tutorial (verilog.com)
Verilog, Formal Verification and Verilator Beginner's Tutorial (Gisselquist Technology)
(3 ratings)
7 Comments
13 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
Good start.
A great and detailed write up which I really enyoyed reading, thank you. Blogs like yours that explain the
concepts and steps required from the start are invaluable IMO to helping others get an understanding of
FPGAs...so much so that I'm bookmarking it
I'm glad you liked it, is there anything special you would like to see?
That was a really nice review. You seem to have really got to grips with FPGAs. In my recent newbie
experience they will still be some WTF moments to come as you progress, but you certainly have the
groundwork covered.
Miguel,
I'd like to thank you for putting in the effort for creating this great blog.
Randall
I'm currently working on the Vector Display GPU Project project, the azure sphere project, and I'm
also writing a roadtest application, so I'm too busy at this moment to also test a Cmod S6. The S7 and
14 of 15 09/11/2019, 13:13
Learning Verilog with the Digilent Cmod S7 | e... https://www.element14.com/community/groups/...
S6 appear to be too similar, with the generation of the FPGA and the IDE being their main difference,
so someone else would probably benefit more from the S6 than me.
Thanks again!
Miguel,
I sensed that you were busy right now. That's fine. Good luck on winning an Azure prize. Some
good ones!
15 of 15 09/11/2019, 13:13