Você está na página 1de 84

A Practical Introduction to Verilog

using Mojo V3

By Yury Magda

Copyright © 2017 by Yury Magda. All rights reserved.

The programs, examples, and applications presented in this book have


been included for their instructional value. The author offers no
warranty implied or express, including but not limited to implied
warranties of fitness or merchantability for any particular purpose and
do not accept any liability for any loss or damage arising from the use of
any information in this book, or any error or omission in such
information, or any incorrect use of these programs, procedures, and
applications.
No part of this publication may be reproduced, stored in a retrieval
system, or transmitted in any form or by any means, electronic,
mechanical, photocopying, recording, or otherwise, without the prior
written permission of the author.
Contents
Introduction
Disclaimer
Coding Styles
Required Software
Using the Mojo base project
Using the Mojo V3 on-board peripherals
The first design with Verilog
Designing frequency dividers: example 1
Designing frequency dividers: example 2
Designing multiplexers: example 1
Designing multiplexers: example 2
Designing decoders: example 1
Designing decoders: example 2
Designing comparators
Designing counters
Designing shift registers
Designing Pulse Width Modulators: example 1
Designing Pulse Width Modulators: example 2
Designing Pulse Width Modulators: example 3
Programming State Machines with Verilog
Example 1
Example 2
Example 3
Introduction
This book is intended as a highly practical guide for those who want to learn designing digital circuits
in Verilog HDL using a popular Mojo V3 FPGA board (Fig.1).

Fig.1

The Mojo V3 is designed to make digital design easy and cost effective for anyone who is just getting
started.
The detail description of the Mojo V3 board is available at
https://embeddedmicro.com/products/mojo-v3.html. The board features include:
Spartan 6 XC6SLX9 FPGA;
84 digital I/O pins;
8 analog inputs;
8 general purpose LEDs;
1 reset button;
1 LED that indicates when the FPGA is correctly configured;
On board DC voltage regulator capable of handling 4.8V – 12V input voltage. The optimum
input for the board is 5V.
A microcontroller (ATmega32U4) used for configuring the FPGA, USB communications and
reading the analog pins;
On board flash memory to store the FPGA configuration file.

This guide aims to get the readers familiar with basics of Verilog through designing various digital
circuits using the Mojo V3. Aa a development tool for creating and compiling designs, programming
the FPGA, the Xilinx ISE Design Suite 14.7 WebPack Edition running in Windows 10 was used.
Each design is accompanied by a brief description which helps to make things clear and allows the
readers to easily improve the design.
Disclaimer
The design techniques described in this book have been tested on the Mojo V3 FPGA development
board without damage of the equipment. I will not accept any responsibility for damages of any kind
due to actions taken by you after reading this book.
Coding Styles
All examples described in this book are developed in Verilog. Verilog HDL allows to implement a
design in several coding styles. Generally, a Verilog coding style may be based on either of four
different levels of abstraction: behavioral, dataflow, structural and switch levels.

In this guide, we will create digital circuits using the Verilog coding style that is based on the
behavioral level of abstraction. This style provides the following features:
A module can be implemented in terms of the desired design algorithm without knowing
hardware implementation details.
It allows to specify a digital circuit in terms of its expected behavior.
It is the best approach to a natural language description of the circuit functionality.

All designs described in this book use Verilog 2001, 2005 syntax.
Required Software

Before we start off our designs, we should install the Mojo Loader and free
Xilinx ISE Design Suite 14.7 WebPack Edition.

The Mojo Loader utility is required if you need to load a .bin file created outside the Xilinx IDE. In
our case, this program will be used to load the .bin files created with ISE to the Mojo.

You should download the proper version of the loader for your operating system (in this guide, there
was used a version for Windows). The latest version of Mojo Loader to download is
1.3.0 (compatible only with firmware 1.2.0, the Arduino compatible firmware, and above).
This version uses the serial port library JSSC instead of RXTX used in older versions. More details
are available on https://embeddedmicro.com/tutorials/mojo-software-and-updates/installing-mojo-
loader.
Using the Mojo base project
In this book, designing digital circuits with Verilog will be based on a Mojo base project that should
be downloaded from https://github.com/embmicro/mojo-base-project/archive/master.zip.
Alternatively, you can check it out at https://github.com/embmicro/mojo-base-project. The Mojo base
project is a good starting point for any Verilog project created for the Mojo V3 board.

The Mojo base project will be used as a template for all designs described in this guide. In each new
project, we will make several modifications to the template, to adapt the Mojo base project to our
design. For convenience, you can make an empty directory for each Verilog project and then extract
the .zip file with a basic project to this directory.
The file structure of the Mojo base project includes the following:
Mojo-Base – the design name;
ipcore_dir – where IP cores that you generate will go;
iseconfig – used by ISE;
src – where all the source files you write are located;
syn – the working directory for ISE;
Mojo-Base.xise – the ISE project file.

When designing our circuits, we will need to modify only two files from the Mojo base project,
mojo_top.v and mojo.ucf.
Using the Mojo V3 on-board peripherals
Our designs will be built around the Mojo on-board peripherals, without using any additional shields
and/or boards. Many designs use a digital input signal that will be taken from the on-board button
labeled “Reset” that is connected as shown in Fig.2.

Fig.2

The button when released provides a high level (log.”1”) on the net L65N_2 associated with the pin
P38 (not shown here) of the FPGA. When pressed, the button provides a low level (log.”0”) on the
pin P38.

To provide LED visualization of the operations in circuits, we will use the Mojo V3 on-board LEDs
connected as shown in Fig.3.

Fig.3

The signal names and pin assignments for the on-board LEDs are detailed in the table below.

Label Network FPGA Pin Alias for Verilog


code
LED2 L34P_0 P134 led[0]
LED3 L34N_0 P133 led[1]
LED4 L35P_0 P132 led[2]
LED5 L35N_0 P131 led[3]
LED6 L36P_0 P127 led[4]
LED7 L36N_0 P126 led[5]
LED8 L37P_0 P124 led[6]
LED9 L37N_0 P123 led[7]

We also need a square wave oscillator (clock) for clocking our circuits. The 50 MHz clocking signal
(labeled CLK) can be taken from the pin 56 of the FPGA (Fig.4).

Fig.4

In order to observe in details how our circuits operate, LED visualization should be implemented at
low speed, with frequencies much less than 50 MHz. For that reason, most circuits in this guide will
use a frequency divider that divides the 50 MHz clocking signal to a few Hz thus providing low-
frequency clocking signal to the rest of a circuit.
Now we know all what is needed to start off our designs. Let’s go to the first project.
The first design with Verilog
In this section, we will design a very simple combinational circuit (Fig.5) using
Xilinx ISE Design Suite. We will pass through all stages required for implementing our circuit in the
FPGA. A similar sequence will be used when designing all circuits described in this guide.

Fig.5

This circuit provides the double inversion of the input signal rst fed from the “Reset” button. The
output led[0] of the NOT gate gate1 drives the on-board LED “LED2” (see Fig.3), while the output
led[1] of the NOT gate gate2 drives the LED “LED3”.
To implement this circuit in the FPGA, in the ISE Design Suite window select and click → Open
Project… (Fig.6).

Fig.6

In the file dialog window, select Mojo-Base.xise from the directory where the Mojo base project
resides (Fig.7).
Fig.7

After the project has been opened, we should see the mojo-top module (mojo_top.v) under the
hierarchy panel on the left side (Fig.8). Double-clicking on the mojo_top.v opens this file thus
allowing us to see its Verilog code.

Fig.8

If, for some reason, the mojo_top.v doesn’t appear as a top module, you should change this manually.
To do that, select mojo_top.v, then select and click Source → Set As Top Module (Fig.9). This way
we define the mojo_top.v as the top module.
Fig.9

The contents of the original mojo_top.v file is shown below (Listing 1).

Listing 1.

1. module mojo_top(
2. // 50MHz clock input
3. input clk,
4. // Input from reset button (active low)
5. input rst_n,
6. // cclk input from AVR, high when AVR is ready
7. input cclk,
8. // Outputs to the 8 onboard LEDs
9. output [7:0] led,
10. // AVR SPI connections
11. output spi_miso,
12. input spi_ss,
13. input spi_mosi,
14. input spi_sck,
15. // AVR ADC channel select
16. output [3:0] spi_channel,
17. // Serial connections
18. input avr_tx, // AVR Tx => FPGA Rx
19. output avr_rx, // AVR Rx => FPGA Tx
20. input avr_rx_busy // AVR Rx buffer full
21. );

22. wire rst = ~rst_n; // make reset active high

23. // these signals should be high-z when not used


24. assign spi_miso = 1'bz;
25. assign avr_rx = 1'bz;
26. assign spi_channel = 4'bzzzz;

27. assign led = 8'b0;

28. endmodule

When designing digital circuits, we will add Verilog code after the line 26.
We will also need to change the contents of the mojo.ucf file – a User Constraint File (UCF) which
maps the NET names in Verilog code to the FPGA pin names. The contents of the original mojo.ucf
file is shown in Listing 2.

Listing 2.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk" TNM_NET = clk;
TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk" LOC = P56 | IOSTANDARD = LVTTL;
NET "rst_n" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;
NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;
NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

In this file, the lines that begin with a # are comment lines – they are not part of the configuration
information, they just describe what is going on.
There are a number of NET commands that define the links from the net name specified in the Verilog
code to the pin location (LOC) in the actual hardware. Finally, at the end of the lines for the
switches, there is a bar symbol followed by the word IOSTANDARD that determines the type of
logical levels for that pin.

In our first design, we should add a few lines at the end of the mojo_top.v file as is shown in Listing
3.

Listing 3.

1. module mojo_top(
2. // 50MHz clock input
3. input clk,
4. // Input from reset button (active low)
5. input rst_n,
6. // cclk input from AVR, high when AVR is ready
7. input cclk,
8. // Outputs to the 8 onboard LEDs
9. output [7:0] led,
10. // AVR SPI connections
11. output spi_miso,
12. input spi_ss,
13. input spi_mosi,
14. input spi_sck,
15. // AVR ADC channel select
16. output [3:0] spi_channel,
17. // Serial connections
18. input avr_tx, // AVR Tx => FPGA Rx
19. output avr_rx, // AVR Rx => FPGA Tx
20. input avr_rx_busy // AVR Rx buffer full
21. );

22. wire rst = ~rst_n; // make reset active high

23. // these signals should be high-z when not used


24. assign spi_miso = 1'bz;
25. assign avr_rx = 1'bz;
26. assign spi_channel = 4'bzzzz;
27. //------ Our code starts here ------

28. assign led[7:2] = 6'd0;


29. assign led[0] = rst ? 1'b0 : 1'b1;
30. assign led[1] = ~led[0];

31. endmodule

Here, our Verilog code begins after the line 28. The statement

assign led[7:2] = 6'd0;

drives the six most significant bits corresponding to the on-board LEDs OFF. This statement is
necessary because these nets are configured in the UCF file (mojo.ucf). Without this statement, the
compiler issues an error. In the following examples, we will modify the contents of the UCF file in
order to avoid such problems.
The sequence

assign led[0] = rst ? 1'b0 : 1'b1;


assign led[1] = ~led[0];

implements the circuit shown in Fig.5.


Note that the output led[0] / led[1] goes HIGH (log.”1”)/LOW (log.”0”) when the button “Reset” is
released. In that case, rst_n is brought HIGH and rst is brought LOW. Conversely, the output led[0] /
led[1] goes LOW/HIGH when the button “Reset” is pressed. In that case, rst_n is LOW and rst is
HIGH.

It is now time to synthesize the design and generate the programming file to be downloaded onto the
Mojo board. Select the mojo_top entry in the hierarchy, and a number of options will appear below
in the panel labeled Processes. In that panel, double-clicking on Generate Programming File
causes a spinning thing to appear and move through the different stages of those processes (Fig.10).
Fig.10

While generating the programming file, there will be warnings indicated by a little “!” in a yellow
triangle. If we scroll through the warnings, we will see that they are all caused by inputs and outputs
in our design not being used. Since that was intentional, we can ignore these.
If we didn't get any errors and the Generate Programming File stage succeeds, we can invoke the
Mojo Loader utility to load the bin file into the FPGA.

Once Mojo Loader (Fig.11) is opened, we should select the serial port associated with the Mojo V3
board. In my case, Windows 10 provided COM3 for the Mojo. It may take a while for Mojo Loader
to recognize the serial port so check the Serial Port dropdown again if you don't see the port listed.
Then click Open Bin File and navigate to the syn folder in the project folder where you should select
a mojo_top.bin file.

Fig.11

Clicking Load causes the binary file to be transferred to the Mojo.


Once it has been transferred, try pressing the reset button and observe how the indication of LEDs
changes.
The circuit shown in Fig.5 as well as other circuits can also be implemented using other approaches.
Below (Listing 4) is another implementation of this circuit.

Listing 4.

assign led[7:2] = 6'd0;


not gate1(led[0], rst);
not gate2(led[1], led[0]);

In this example, the structure of the circuit is specified by the list of Verilog built-in primitive gates
identified by a descriptive keyword (and, not, or). In our case, we use two not gates. The elements
of the list are referred to as instantiations of a gate, each of which is referred to as a gate instance.
Each gate instantiation consists of an optional name (gate1 and gate2, in our case) followed by the
gate output and inputs separated by commas and enclosed within parentheses. The output of a
primitive gate is always listed first (led[0] and led[1], in our case) followed by the inputs (rst,
led[0]).
The output of a primitive must be listed first, but the inputs and outputs of a module may be listed in
any order.
Designing frequency dividers: example 1
This design allows to build a frequency divider with the output frequency of 1 Hz. The input
frequency to the frequency divider is fed from the 50 MHz clock signal available on the pin P56 of
the FPGA. The circuit diagram of the frequency divider is shown in Fig.12.

Fig.12

To visualize the output signal, we will use the on-board LED (output led[0]) that will blink with a
frequency of 1 Hz. The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in
Listing 5.

Listing 5.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active high)
input en,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,

// AVR SPI connections


output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter maxDIV = 25000000; // 2 Hz /2

reg qdiv; // freq. divider output


integer cntdiv; // counter

initial
begin
qdiv <= 1'b0;
led <= 8'd0;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the freq. divider of 1Hz

always @(posedge clk_50M)


if (en) begin
if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else begin
cntdiv = 0;
qdiv <= !qdiv;
end
end

// Toggling LED

always @(posedge qdiv)


led[0] <= !led[0];

endmodule

In this code, the always-block

always @(posedge clk_50M)

implements the frequency divider whose output frequency is determined by the parameter maxDIV.
The en input enables/disables the counter (variable cntdiv) of the frequency divider. The internal
clock qdiv toggles the LED within an always-block
always @(posedge qdiv)

The contents of the UCF (mojo.ucf) is shown in Listing 6.

Listing 6.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "en" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold.
Designing frequency dividers: example 2
This is the modified version of the previous example. With this circuit, we get three different
frequencies (1, 5 and 10 Hz) at three outputs led[0] – led[2]. The circuit diagram of the modified
frequency divider is shown in Fig.13.

Fig.13

The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in Listing 7.

Listing 7.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active high)
input en,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,

// AVR SPI connections


output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter max1HZ = 25000000; // clock output = 1 Hz


parameter max5HZ = 5000000; // clock output = 5 Hz
parameter max10HZ = 2500000; // clock output = 10 Hz

reg [2:0] qdiv; // divider outputs


integer cntdiv0, cntdiv1, cntdiv2; // counters

initial
begin
qdiv <= 3'b0;
cntdiv0 = 0;
cntdiv1 = 0;
cntdiv2 = 0;
led <= 8'd0;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the freq. divider of 1Hz

always @(posedge clk_50M)


if (en) begin
if (cntdiv0 < max1HZ) cntdiv0 = cntdiv0 + 1;
else begin
cntdiv0 = 0;
qdiv[0] <= !qdiv[0];
end
end

// Implementation of the freq. divider of 5Hz

always @(posedge clk_50M)


if (en) begin
if (cntdiv1 < max5HZ) cntdiv1 = cntdiv1 + 1;
else begin
cntdiv1 = 0;
qdiv[1] <= !qdiv[1];
end
end
// Implementation of the freq. divider of 10Hz

always @(posedge clk_50M)


if (en) begin
if (cntdiv2 < max10HZ) cntdiv2 = cntdiv2 + 1;
else begin
cntdiv2 = 0;
qdiv[2] <= !qdiv[2];
end
end

// Toggling LEDs

always @(posedge qdiv[0])


led[0] <= !led[0];

always @(posedge qdiv[1])


led[1] <= !led[1];

always @(posedge qdiv[2])


led[2] <= !led[2];

endmodule

The contents of the UCF (mojo.ucf) is shown in Listing 8.

Listing 8.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "en" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes in introduced into the original mojo.ucf file are shown in bold.
Designing multiplexers: example 1
This design allows to implement the 2-to-1 multiplexer circuit (Fig.14).

Fig.14

In this circuit, the button “Reset” drives the input en of the multiplexer. If en is HIGH (log.”1”,
“Reset” is released), the data byte data2 will be passed to the output led[7:0]. If en is LOW
(log.”0”, “Reset” is pressed), data1 goes to the output led[7:0].

To model the behavior of this circuit in Verilog, we need to modify both mojo_top.v and mojo.ucf
files in the Mojo base project.
The Verilog code contained in the modified mojo_top.v file is shown in Listing 9.

Listing 9.

module mojo_top(
// 50MHz clock input
input clk,
// Input from reset button
input sel,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

integer data1, data2; // mux channels

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

initial
begin
data1 = 8'd129;
data2 = ~data1;
end;

assign led = sel ? data2 : data1;

endmodule

In this code, the multiplexer is implemented by the statement

assign led = sel ? data2 : data1;

The variables data1 and data2 may be assigned any suitable values.

We should also modify the UCF (mojo.ucf) as is shown in Listing 10.

Listing 10.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk" TNM_NET = clk;
TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk" LOC = P56 | IOSTANDARD = LVTTL;
NET "sel" LOC = P38 | IOSTANDARD = LVTTL;
NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold.
Designing multiplexers: example 2
In this design, we will implement the 2-to-1 multiplexer circuit capable of passing either 1 Hz or 5
Hz pulse train. Both clock sources are taken from the frequency dividers fed from the 50 MHz on-
board clock available on the pin P56 of the FPGA. Both signals, 1 Hz and 5 Hz, are fed to the inputs
of the multiplexer. The input channel is selected by the sel input driven by the button “Reset”.
The circuit diagram is shown in Fig.15

Fig.15

The Verilog code (contained in mojo_top.v) that models the behavior of this circuit is shown in
Listing 11.

Listing 11.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input sel,
// cclk input from AVR, high when AVR is ready
input cclk,
// Output to the onboard LED
output led0,

// AVR SPI connections


output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter max1HZ = 25000000; // div.1 output = 1 Hz


parameter max5HZ = 5000000; // div.2 output = 5 Hz

reg [1:0] qdiv; // divider output


integer cntdiv0, cntdiv1; // counters

initial
begin
qdiv <= 2'b00;
cntdiv0 = 0;
cntdiv1 = 0;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the 2-to-1 multiplexer

assign led0 = sel ? qdiv[0] : qdiv[1];

// Implementation of the freq. divider of 1Hz

always @(posedge clk_50M)


if (cntdiv0 < max1HZ) cntdiv0 = cntdiv0 + 1;
else begin
cntdiv0 = 0;
qdiv[0] <= !qdiv[0];
end

// Implementation of the freq. divider of 5Hz

always @(posedge clk_50M)


if (cntdiv1 < max5HZ) cntdiv1 = cntdiv1 + 1;
else begin
cntdiv1 = 0;
qdiv[1] <= !qdiv[1];
end

endmodule

The contents of the UCF (mojo.ucf) is shown in Listing 12.

Listing 12.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "sel" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led0" LOC = P134 | IOSTANDARD = LVTTL;


#NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
#NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
#NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
#NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
#NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
#NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
#NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;
The changes introduced into the original mojo.ucf file are shown in bold. To avoid the errors while
compiling the code, the lines with “led<>” were commented.
Designing decoders: example 1
This design implements the binary decoder with 3 inputs and 8 outputs. Its inputs represent a binary
number, which is decoded to assert the corresponding output
As is shown in the truth table below, only one of the outputs from Q0 – Q7 is asserted at a time, and
each output corresponds to one combination of the X0 – X2 inputs.

X0 X1 X2 Q0 Q1 Q2 Q3 Q4 Q5 Q6 Q7
0 0 0 1 0 0 0 0 0 0 0
1 0 0 0 1 0 0 0 0 0 0
0 1 0 0 0 1 0 0 0 0 0
1 1 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 1 0 0 0
1 0 1 0 0 0 0 0 1 0 0
0 1 1 0 0 0 0 0 0 1 0
1 1 1 0 0 0 0 0 0 0 1

Fig.16 depicts the 3-to-8 decoder circuit where the input sel is driven by the “Reset” button. A data
byte being taken from the integer array X[0:1] (see Verilog code below) forms the input X (not
defined in Verilog code) of the decoder. Depending of the state of the button “Reset”, either X[0] or
X[1] is fed to X.
The value on the input X drives a corresponding on-board LED (output led[7:0]) through the output
Q[7:0], so we can observe the state of the LEDs when “Reset” pressed/released.

Fig.16

The Verilog code (mojo_top.v) that models the behavior of the above circuit is shown in Listing 13.

Listing 13.

module mojo_top(
// Input from reset button
input sel,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

integer X[0:1];
wire [7:0] Q; // decoder outputs

initial
begin
X[0] = 7;
X[1] = 0;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

assign Q = sel ? 1'b1 << X[0]: 1'b1 << X[1];


assign led = Q;

endmodule

In this code, the sequence

assign Q = sel ? 1'b1 << X[0]: 1'b1 << X[1];


assign led = Q;

implements the decoder.


The contents of the UCF (mojo.ucf) is shown in Listing 14.

Listing 14.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


//NET "clk_50M" TNM_NET = clk_50M;
//TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


//NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "sel" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold. Since a clock signal isn’t
used in this circuit, the corresponding lines are commented.
Designing decoders: example 2
One more decoder circuit is shown in Fig.17. Here the data on the input X of the decoder are
incremented every 0.5 s at the rising edge of the internal clock clk. The on-board LEDs (led[7:0])
reflect the decoder output Q[7:0].

Fig.17

The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in Listing 15.

Listing 15.

module mojo_top(
// 50MHz clock input
input clk_50M,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

reg clk;
reg [7:0] Q;
integer X;

parameter maxCNT = 12500000; // output clk = 4 Hz / 2 = 2 Hz


integer cnt;

initial
begin
cnt = 0;
X = 0;
Q <= 8'd0;
led <= Q;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the decoder

always @(posedge clk)


begin
Q <= 8'd0;
Q <= 1 << X;
led <= Q;
if (X < 7) X = X + 1;
else X = 0;
end

// Implementation of the freq. divider 2 Hz

always @(posedge clk_50M)


if (cnt < maxCNT) cnt = cnt + 1;
else
begin
cnt = 0;
clk <= !clk;
end

endmodule

In this code, the always-block


always @(posedge clk_50M)

implements the frequency divider with an output frequency of 2 Hz (internal clock clk).

The coder is implemented within the block

always @(posedge clk)

Here, the variable X changes from 0 to 7 at each rising edge of clk, thus causing the outputs Q and led
to change accordingly.

The content of the UCF (mojo.ucf) is shown in Listing 16.

Listing 16.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;
The changes introduced into the original mojo.ucf file are shown in bold.
Designing comparators
A digital comparator circuit performs comparison of two digital numbers and, depending on the result
of comparison produces a 1-bit output signal. The output of a comparator may be triggered when a
first number is greater than second, when a first number is less than the second or when both numbers
are equal.
In the following design (Fig.18), the output signal on the output qcomp of the comparator goes HIGH
(log.”1”) when the data byte on the input A0 – A7 becomes equal to the predetermined data on B0 –
B7.

Fig.18

In this circuit, the on-board clock of 50 MHz feeds the counter that increments its value every 0.1 s
(10 Hz) while the input en remains HIGH (log.”1”). The data byte to the inputs A0 – A7 of the
comparator comes from the counter output q[7:0]. Initially, en is brought HIGH thus allowing to start
counting from 0 up to the value determined by the datacomp variable (171, in our example).
When the value of the data byte on A0 – A7 reaches datacomp, the qcomp output goes
HIGH(log.”1”) thus bringing the en input LOW (log.”0”). The low level on the en input disables
counting. To resume counting from 0, we should activate the rst inputs by pressing/releasing the
“Reset” button.
The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in Listing 17.
Listing 17.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input rst,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,

// AVR SPI connections


output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter maxDIV = 2500000; // 20 Hz / 2

reg clk; // internal clock


reg [7:0] q; // internal counter output
reg en; // enable/disable a counter;
reg qcomp; // comp. output = 1 if two bytes are equal, otherwise 0
integer datacomp; // data to compare;
integer cntdiv, cnt;

initial
begin
q <= 8'd0;
led <= q;
cnt = 0;
datacomp = 171;
qcomp <= 1'b0;
en <= !qcomp;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Enable/disable a counter

always @(qcomp)
en <= !qcomp;

// Implementation of the freq. divider of 10 Hz

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else
begin
cntdiv = 0;
clk <= !clk;
end

// Implementation of the counter

always @(posedge clk or negedge rst)


if (!rst) cnt = 0;
else if(en)
begin
cnt = cnt + 1;
led <= cnt;
end

// Implementation of the comparator

always @(negedge clk or negedge rst)


if (!rst) qcomp <= 1'b0;
else if (cnt == datacomp) qcomp <= 1'b1;

endmodule

In this code, the always-block

always @(posedge clk_50M)


implements the frequency divider of 10 Hz providing the internal clock clk to the counter. The counter
implemented in the block

always @(posedge clk or negedge rst)

increments the cnt variable on each rising edge of clk. The on-board LEDs reflect the state of the
counter output.
The comparator itself is implemented within the block

always @(negedge clk or negedge rst)

The qcomp output is pulled HIGH when comparator inputs A and B become equal.

The contents of the UCF (mojo.ucf) is shown in Listing 18.

Listing 18.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "rst" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;
NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;
NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold.
Designing counters

This project allows to build a simple 8-bit up counter circuit with the reset (rst) and clock
(clk_50M) inputs (Fig.19).

Fig.19
In this circuit, the clock signal of 50 MHz feeds the counter whose value is incremented by 1 every 1
s. When the counter reaches the value determined by the parameter maxCNT (32, in our case),
counting resumes from 0. The output q[7:0] is connected to the on-board LEDs (output led[7:0])
reflecting the states of the counter output. If the on-board button “Reset” is pressed, the counting
begins from 0.
As usual, this design is based upon the basic Mojo project with a few modifications in the
mojo_top.v and mojo.ucf files.
The Verilog code (mojo_top.v) that models the behavior of the counter is shown in Listing 19.
Listing 19.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input rst_n,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

wire rst = ~rst_n; // make reset active high

parameter maxDIV = 25000000;


parameter maxCNT = 32;
integer cntDiv;
integer cnt;
reg qclk;

initial
begin
cnt = 0;
cntDiv = 0;
qclk <= 1'b0;
led <= 8'd0;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the freq. div of 1 Hz

always @(posedge clk_50M)


if (cntDiv < maxDIV) cntDiv = cntDiv + 1;
else
begin
cntDiv = 0;
qclk <= !qclk;
end;

// Implementation of the 8-bit counter

always @(posedge qclk or posedge rst)


if (rst)
begin
cnt = 0;
led <= 8'd0;
end
else
begin
if (cnt < maxCNT) cnt = cnt + 1;
else cnt = 0;
led <= cnt;
end
endmodule

The contents of the UCF (mojo.ucf) looks like the following (Listing 20).
Listing 20.
#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05
NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "rst_n" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;
The changes introduced into the original mojo.ucf file are shown in bold.

The counter that counts down can be obtained from Listing 19 by introducing a few changes into the
Verilog code (Listing 21.)
Listing 21.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input rst_n,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

wire rst = ~rst_n; // make reset active high

parameter maxDIV = 25000000;


parameter maxCNT = 32;
integer cntDiv;
integer cnt;
reg qclk;

initial
begin
cnt = maxCNT;
cntDiv = 0;
qclk <= 1'b0;
led <= 8'd32;
end
// these signals should be high-z when not used
assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the freq. div of 1 Hz

always @(posedge clk_50M)


if (cntDiv < maxDIV) cntDiv = cntDiv + 1;
else
begin
cntDiv = 0;
qclk <= !qclk;
end;

// Implementation of the 8-bit counter

always @(posedge qclk or posedge rst)


if (rst)
begin
cnt = maxCNT;
led <= 8'd32;
end
else
begin
if (cnt > 0) cnt = cnt - 1;
else cnt = maxCNT;
led <= cnt;
end
endmodule

Designing shift registers


This project illustrates designing the parallel in/serial out shift register. The circuit diagram of this
register is shown in Fig.20.
Fig.20

In this circuit, the data byte pLoad (177, in our case) is loaded into the shift register when the input
rst becomes HIGH (button “Reset” is released). As rst goes LOW (button “Reset” is pressed), each
bit of pLoad is shifted out through the output sOut on the rising edge of the internal clock clk (see
Listing 22) every 0.5 s that corresponds to the frequency of 2 Hz. After 8 iterations have passed, the
value of pLoad will be reflected by the on-board LEDs (output led[7:0].
To resume the operation, we should reload pLoad by releasing “Reset”, then press and hold “Reset”
until the shift operation is complete.
The Verilog code (mojo_top.v) that models the behavior of the shift register is shown in Listing 22.

Listing 22.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input rst,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter maxCNT = 12500000; // 4 Hz / 2


integer i, cnt;
reg clk, sOut;

integer pLoad; // the value to be loaded into reg


integer mask;

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

initial
begin
cnt = 0;
pLoad = 177;
led <= 8'd0;
mask = 1;
i = 0;
end

// Implementation of the freq. div 2 Hz

always @(posedge clk_50M)


if (cnt < maxCNT) cnt = cnt + 1;
else begin
cnt = 0;
clk <= !clk;
end

// Implementation of the shift. reg

always @(posedge clk)


if (rst) begin
pLoad = 177;
led <= 8'd0;
i = 0;
end
else if (!rst && i < 8) begin
sOut = pLoad & mask;
pLoad = pLoad >> 1;
led <= led >> 1;
led[7] <= sOut;
i = i + 1;
end

endmodule

In this code, the frequency divider of 2 Hz is implemented in the always-block

always @(posedge clk_50M)


if (cnt < maxCNT) cnt = cnt + 1;
else begin
cnt = 0;
clk <= !clk;
end

The output of the frequency divider (clk) serves as an internal clock to a shift register.
The following block

always @(posedge clk)


if (rst) begin
pLoad = 177;
led <= 8'd0;
i = 0;
end
else if (!rst && i < 8) begin
sOut = pLoad & mask;
pLoad = pLoad >> 1;
led <= led >> 1;
led[7] <= sOut;
i = i + 1;
end

implements the shift register. In each of 8 iterations, the least significant bit (LSB) of pLoad is fed to
the serial output sOut, then pLoad is shifted right by 1. The value of sOut is assigned to the output
led[7].
After 8 iterations, the pLoad data byte appears on the output led[7:0].

The content of the UCF (mojo.ucf) is shown in Listing 23.

Listing 23.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "rst" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold.

Designing Pulse Width Modulators: example 1

This project illustrates designing a PWM circuit where the duty cycle of an output signal can be
selected by pressing/releasing the button “Reset” (Fig.21).

Fig.21
In this circuit, the base frequency of PWM is set to 2000 Hz. The duty cycle of the PWM signal
(output pwmOUT) can be selected either 32% (button “Reset” is released) or 64% (button “Reset”
is pressed).
The Verilog code (mojo_top.v) that models the behavior of the PWM circuit is shown in Listing 24.
Listing 24.
module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input sw,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg pwmOUT,

// AVR SPI connections


output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
parameter maxDIV = 25000; // base frequency = 2000 Hz
integer cntdiv, duty;

initial
duty = 12500; // the initial duty cycle = 12500/25000 x 100 = 50%

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Choosing the duty cycle of a PWM signal

always @(sw)
duty = sw ? 8000: 16000;

// Implementation of the freq. divider of 2000 Hz

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else cntdiv = 0;

// Implementation of the PWM circuit

always @(posedge clk_50M)


if (cntdiv > duty) pwmOUT <= 1'b0;
else pwmOUT <= 1'b1;

endmodule

In this code, the always-block


always @(posedge clk_50M)
if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else cntdiv = 0;

implements the base frequency for a PWM signal. In our case, the base frequency (2000 Hz) is
determined by the maxDIV parameter.
The initial duty cycle (variable duty) for our PWM circuit is set to 12500 (50%).
Then the duty cycle will be set either to 8000 (32%) when the button “Reset” (input sw = 1) is
released or 16000 (64%) when “Reset” is pressed (sw = 0). This sequence is implemented in the
following block:
always @(sw)
duty = sw ? 8000: 16000;
Driving the PWM output pwmOUT is implemented in the block:
always @(posedge clk_50M)
if (cntdiv > duty) pwmOUT <= 1'b0;
else pwmOUT <= 1'b1;

The contents of the UCF (mojo.ucf) is shown in Listing 25.


Listing 25.
#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05
NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "sw" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "pwmOUT" LOC = P9 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold. There were also deleted
lines NET “led<x>”.
Designing Pulse Width Modulators: example 2
This is one more design of a PWM circuit. Here the duty cycle of a PWM signal gradually increases
while the button “Reset” remains pressed. The circuit diagram of PWM is shown in Fig.22.

Fig.22

In this circuit, the base frequency of a PWM signal is 100 Hz. As the duty cycle increases, the
brightness of the on-board LED (output led0) increases as well.
The Verilog code (mojo_top.v) that models the behavior of the circuit is shown in Listing 26.

Listing 26.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input up,
// cclk input from AVR, high when AVR is ready
input cclk,
// Output to the onboard LED 0
output reg led0,

// AVR SPI connections


output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter maxDIV = 250000; // 200 Hz / 2 = 100 Hz


parameter maxCNT = 500000; // base PWM freq. = 100 Hz
parameter minDUTY = 1000;
parameter inc = 500;
reg clk;

integer duty;
integer cnt, cntdiv; // the current value of a counter

initial
begin
duty = minDUTY;
led0 <= 1'b0;
cnt = 0;
cntdiv = 0;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the 1 Hz freq. divider

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else begin
cntdiv = 0;
clk <= !clk;
end

// Implementation of the counter

always @(posedge clk_50M)


if (cnt < maxCNT) cnt = cnt + 1;
else cnt = 0;

// Implementation of the PWM circuit

always @(posedge clk_50M)


if (cnt > 0 && cnt <= duty) led0 <= 1'b1; // LED is ON
else if (cnt > duty && cnt < maxCNT) led0 <= 1'b0; // LED is OFF
// Implementation of the procedure incrementing the duty cycle

always @(posedge clk)


if (!up) begin
if (duty <= 475000) duty = duty + inc;
else duty = minDUTY;
end

endmodule

In this code, the always-block

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else begin
cntdiv = 0;
clk <= !clk;
end

implements the frequency divider providing the internal clock signal clk of 100 Hz (determined by the
maxDIV parameter) used for incrementing the duty cycle. The duty cycle is configured within the
following always-block:

always @(posedge clk)


if (!up) begin
if (duty <= 475000) duty = duty + inc;
else duty = minDUTY;
end

Incrementing the duty cycle (variable duty) is performed every 0.01 s while the “Reset” button
remains pressed (up = 0). The value of increment is determined by the inc value. When the duty cycle
reaches 475000, it begins incrementing from minDUTY.

The base frequency of a PWM signal (100 Hz) is determined by the parameter maxCNT. The
following always-block drives the led0 output according to the current duty cycle:

always @(posedge clk_50M)


if (cnt > 0 && cnt <= duty) led0 <= 1'b1; // LED is ON
else if (cnt > duty && cnt < maxCNT) led0 <= 1'b0; // LED is OFF

The content of the UCF (mojo.ucf) is shown in Listing 27.


Listing 27.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "up" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led0" LOC = P134 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold.
Designing Pulse Width Modulators: example 3
In this design (Fig.23), the duty cycle of a PWM signal varies between the minDUTY and maxDUTY
values (see the Verilog code below). The duty cycle increases until it reaches the maxDUTY value,
then decreases down to the minDUTY value. The PWM output is connected to the on-board LEDs
(output led[7:0]) that change brightness according to the current duty cycle.

Fig.23

The Verilog code (mojo_top.v) that models the behavior of this PWM circuit is shown in Listing 28.

Listing 28.

module mojo_top(
// 50MHz clock input
input clk_50M,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the onboard LEDs
output reg [7:0] led,

// AVR SPI connections


output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);
parameter maxDIV = 250000; // 200 Hz / 2 = 100 Hz of the duty inc/dec
parameter maxCNT = 500000; // base PWM freq = 100 Hz
parameter minDUTY = 1000;
parameter maxDUTY = 480000;
parameter inc = 500;

reg clk;
integer duty;
integer cnt, cntdiv;
integer up; // 1 --> inc, 0 --> dec

initial
begin
up = 1;
duty = minDUTY;
led <= 8'd0;
cnt = 0;
cntdiv = 0;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the freq. divider of 100 Hz

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else begin
cntdiv = 0;
clk <= !clk;
end

// Implementation of the PWM counter

always @(posedge clk_50M)


if (cnt < maxCNT) cnt = cnt + 1;
else cnt = 0;

// Implementation of the LEDs control

always @(posedge clk_50M)


if (cnt > 0 && cnt <= duty) led <= 8'd255; // LEDs are OFF
else if (cnt > duty && cnt < maxCNT) led <= 8'd0; // LEDs are ON

// Implementation of the duty cycle configuration procedure

always @(posedge clk)


if (up == 1) begin
if (duty <= maxDUTY) duty = duty + inc;
else up = 0;
end
else if (up == 0) begin
if (duty >= minDUTY) duty = duty - inc;
else up = 1;
end

endmodule

In this code, the always-block

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else begin
cntdiv = 0;
clk <= !clk;
end

implements the frequency divider providing the 100 Hz clock signal that is used for changing the duty
cycle in the following always-block:

always @(posedge clk)


if (up == 1) begin
if (duty <= maxDUTY) duty = duty + inc;
else up = 0;
end
else if (up == 0) begin
if (duty >= minDUTY) duty = duty - inc;
else up = 1;
end

The base frequency source for the PWM signal is implemented as a counter in the following always-
block:

always @(posedge clk_50M)


if (cnt < maxCNT) cnt = cnt + 1;
else cnt = 0;

Configuring the duty cycle is provided by the always-block

always @(posedge clk)


if (up == 1) begin
if (duty <= maxDUTY) duty = duty + inc;
else up = 0;
end
else if (up == 0) begin
if (duty >= minDUTY) duty = duty - inc;
else up = 1;
end

Here the direction of changing the duty cycle is determined by the up variable. While up = 1, the
value of the duty cycle is incremented by the inc value every 0.01 s. When the duty cycle has reached
maxDUTY, the variable up becomes 0 and the duty cycle begins decrementing until it reaches
minDUTY. At this point, up becomes 1 and this sequence repeats.

Driving the on-board LEDs is implemented by the following always-block:

always @(posedge clk_50M)


if (cnt > 0 && cnt <= duty) led <= 8'd255; // LEDs are OFF
else if (cnt > duty && cnt < maxCNT) led <= 8'd0; // LEDs are ON

The contents of the UCF (mojo.ucf) is shown in Listing 29.

Listing 29.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold.
Programming State Machines with Verilog

This chapter describes a few digital circuits built using state machines. Often, even an apparently
simple circuits may be tricky to develop so using state machines allows to greatly simplify a design.
This approach provides modeling a system behavior in diagrammatic form. A state machine is
completely based on mathematics and frequently is referred to as Finite State Machine (FSM).

The basic concept behind state machines is that a system stays in a stable state until some event
causes it to transition to another state. During this transition, some actions may occur. States drawn on
a diagram are usually represented by boxes or bubbles, while transitions are drawn as lines with
arrows going either from one box to another or from one box back to itself. The transition lines are
drawn with the label(s) near them. The labels describe the condition(s) for the transition to occur and,
optionally, may describe any actions that need to take place during the transition.

The following sections contain a few projects that illustrates designing digital circuits using state
machines. You may realize that entire operations performed by these state machines could also be
implemented using simpler Verilog code, but the state machine presents a clear communication of the
intent of a digital circuit and provide an easy way for improving end modifying your design.
Example 1
This example illustrates how to design a state machine implementing an up/down counter circuit
(Fig.24).

Fig.24

In this circuit, the external clock of 50 MHz is taken from the input clk_50M (pin P56 of the FPGA).
Then the frequency of the input clock is divided by an internal frequency divider that provides the
internal clock of 1 Hz to the counter. The counter output q[7:0] drives the on-board LEDs (led[7:0]).
The input dir determines the direction of counting, either up or down. When dir = 0, a counter is
decremented at each positive edge of the internal clock every 1 s; when dir = 1, the counter is
incremented. The dir input is driven by the on-board button “Reset” connected to the pin P38 of the
FPGA.
The on-board LEDs (led[7:0]) reflect the changes of the counter output.

To design this circuit using a state machine approach, let’s determine the possible states where our
system will stay in and signals (events) causing transitions between states. One possible solution is
shown in Fig.25.
Fig.25

In this system, the IDLE state provides transitions to the CNTUP and CNTDOWN states. Transition
from IDLE to one of the active states (CNTUP or CNTDOWN) will be possible if any of the
following events occurs:
1. The signal dir is active (log.”1”). In this case, transition from the IDLE state to CNTUP takes
place;
2. The signals dir is inactive (log.”0”). In this case, transition from IDLE to CNTDOWN takes
place.

When the system stays in the CNTUP state, the circuit is counting up while dir remains 1. When dir
becomes 0, transition to the IDLE state takes place. The current value of the counter is kept during
transition.
When the system stays in the CNDOWN state, the circuit is counting down while dir remains 0. When
dir becomes 1, transition to the IDLE state takes place. The current value of the counter is kept during
transition.

The Verilog code (mojo_top.v) that models the behavior of our state machine is shown in Listing 30.

Listing 30.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input dir,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter maxDIV = 25000000; // 2 Hz /2 = 1 Hz


parameter maxCNT = 16;
parameter minCNT = 4;

parameter IDLE = 2'b00;


parameter CNTUP = 2'b01;
parameter CNTDOWN = 2'b10;

reg [1:0] state_reg; // holds a current state


reg clk; // internal clock to the counter
reg [7:0] q; // internal counter outputs
integer cntdiv, cnt;

initial
begin
q <= 8'd0;
led <= q;
state_reg <= IDLE;
cnt = minCNT - 1;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the freq. divider 1 Hz

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else
begin
cntdiv = 0;
clk <= !clk;
end

// Implementation of the up/down counter & state machine

always @(posedge clk)


case (state_reg)
IDLE:
if (dir) state_reg <= CNTUP;
else state_reg <= CNTDOWN;
CNTUP:
if (dir && cnt < maxCNT) begin
cnt = cnt + 1;
q <= cnt;
led <= q;
end
else if (dir && cnt == maxCNT) cnt = minCNT - 1;
else if (!dir) state_reg <= IDLE;
CNTDOWN:
if (!dir && cnt > minCNT) begin
cnt = cnt - 1;
q <= cnt;
led <= q;
end
else if (!dir && cnt == minCNT) cnt = maxCNT + 1;
else if (dir) state_reg <= IDLE;
default:
state_reg <= IDLE;
endcase

endmodule

In this code, the state of our system is determined by the set of 2-bit parameters:

parameter IDLE = 2'b00;


parameter CNTUP = 2'b01;
parameter CNTDOWN = 2'b10;

We also need to keep a current state in order to provide transitions between states. In this code, the
current state is stored in the 2-bit state_reg variable of the reg type.
The always-block

always @(posedge clk_50M)

implements the frequency divider providing the internal clock clk of 1 Hz to the counter. The output
frequency of the divider is determined by the maxDIV parameter.

The state machine itself is implemented within the block

always @(posedge clk)

The case statement in this block describes the required operations in each state and allows to make
transitions between states if the required conditions are satisfied

The contents of the UCF (mojo.ucf) is shown in Listing 31.

Listing 31.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "dir" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf are shown in bold.

In the above Verilog code, all required actions were completely executed in the section related to the
particular state. It is possible, however, to make a code more readable by distinguishing the part
processing a state itself from the rest of code. The following example (Listing 32) is a modified
version of the Verilog code shown in Listing 30.

Listing 32.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input dir,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,

// AVR SPI connections


output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter maxDIV = 25000000; // 2 Hz


parameter maxCNT = 32;
parameter minCNT = 16;

parameter IDLE = 2'b00;


parameter CNTUP = 2'b01;
parameter CNTDOWN = 2'b10;

reg [1:0] state_reg;


reg clk; // internal clock
reg [7:0] q; // internal counter outputs
integer cntdiv, cnt;

initial
begin
q <= 8'd0;
led <= q;
state_reg <= IDLE;
cnt = minCNT;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the freq. divider of 1 Hz

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else
begin
cntdiv = 0;
clk <= !clk;
end

// Implementation of the state machine

always @(posedge clk)


case (state_reg)
IDLE:
if (dir) state_reg <= CNTUP;
else state_reg <= CNTDOWN;
CNTUP:
if (!dir) state_reg <= IDLE;
CNTDOWN:
if (dir) state_reg <= IDLE;
default:
state_reg <= IDLE;
endcase

// Implementation of the counter

always @(posedge clk)


case (state_reg)
CNTUP:
if (dir && cnt <= maxCNT) begin
q <= cnt;
led <= q;
cnt = cnt + 1;
end
else if (dir && cnt > maxCNT) cnt = minCNT;
CNTDOWN:
if (!dir && cnt >= minCNT) begin
q <= cnt;
led <= q;
cnt = cnt - 1;
end
else if (!dir && cnt < minCNT) cnt = maxCNT;
endcase

endmodule
Example 2
This example illustrates designing a simple counter (Fig.26) that begins counting up when the input
reload becomes active (log.”0”). This occurs when the button “Reset” associated with reload is
pressed. Counting continues regardless of the state of “Reset” until some predetermined value
(parameter maxCNT) is reached.
At this point, the counter either stops (if the button “Reset” is released) or continues counting from 0
(if “Reset” remains pressed).
The bWait output connected to led[7] toggles when counting is stopped. When counting begins, bWait
becomes 0.

Fig.26

The state diagram that describes this circuit is shown in Fig.27.

Fig.27

This system stays in the IDLE state while the reload input is inactive (log.”1”) and a counter is
cleared (led = 0). The transition from IDLE to the COUNT states occurs when reload becomes active
(log.”0”) while the counter is still clear (led = 0).

When the system stays in the COUNT state, the circuit is counting up from 0 until maxCNT is
reached. When the value of the counter reaches maxCNT, the counter is stopped and transition to the
RELOAD state takes place.
In the RELOAD state, the counter is cleared (led = 0) and transition to the IDLE state takes place.

The Verilog code (mojo_top.v) that models the behavior of this circuit is shown in Listing 33.

Listing 33.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button
input reload,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

parameter maxDIV = 5000000; // 10Hz / 2


parameter maxCNT = 20;

// state machine parameters

parameter IDLE = 2'b00;


parameter COUNT = 2'b01;
parameter RELOAD = 2'b10;

reg [1:0] state;


integer cnt;
reg clk, bWait;

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

initial
begin
state <= IDLE;
led <= 8'd0;
cnt = 0;
end

// Implementation of the freq. divider 5 Hz

always @(posedge clk_50M)


if (cnt < maxDIV) cnt = cnt + 1;
else begin
cnt = 0;
clk <= !clk;
end

// Implementation of the state machine & counter

always @(posedge clk)


case (state)
IDLE:
if (!reload && led == 8'd0) begin
bWait <= 1'b0;
led[7] <= bWait;
state <= COUNT;
end
else begin
bWait <= !bWait;
led[7] <= bWait;
end
COUNT:
if (led < maxCNT) led <= led + 1;
else if (led >= maxCNT) state <= RELOAD;
RELOAD:
begin
led <= 8'd0;
state <= IDLE;
end
default:
state <= IDLE;
endcase

endmodule

In this code, the always-block

always @(posedge clk_50M)


if (cnt < maxDIV) cnt = cnt + 1;
else begin
cnt = 0;
clk <= !clk;
end

implements the frequency divider. The divider provides the internal clock clk with a frequency of 5
Hz to the counter. The output frequency is determined by the maxDIV parameter.

The state machine and counter are implemented within a block

always @(posedge clk)


case (state)
.
.
.
endcase

The contents of the UCF (mojo.ucf) is shown in Listing 34.

Listing 34.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "reload" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold.
Example 3
This example illustrates the design of the counter circuit (Fig.28) controlled through the input en
(button “Reset”). This circuit counts down from the value determined by the parameter maxCNT to
0. Counting begins when “Reset” is pressed (log.”0”) and stops when “Reset” is released (log.”1”).
As the counter reaches 0, it is reloaded with the value determined by maxCNT.
The circuit diagram of the counter is shown in Fig.28.

Fig.28

The block diagram of the state machine that implements this circuit is shown in Fig.29.

Fig.29

When in the IDLE state, the system waits until the enable signal en becomes active (log.”0”). When
this event occurs, transition from IDLE to the COUNT state takes place.
In the COUNT state, while en stays active (log.”0”), the counter is counting down from maxCNT to
0. If en becomes inactive (log.”1”) during counting, the counter stops and transition to the IDLE state
takes place. When the counter reaches 0, transition from COUNT to RELOAD takes place.
In the RELOAD state, the counter is reloaded with the predetermined value (parameter maxCNT)
and transition to the IDLE state takes place.

The Verilog code (mojo_top.v) that models the behavior of the above circuit is shown in Listing 35.

Listing 35.

module mojo_top(
// 50MHz clock input
input clk_50M,
// Input from reset button (active low)
input en,
// cclk input from AVR, high when AVR is ready
input cclk,
// Outputs to the 8 onboard LEDs
output reg [7:0] led,
// AVR SPI connections
output spi_miso,
input spi_ss,
input spi_mosi,
input spi_sck,
// AVR ADC channel select
output [3:0] spi_channel,
// Serial connections
input avr_tx, // AVR Tx => FPGA Rx
output avr_rx, // AVR Rx => FPGA Tx
input avr_rx_busy // AVR Rx buffer full
);

// parameters for a freq. divider from 50MHz to 1Hz


parameter maxDIV = 12500000; // 4 Hz /2
parameter maxCNT = 16;

parameter IDLE = 2'd0;


parameter COUNT = 2'd1;
parameter RELOAD = 2'd2;

reg [1:0] state;


reg clk; // internal clock
reg [7:0] q; // internal counter outputs

integer cntdiv;
integer cnt;
initial
begin
cnt = maxCNT;
state <= IDLE;
end

// these signals should be high-z when not used


assign spi_miso = 1'bz;
assign avr_rx = 1'bz;
assign spi_channel = 4'bzzzz;

// Implementation of the freq. divider 2 Hz

always @(posedge clk_50M)


if (cntdiv < maxDIV) cntdiv = cntdiv + 1;
else
begin
cntdiv = 0;
clk <= !clk;
end

// Implementation of the state machine & counter

always @(posedge clk)


case (state)
IDLE:
if (!en) state <= COUNT;
COUNT:
if (!en) begin
q <= cnt;
led <= q;
if (cnt == 0) state <= RELOAD;
else cnt = cnt - 1;
end
else state <= IDLE;
RELOAD:
begin
cnt = maxCNT;
q <= cnt;
led <= q;
state <= IDLE;
end
default:
state <= IDLE;
endcase

endmodule

The contents of the UCF (mojo.ucf) is shown in Listing 36.

Listing 36.

#Created by Constraints Editor (xc6slx9-tqg144-3) - 2012/11/05


NET "clk_50M" TNM_NET = clk_50M;
TIMESPEC TS_clk_50M = PERIOD "clk_50M" 50 MHz HIGH 50%;

# PlanAhead Generated physical constraints


NET "clk_50M" LOC = P56 | IOSTANDARD = LVTTL;
NET "en" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "led<0>" LOC = P134 | IOSTANDARD = LVTTL;


NET "led<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "led<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "led<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "led<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "led<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "led<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "led<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;


NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;


NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

The changes introduced into the original mojo.ucf file are shown in bold.

Você também pode gostar