Simulation and synthesis of a counter
The goal of this exercise is to review the basis of hardware description languages (HDL), and
the simulation and synthesis flow targeting programable logic devices. You have to provide three
implementations of simple counter with the following features:
- 8-bit binary up-counter with synchronous set and reset.
- Must increment its output value by 1, every second.
- RTL synthesizable implementation in VHDL, Verilog, and SystemC.
Pseudo-code:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
|
On each clock cycle {
if reset is enabled {
counter_output = 0
}
else {
if set is enabled {
counter_output = counter_input
}
else {
if 1s has elapsed since last change of counter_output
counter_output = counter_output + 1
}
}
}
|
Simulation
The first step is to validate the three implementations using a testbench and an RTL simulator.
To help you with this task, the following simulation files and templates are provided here:
- counter_vhdl.vhd, counter_verilog.v, and counter_systemc.h: define the interface of the three implementations.
In each one, the parameter FREQ is used to define the input clock frequency. The meaning of the remaining
input/output ports is straightforward. Provide your implementation inside this files
- counter_modelsim_vhdl.cc, counter_modelsim_vlog.cc, and counter_modelsim_sc.cc: simulation top-level modules.
- counter_testbench.h: SystemC testbench implementation. The same testbench is used to validate all implementations.
SystemC is used as the testbench language since it provides more high-level features then VHDL and Verilog.
- simulation_cmds.do: contains scripts for simulating the design using Modelsim. If you want to change something in the simulation flow, take a look in this file.
- common/Makefile.common and Makefile: more scripts for simulation.
- The remaining files are related to synthesis and will be described latter.
After implementing your counters, just type make sim
to start Modelsim and simulate your design for 30s. You should get
the following (or a very similar one) simulation trace for all implementations:
# Starting testbench
# Count : 1
# Count : 2
# Count : 3
# Count : 4
# Count : 5
# Count : 6
# Count : 7
# Count : 8
# Count : 9
# Count : 10
# Setting counter to 5
# Count : 5
# Count : 6
# Count : 7
# Count : 8
# Count : 9
# Count : 10
# Setting counter to 5
# Count : 5
# Count : 6
# Count : 7
# Count : 8
# Count : 9
# Count : 10
# Count : 11
# Count : 12
# Count : 13
# Count : 14
# Count : 15
# Count : 16
# Count : 17
# Count : 18
# Count : 19
If things don't work as expected. You can take a lock at the testbench waveforms. Use a waveform viewer like gtkwave
to open the trace*.vcd files generated during simulation.
Synthesis
Now that you have validated the implementations, you can download them into an FPGA and see it running as a real hardware.
We will use an Spartan3 Starter Board, which features an Spartan3 FPGA and some useful IO peripherals.
Scripts which implement the synthesis flows are already available, just chose either the VHDL or the Verilog implementation
of your counter, and modify the files counter_spartan3.ucf and counter_spartan3.v in order to instantiate
your counter in a way in which:
- The counter's output data is connected to the board's leds.
- The counter's input data is connected to the board's switches.
- The counter's set and reset are each connected to one the board's buttons.
The following files related to synthesis are already available:
- counter_spartan3.v: synthesis top-level module. This is where you will define the input/output ports
for your design and instantiate your counter. Some clock-related stuff is already defined.
- counter_spartan3.ucf: synthesis constraints file. Here you will find the definition of the timing constraints
and the mapping of input/outputs to physical FPGA pins. Timing constraints are already defined.
- counter_spartan3.cdf and counter_spartan3.impact: contains some definitions for uploading the design to
the FPGA.
- common/*: contains synthesis-related scripts.
To synthesise the design, type make synth
, to start Xilinx's synthesis tools (XST).
Take a look at the tool's output, if the synthesis process had completed succesfully, you should get a resource
and timing summary similar to the one bellow:
Advanced HDL Synthesis Report
Macro Statistics
# Adders/Subtractors : 1
32-bit adder : 1
# Counters : 1
8-bit up counter : 1
# Registers : 32
Flip-Flops : 32
# Multiplexers : 1
32-bit 4-to-1 multiplexer : 1
...
Timing Summary:
---------------
Speed Grade: -4
Minimum period: 7.964ns (Maximum Frequency: 125.568MHz)
Minimum input arrival time before clock: 5.638ns
Maximum output required time after clock: 7.241ns
Maximum combinational path delay: No path found
After synthesis, use make par
to run the implementation flow. It will execute the Translate (NGDBUILD), Map (MAP),
and place-and-route (PAR) tools in sequence. The most relevant information generate by the tools is the resource consumption
and timming reports which may look like the ones bellow:
Design Summary:
Number of errors: 0
Number of warnings: 2
Logic Utilization:
Number of Slice Flip Flops: 40 out of 3,840 1%
Number of 4 input LUTs: 50 out of 3,840 1%
Logic Distribution:
Number of occupied Slices: 41 out of 1,920 2%
Number of Slices containing only related logic: 41 out of 41 100%
Number of Slices containing unrelated logic: 0 out of 41 0%
*See NOTES below for an explanation of the effects of unrelated logic.
Total Number of 4 input LUTs: 81 out of 3,840 2%
Number used as logic: 50
Number used as a route-thru: 31
The Slice Logic Distribution report is not meaningful if the design is
over-mapped for a non-slice resource or if Placement fails.
Number of bonded IOBs: 21 out of 173 12%
Number of BUFGMUXs: 1 out of 8 12%
Number of DCMs: 1 out of 4 25%
Average Fanout of Non-Clock Nets: 2.45
...
+-------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
| | Period | Actual Period | Timing Errors | Paths Analyzed |
| Constraint | Requirement |-------------+-------------|-------------+-------------|-------------+-------------|
| | | Direct | Derivative | Direct | Derivative | Direct | Derivative |
+-------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
|TS_clk_fpga_in | 20.000ns| 6.000ns| 7.509ns| 0| 0| 0| 1844|
| TS_clks_main_CLK0_BUF | 20.000ns| 7.509ns| N/A| 0| 0| 1844| 0|
+-------------------------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+
All constraints were met.
If the design does not fit in the FPGA (i.e. it uses more resources the ones available), the implementation process will not
complete succesfully. If one of your timing constraints is not met, the process will complete, but your design may not
work.
The last step is to generate the bitstream and upload the design to the FPGA. Use make bin
, and than
make program
. With make bin
you can also run the whole synthesis/implementation process in one step.
Use make clean
to make sure everything is cleaned-up between each synthesis/program iteration.
NOTE1: some times make program just does not work. If thats the case, use make mcs to generate
the FPGA bitstream, than type impact to open the Xilinx's programming GUI and upload the build/counter_spartan.mcs
to the board's FLASH memory (see the manuals bellow for more details about using impact.
NOTE2: You can use the Xilinx's IDE to run all the steps above. Use make proj to generate a ISE project file
(build/counter_spartan3.xise
) and than use the command ise
to run ISE and open your project file.
After everything is completed, you should see the leds showing a incrementing value every second. Use the buttons and switches to force a new value
into the leds
Useful links
Solution