Tutorial Project
Tutorial Project
1. Tutorial project
For the Xilinx ISE tutorial the goal is to implement a one-digit BCD (binary coded decimal) second counter. That
is, the counter counts from zero to nine and increments once every second. The actual value is displayed on 4
LEDs. Based on the state of the SW0 switch, the counter counts upwards or downwards.
During Measurement Laboratory 1., it is required to design synchronous systems, that is all flip-flops in the
design should operate using the 50 MHz clock input available on the development board. If part of the design
should operate less frequently (just like the counter in this tutorial), an enable signal should be generated. For
example, for the second counter this enable signal has a frequency of 1 Hz it takes value of 1 once in every
second for exactly one system clock cycle long. That is, the enable signal is 0 for 49,999,999 clock cycles, then
it goes to 1 for a single clock cycle.
To be able to set the system into a known state, an external reset signal should be present.
The schematic diagram of the system to be designed is shown below. The counter module is the BCD counter,
while rategen generates the necessary enable signal for the counter which was described above. These two
submodules are connected together in the top-level module.
FPGA
BTN0
btn0
q[3]
rst
Counter
SW0
sw0
q[3:0]
dir
clk
System
clock
clk
rst
q[2]
ce
q[1]
q[0]
LD3
LD2
LD1
LD0
cy
Rate
generator
clk
Top left: Sources window: sources of the current project. In the drop-down menu you can select to show
source files for Implementation or for Simulation.
Processes window shows the allowed processes to be ran using the source file selected in the Sources
window.
The Editor window is the Xilinx text editor to edit different kinds of source files.
- 1/16 -
At the bottom, the Transcript window shows messages from the tool. The Console window lists all
messages, while Warnings and Errors lists only the selected messages..
- 2/16 -
After press Next button, ISE offers the creation of new source files, but at the moment this option is not used.
Also skip the Add Existing Sources option, and press Next then Finish to finalize the creation of the
empty project..
- 3/16 -
Using the schematic diagram above, create the necessary ports for the counter.
Press Next, Finish to see the module declaration in the editor window:
module count_sec(
input clk,
input rst,
input ce,
input dir,
output [3:0] q
);
endmodule
- 4/16 -
To detect the end-value, two combinatorial comparators are used, which compare the output of the register with 9
and 0. Based on these, the schematic diagram of the counter looks as follows:
cntr_d0_inc
cntr_d0_eq9
9
==
0
2:1
MUX
mux_0
INC
2:1
MUX
mux_2
4-bit
register
DEC
2:1
MUX
mux_1
==
cntr_d0_eq0
cntr_d0_dec
dir
clk
rst
ce
In Verilog it is possible to describe the exact same structure (for the register reg typed variables are declared, for
the combinatorial part wire variables are used).
reg [3:0] cntr_d0;
wire [3:0] cntr_inc, cntr_dec;
wire [3:0] mux_0, mux_1, mux_2;
wire cntr_d0_eq0, cntr_d0_eq9;
always @(posedge clk)
if (rst)
cntr_d0 <= 0;
else if (ce)
cntr_d0 <= mux_2;
assign
assign
assign
assign
cntr_d0_inc
cntr_d0_dec
cntr_d0_eq0
cntr_d0_eq9
=
=
=
=
cntr_d0 + 1;
cntr_d0 - 1;
(cntr_d0 == 0);
(cntr_d0 == 9);
4. Simulation
4.1 Creating the testbench
To be able to functionally verify the module you have just created you have to generate input signals for the
module. This is done in the so-called testbench. First, create a Verilog Test Fixture using Project /
New Source and selecting Verilog Test Fixture as the type of the source.
In the next window select the module you want to create a testbench for. In our case we have only one module
(count_sec), so select it.
- 6/16 -
Press Next, Finish to have the file generated. In the top-left drop-down menu select Behavioral
Simulation to see the source which are only valid for simulation. As you can see, the module to be tested
(count_sec) is a submodule for the testbench (tb_counter).
instantiation of the module to be tested with the name UUT (unit under test)
all inputs are set to 0 at the beginning of the simulation (initial block)
`timescale 1ns / 1ps
module tb_conter;
// Inputs
reg clk;
reg rst;
reg ce;
reg dir;
// Outputs
- 7/16 -
wire [3:0] q;
// Instantiate the Unit Under Test (UUT)
count_sec uut (
.clk(clk),
.rst(rst),
.ce(ce),
.dir(dir),
.q(q)
);
initial begin
// Initialize Inputs
clk = 0;
rst = 0;
ce = 0;
dir = 0;
// Wait 100 ns for global reset to finish
#100;
// Add stimulus here
end
endmodule
As the counter contains sequential logic, a clock signal should be generated:
always #5
clk <= ~clk;
For the other inputs generate the following waveforms.
- 8/16 -
By right clicking on the signals you can change the display format set q[3:0] to hexadecimal.
The simulator only shows the inputs and output automatically. However, often it is necessary to inspect internal
signals of the system. Internal signals can be added to the simulator waveform without modifying the Verilog
code.Select Instances and Processes tab in the left window to see the testbench hierarchy. In the
hierarchy select the counter instance (UUT), then select the Objects tab. Here you can see all internal signals o
the counter, which can be drag-and-dropped into the waveform window. After restarting the simulation
(restart/play icons at the top) you will see the values of the newly added signals.
- 9/16 -
- 10/16 -
The top level declaration therefore should look like the code below:
module wpbevtop1(
input clk,btn0, sw0,
output [3:0] q
);
The external asynchronous signals (button, switch) are synchronized to the system clock by sampling them into
registers:
reg rst, dir;
always @(posedge clk)
//Synchronize inputs
begin
rst <= btn0;
dir <= sw0;
end
The next task is to instantiate the submodules, namely create one instance from rategen and one instance from
count_sec.
Instantiation of rategen:
wire ce;
rategen rategenerator(
.clk(clk),
.rst(rst),
.cy(ce)
);
Instantiation of the counter:
count_sec counter(
.clk(clk),
.rst(rst),
.ce(ce),
.dir(dir),
.q(q)
);
So, with the input synchronization and all submodule instantiation the top-level module code:
- 11/16 -
module wpbevtop1(
input clk,btn0, sw0,
output [3:0] q
);
reg rst, dir;
always @(posedge clk)
//Synchronize inputs
begin
rst <= btn0;
dir <= sw0;
end
wire ce;
rategen rategenerator(
.clk(clk),
.rst(rst),
.cy(ce)
);
count_sec counter(
.clk(clk),
.rst(rst),
.ce(ce),
.dir(dir),
.q(q)
);
endmodule
The ports of the top-level module are connected to the pins of the FPGA. The port pin mapping can be done
with a Xilinx tool, called PlanAhead.
First, create an Implementation Constraint File (.ucf) with Project / New Source menu, and select
Implementation Constraint File. Name it to counter_pins.
Click Next/Finish to finish the file generation. In the top-left drop-down menu select Implementation to
verify that the counter_pins.ucf file is added to the project.
Select the top-level module in the sources Window. In the Processes window click on User Constraints /
I/O Pin Planning (PlanAhead) Pre-Synthesis.
- 12/16 -
In the I/O Ports window you can see all ports of wpbevtop1 module. Pin names should be typed into the LOC
column (or alternatively, select the port and type in the pin name in the top-left window called I/O Properties).
The peripheral pin name associations can be read from the development board (e.g. clock is connected to pin
T9).
- 13/16 -
After typing in all pi names, save the PlanAhead project and quit. In ISE Sources window select the
counter_pins.ucf file, then in the Processes menu click on Edit Constraints (Text) option to see the
syntax of the UCF file.
NET
NET
NET
NET
NET
NET
NET
"clk"
"btn0"
"sw0"
"q<3>"
"q<2>"
"q<1>"
"q<0>"
LOC="t9";
LOC="m13";
LOC="f12";
LOC="n14";
LOC="l12";
LOC="p14";
LOC="k12";
Check the box next to the JTAG Download text to have the configuration panel.
- 14/16 -
Click Query JTAG chain. You will see two devices: XC3S200 FPGA and XCF02S flash memory. In the dropdown menu select the FPGA and then click on the Configure the selected device button. Select the bit file from
your own ISE project directory.
Verify the operation of the design.
counting upwards (dir=1), LS digit is 9 (cntr_d0_eq9=1) and the external enable signal is active
(ce=1) OR
counting downwards (dir=0), LS digit is 0 (cntr_d0_eq0=1) and the external enable signal is active
(ce=1)
- 15/16 -
In the count_sec module declare the necessary variables and describe the functionality of the MS digit
IN A SEPARATE always block.
Increase the output port width in the counter and in the top-module.
- 16/16 -