Skip to main content

AMD (formerly Xilinx) FPGAs: Part 2 Synthesis and testing on device

Introduction

In the previous tutorial, you ran through the automated simulation of a full adder. In this section, you will learn how to synthesize the full adder and run tests on the FPGA device using the Integrated Logic Analyzer (ILA) IP core.

You can find the source code for this example here.

Creating and running a hardware testbench

Creating a block diagram

The testbench you created previously is not synthesizable for your FPGA. To test on actual hardware, you need to create a hardware testbench by including IP that can stimulate the full adder's input and then use the ILA core to record the waveforms. The first step is to create a block diagram of our design.

  1. In Vivado, in the Flow Navigator, select Create block diagram under IP Integrator. The Create Block Design window will open. Select OK.
  2. The BLOCK DESIGN tab will now open. Under Sources, find Design Sources and then right click adder. Then select Add module to Block Diagram, which will add your full adder to the block diagram. Getting started AMD FPGA Hardware 01
  3. Now you need a clock source. Right click the block diagram and select Add IP then find the Clocking Wizard IP.
  4. A message on the block diagram stating Designer Assistance Available. Run Connection Automation should appear. Select Run Connection Automation. In the new Run Connection Automation window, select All Automation. Getting started AMD FPGA Hardware 02 This will automatically connect a sys_clock and a reset pin to the block diagram. Getting started AMD FPGA Hardware 03
  5. To write to your adder inputs, you will use a simple 3-bit counter. Right click the block diagram and select Add IP then find the Binary Counter IP.
  6. Double click the Binary Counter to open up the Re-customize IP window and modify the Output Width to be 3.
  7. Connect the CLK of the Binary Counter to clk_out1 of the clk_wiz_0.
  8. Add three Slice IPs. Modify each one as follows:
    • xlslice_0 Din Width: 3, Din From: 0, Din Down To: 0, Dout Width: 0
    • xlslice_1 Din Width: 3, Din From: 1, Din Down To: 1, Dout Width: 0
    • xlslice_2 Din Width: 3, Din From: 2, Din Down To: 2, Dout Width: 0
  9. Connect the input of each Slice to the output of the Binary Counter.
  10. Connect each Slice output as follows:
    - xlslice_0: Dout[0:0] -> A
    - xlslice_1: Dout[0:0] -> B
    - xlslice_2: Dout[0:0] -> Cin
    Getting started AMD FPGA Hardware 04
  11. Now you need to add the ILA. Right-click the block diagram and select Add IP then find the ILA IP.
  12. Double click the ILA to customize it. Change Monitor Type to Native and Number of Probes to 5.
  13. Attach the ILA input port clk to clk_out1 of the clk_wiz_0.
  14. Attach the ILA input port probe0[0:0] to S of the adder_0.
  15. Attach the ILA input port probe1[0:0] to COUT of the adder_0.
  16. Attach the ILA input port probe2[0:0] to A of the adder_0.
  17. Attach the ILA input port probe3[0:0] to B of the adder_0.
  18. Attach the ILA input port probe4[0:0] to CIN of the adder_0.

Getting started AMD FPGA Hardware 05 19. Right-click the block diagram and select Validate Design. Vivado should indicate that validation was successful. 20. Under Flow Navigator and the IP INTEGRATOR section, select Generate Block Design. Wait for the block design to successfully generate. 21. Back in the BLOCK DESIGN, under Design Sources, right-click design_1.bd and select Create HDL Wrapper.... In the Create HDL Wrapper window, select Let Vivado manage wrapper and auto-update, then select OK. Getting started AMD FPGA Hardware 06 22. Right-click the generated HDL and select Set as Top. 23. Under Flow Navigator and the PROGRAM AND DEBUG section, select Generate Bitstream. This will open the Save Project window to which you should select Save. The Launch Run window should now open and you can select OK. After a while, you should receive a success message. Select Open Hardware Manager.

Running the hardware testbench

Now that you have generated your bitstream, you can run your hardware testbench. To do so, you need to program your device and then capture the results from the ILA.

  1. In the Hardware Manager under hardware, right-click your device, then select Program Device.... The Program Device window should appear, where you can select Program. Getting started AMD FPGA Hardware 07

  2. This should open your hw_ila_1 waveform window. In the Waveform tab, select the Play button. Getting started AMD FPGA Hardware 08

  3. The ILA should then capture the waveforms running on the device itself!

Getting started AMD FPGA Hardware 09

Automating the hardware testbench to the repo

Adding the hardware testbench to the repo

Now that you have a working hardware testbench, you need to add it to the repository alongside the tcl files that are needed to synthesize the file, program the device, and trigger the ILA.

  1. You first need to update your .gitignore file to include the generated files. Make sure to push this to the repo:
.gitignore
# Blocklist files/folders in same directory as the .gitignore file
/*

# Includelist some files
!.gitignore
!README.md

# Include xpr and srcs
!ci_for_fpgas.srcs/
!ci_for_fpgas.srcs/*
!ci_for_fpgas.xpr

# Include gen files
!ci_for_fpgas.gen/
!ci_for_fpgas.gen/*

!tcl_scripts/
!tcl_scripts/*

  1. For automated runs you will also need to set the pins in the constraints. Create a constraints file, by going to the Flow Navigator and selecting Add Sources under PROJECT MANAGER. Create one called pin_constraints.xdc and copy in the following code:
pin_constraints.xdc
set_property PACKAGE_PIN E3 [get_ports sys_clock]
set_property IOSTANDARD LVCMOS33 [get_ports sys_clock]
set_property PACKAGE_PIN C2 [get_ports reset]
set_property IOSTANDARD LVCMOS33 [get_ports reset]

If you are using a different board than the A7-100, you will need to change these pins to the relevant ones for your board. You can look in the pin planner to see what Vivado has automatically assigned to them.

  1. You are now going to add a tcl script for running through synthesis, implementation and bitstream generation. In your tcl_scripts folder, add the following run_synthesis.tcl file:
run_synthesis.tcl
open_project ci_for_fpgas.xpr
update_compile_order -fileset sources_1
reset_run impl_1 -prev_step
launch_runs impl_1 -to_step write_bitstream -jobs 4
  1. You also need a tcl script to program your board and trigger the ila. In your tcl_scripts folder, add the following program_device_trigger_ila.tcl file:
program_device_trigger_ila.tcl
open_hw_manager
connect_hw_server -allow_non_jtag
open_hw_target
set_property PROBES.FILE {./ci_for_fpgas.runs/impl_1/design_1_wrapper.ltx} [get_hw_devices xc7a100t_0]
set_property FULL_PROBES.FILE {./ci_for_fpgas.runs/impl_1/design_1_wrapper.ltx} [get_hw_devices xc7a100t_0]
set_property PROGRAM.FILE {./ci_for_fpgas.runs/impl_1/design_1_wrapper.bit} [get_hw_devices xc7a100t_0]
program_hw_devices [get_hw_devices xc7a100t_0]
refresh_hw_device [lindex [get_hw_devices xc7a100t_0] 0]
run_hw_ila [get_hw_ilas -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"design_1_i/ila_0"}]
wait_on_hw_ila [get_hw_ilas -of_objects [get_hw_devices xc7a100t_0] -filter {CELL_NAME=~"design_1_i/ila_0"}]
write_hw_ila_data {./iladata.ila} hw_ila_data_1

If you are using a different board than the A7-100, you will need to change xc7a100t_0 to the FPGA found on your board. You can find that out by looking at your hardware manager or by seeing the commands that are run by your tcl console in Vivado when you program the board. 5. Make sure to push all these files to your Git repo.

Running the pipeline

Now you have the files you need, you need to make a few modification to your config.yaml file then you will be ready to run the pipeline

  1. Modify your config.yaml file to add two more steps and new artifacts:
config.yaml
# Example config file to use as a starting point.
# Please visit https://docs.beetleboxci.com/docs/config/configuration-yaml for guidance on setting up your configuration file.

# Define a runner that will be used to run a job
runners:
ubuntu-runner:
image: public.ecr.aws/y2s4f3y9/ubuntu-generic

# Define a job to be performed during a workflow
jobs:
run-sim-syn-job:
# Specify the runner used to perform this job
runner: ubuntu-runner
resource_spec: large
output:
artifact:
- ci_for_fpgas.sim/
- ci_for_fpgas.hw/
- ci_for_fpgas.runs/
- ci_for_fpgas.cache/
- iladata.ila
volumes:
- mount:
name: volume1
path: < The installation directory of Xilinx tools, by default this is /tools/Xilinx>

# Define one or more steps to execute commands as part of the job
steps:
- run:
name: Initalise vivado environment
command: |
apt-get update
apt-get install locales
locale
locale-gen "en_US.UTF-8"
update-locale LANG=en_US.UTF-8
- run:
name: Run Simulation
command: |
cd < The installation directory of Vivado, by default this is /tools/Xilinx/Vivado/2023.1/>
source settings64.sh
cd $HOME
ls
vivado -mode batch -source tcl_scripts/run_sim.tcl | tee simulation_output.txt
- run:
name: Parse simulation for errors
command: |
# Path to the file to be checked
FILE_PATH="./simulation_output.txt"
# Check if the file exists
if [[ ! -f "$FILE_PATH" ]]; then
echo "File does not exist: $FILE_PATH"
exit 1
fi
# Search for the phrase "Error: Assertion violation" in the file
if grep -q "Error: Assertion violation" "$FILE_PATH"; then
echo "Error: Assertion violation found in file."
exit 1
else
echo "No assertion violations found. Passing."
exit 0
fi
- run:
name: Run Bitstream Generation
command: |
cd /tools/Xilinx/Vivado/2023.1/
source settings64.sh
cd $HOME
vivado -mode batch -source tcl_scripts/run_gen_bitstream.tcl | tee bit_stream_gen_output.txt
- run:
name: Program Device and Trigger ILA
command: |
cd /tools/Xilinx/Vivado/2023.1/
source settings64.sh
cd $HOME
vivado -mode batch -source tcl_scripts/program_device_trigger_ila.tcl | tee program_device_trigger_ila.txt

# Define a workflow to orchestrate a job
workflows:
run-sim-syn-workflow:
jobs:
- run-sim-syn-job

The first new step Run Bitstream Generation runs through the synthesis, implementation and bitstream generation. Afterwards, Program Device and Trigger ILA will use that generated bitstream to program your device, trigger the ILA and capture the waveforms. You will also notice the new line resource_spec: large. This provides 16GB of memory which is needed for synthesis runs.

  output: 
artifact:
- ci_for_fpgas.sim/
- ci_for_fpgas.hw/
- ci_for_fpgas.runs/
- ci_for_fpgas.cache/
- iladata.ila

Finally, you also include some new folders that will allow you to access the files generated for this build, so the artifact output is also modified. You will also need the iladata.ila file to check the results of the testbench.

  1. Go back to BeetleboxCI and run the new pipeline. On the job page, it should be successful and show the following:

Getting started AMD FPGA Hardware 10

  1. On the job page, go the Artifacts tab and download the compressed folder that contains all the artifacts:

Getting started AMD FPGA Hardware 11

  1. In the downloaded folder, you should find iladata.ila. Go back to Vivado and open this file by clicking back onto the Hardware Manager and then going to File > Import Data > Import ILA Data. This should contain your waveforms that are successfully running a full adder:

Getting started AMD FPGA Hardware 12

Conclusion

Congratulations, you have reached the end of this tutorial on getting started with AMD (Xilinx) FPGA. In this series you have learned:

  • How to create a Vivado project and link it to a git repo.
  • How to run simulation through continuous integration.
  • How to use assertion statements to check for correctness in simulation.
  • How to run synthesis, implementation and bitstream generation through continuous integration.
  • How to trigger the ILA and extract the data through artifacts.

If you would like to learn more about BeetleboxCI please see our documentation or have a look at more of our tutorials.