Skip to main content

Getting started with BeeltleboxCI and Vivado: Simple Multiplexer

This is a tutorial designed to show to get started using BeetleboxCI and Vivado, in which we will cover the following:

  • Design - Setting up a Vivado project and make a multiplexer in VHLD
  • Simulate - Simulating this in Vivado by setting up a test bench
  • BeetleboxCI Integratation - Integrating our multiplexer and testbench with BeetleboxCI
  • Review - To finish we will compare the simulation results

The tutorial is designed not to be board specific. The accompanying git repository for this tutorial may be found here.

Overview

4x1-mux

Multiplexers are one of the most fundamental devices in digital design and are found in a large amount of different applications. Its simplistic design and near ubiquity makes it a great example for getting started with BeetleboxCI. A multiplexer selects one of several different input signalsi0-3 and uses that input as its outputbitout. The selection is based on a seperate input known as select or sel. Multiplexers may be represented as a logic table:

Sel1Sel0Output
00i0
01i1
10i2
11i3

In this tutorial, we will show how to get started with BeetleboxCI through designing a simple multiplexer. We will be focused on simulating it through running Vivado on BeetleboxCI. This tutorial is intended to show the strengths of CI even on a relativly simple design and we will demonstrate how we can iterate both the design and the test.

Tools we are using

  • Vivado: Vivado is Xilinx's synthesis and analysis tool for creating bitstreams to be placed onto our FPGA devices. Traditionally this has been centered around the use of HDL languages such as VHDL and Verilog, but the software also includes advanced features for system on chip development, design flow mangement and high level synthesis. Vivado may be installed as part of the Vitis (SW Developer) from Xilinx's website, which may be found here.
  • BeetleboxCI: BeetleboxCI is the Continuous Integration software specifically designed for FPGA design.
  • Github: Github is a git repository service that can be connected to BeetleboxCI to create an automated workflow.

Tested Environment

  • OS: Ubuntu 18.04
  • Vivado version: Vivado 2020.1
  • FPGA used: Zynq Ultrascale+ series ZCU104

Installation Guide:

Design

To create our multiplexer, we will be writing the design file in VHDL.

  1. Create a directory called workspace in the Vivado folder and change it to be the current working directory. Then we may launch Vivado. The following script assumes that Vivado was installed in the default directory. If it was not, then use the correct installation directory.
# Make workspace
cd /tools/Xilinx/Vivado/2020.1
mkdir workspace
cd /tools/Xilinx/Vivado/2020.1/workspace
source /tools/Xilinx/Vivado/2020.1/settings64.sh
vivado
  1. Create a new project

    1. Go to File->Project->New
    2. Name the project project_ci_sim, keep the same project location. In the next screen chose RTL project and click through until arriving at the Default Part screen.
    3. Select Boards and then search for the ZCU104 Evaluation Board
    4. Click finish
  2. Add VHDL file.

    1. To add our VHDL file, click the + button in the Sources tab.
    2. In the Add or Create Design Sources tab, click Create File and name it multiplexer4_1. Make sure it the VHDL File Type.
    3. Click OK on the pop ups. vivadoVHD
  3. Double click multiplexer4_1 in the Design Sources tab and copy in the following code:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity multiplexer4_1 is
port (
i0 : in std_logic;
i1 : in std_logic;
i2 : in std_logic;
i3 : in std_logic;
sel : in std_logic_vector(1 downto 0);
bitout : out std_logic
);
end multiplexer4_1;

architecture Behavioral of multiplexer4_1 is
begin

process(i0,i1,i2,i3,sel)
begin
case sel is
when "00" => bitout <= i0;
when "01" => bitout <= i1;
when "10" => bitout <= i2;
when others => bitout <= i3;
end case;
end process;

end Behavioral;

Our multiplexer has four input lines i0-i4, an input selection line sel and an output bitout. To implement the logic, we use a simple case statement to go through the possible values of sel. In each case, we assign a different input i0-i4, to the output bitout, creating our multiplexer.

Simulate

vivadosim 5. Now we have created our design, we will perform a simulation locally to ensure the correct behaviour before uploading to our Git Repository.

  1. In the Sources tab, right click Simulation Sources, then click Add Sources....
  2. In the Add Sources tab, click Add or create simulation sources.
  3. In the next window, click Create File and call it testbench, ensuring it is also a VHDL file. Then finish creating the file
  4. In the Sources tab, double click testbench then add the following code:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY testbench IS
END testbench;

ARCHITECTURE behavior OF testbench IS
SIGNAL i0,i1,i2,i3,bitout : std_logic:='0';
SIGNAL sel : std_logic_vector(1 downto 0):="00";
BEGIN
UUT : entity work.multiplexer4_1 port map(i0,i1,i2,i3,sel,bitout);

tb : PROCESS
BEGIN
i0<='1';
i1<='0';
i2<='1';
i3<='0';
sel <="00";
wait for 2 ns;
sel <="01";
wait for 2 ns;
sel <="10";
wait for 2 ns;
sel <="11";
wait for 2 ns;
--more input combinations can be given here.
END PROCESS tb;

END;

Our testbench works by importing our multiplexer as an entity. We then assign values to each one of the inputs i0-i4. Afterwards, we cycle through the various possible values of sel to observe how output has changed.

  1. In the Flow Navigator, click Run Simulation and Vivado will now display the the run simulation as shown below.

vivadosimdisplay

Running on BeetleboxCI

Now we have verified our multiplexer locally, we will integrate it with BeetleboxCI. Using BeetleboxCI will allow us to regularly iterate on the multiplexer, so any changes such as additional inputs or an enable signal can be automatically tested. It will also allow us to run simulations for long periods of time without using local computing resources, allowing us too focus on other parts of a system.

  1. Make a file in the project folder called sim.tcl and add the following code:
open_project ./project_ci_sim.xpr
set_property -name {xsim.simulate.log_all_signals} -value {true} -objects [get_filesets sim_1]
launch_simulation

sim.tcl is essentially a scripted version of the process we just ran manually. Scripting allows us to automate what we previously ran manually, allowing significant savings in development effort.

  1. Make a folder called .bbx in the same folder root directory and add a file called config.yaml with the following code:
runners:
example-runner:
image: ubuntu-vitis-2020-1

jobs:
build_run_sim:
runner: example-runner
type:
build: hardware
current_working_directory: /tools/Xilinx/Vivado/2020.1/workspace/project_ci_sim
output:
artifact:
- ./project_ci_sim.xpr
- ./project_ci_sim.cache
- ./project_ci_sim.hw
- ./project_ci_sim.ip_user_files
- ./project_ci_sim.sim
- ./project_ci_sim.srcs
steps:
- run:
name: Download files
command: |
source /tools/Xilinx/Vivado/2020.1/settings64.sh
vivado -mode tcl -source sim.tcl
type: miscellaneous
workflows:
complete-build-test:
jobs:
- build_run_sim

The .bbx/config.yaml is the configuration file that BeetleboxCI will use to automate this application. Each project in BeetleboxCI consists of a pipeline, which is made of different workflows. Workflows are a series of jobs that are to be executed are configurable by the user in the configuration file under the workflows section. These jobs are then specified under the jobsand in our case we have a single job called build_run_sim. We specify the runner to be used as example-runner, which uses the machine image ubuntu-vitis-2020-1. This machine image is specifically designed to run Vitis and Vivado tools.

We also specify that the type is a build:hardware. This is an optional setting, but can be use to help identify what the purpose of this build is. The current_working_directory is used to set the working directory that the build will start from. If it is not set, it will by default be ~/.

We then identify the artifacts that are to be stored in the artifact store. Finally, we provide the steps that the job is to perform. We need to run commands in a bash shell, so we use the run command step. We provide name and the individual commands to be run in our bash shell through command. vivado -mode tcl -source sim.tcl executes the Tcl file, we produced earlier on Vivado. Using workflows we are able to automate the entire simulation process, but we now need to execute this environment by committing it to Github and linking BeetleboxCI to it.

  1. We need to ensure that only source code is committed to our Github repository and not large build files. To do so, we make a .gitignore file in the project root directory and add the following code:
#########################################################################################################
## This is an example .gitignore file for Vivado, please treat it as an example as
## it might not be complete. In addition, XAPP 1165 should be followed.
#########################################################################################################
#########
#Exclude all
#########
*
!*/
!.gitignore
###########################################################################
## VIVADO
###########################################################################
#########
#Source files:
#########
#Do NOT ignore VHDL, Verilog, block diagrams or EDIF files.
!*.vhd
!*.v
!*.bd
!*.edif
#########
#IP files
#########
#.xci: synthesis and implemented not possible - you need to return back to the previous version to generate output products
#.xci + .dcp: implementation possible but not re-synthesis
#*.xci(www.spiritconsortium.org)
!*.xci
#*.dcp(checkpoint files)
!*.dcp
!*.vds
!*.pb
#All bd comments and layout coordinates are stored within .ui
!*.ui
!*.ooc
#########
#System Generator
#########
!*.mdl
!*.slx
!*.bxml
#########
#Simulation logic analyzer
#########
!*.wcfg
!*.coe
#########
#MIG
#########
!*.prj
!*.mem
#########
#Project files
#########
#XPR + *.XML ? XPR (Files are merged into a single XPR file for 2014.1 version)
#Do NOT ignore *.xpr files
!*.xpr
#Include *.xml files for 2013.4 or earlier version
!*.xml
#########
#Constraint files
#########
#Do NOT ignore *.xdc files
!*.xdc
#########
#TCL - files
#########
!*.tcl
#########
#Journal - files
#########
!*.jou
#########
#Reports
#########
!*.rpt
!*.txt
!*.vdi
#########
#C-files
#########
!*.c
!*.h
!*.elf
!*.bmm
!*.xmp
  1. Create a new Github Repository. Name the repository project_ci_sim.
  2. Now log into your BeetleboxCI web application which you have already installed.
  3. You will see the following screen, click Add Project beetleboxci
  4. Fill in the details for the project name, URL, and the Login details and click Submit.
  5. To run the pipeline on the CI, we must go into the pipeline and click the run button on the top right of the Workflows list.
  1. When the build has finished in the CI navigate to the artifacts window and download the artifact using the cloud button as shown below.

cicloud

Viewing our waveforms

Now that we have run our waveforms, we can view them through Vivado.

  1. Extract the downloaded zip file into a folder.
  2. Open Vivado and then select open project and open the .xpr file in the extracted folder.
  3. Now click Flow in the top ribbon then click Open Static Simulation.
  4. From here locate the file testbench_behav.wdb, which should be in the project_ci_sim.sim/sim_1/behav/xsim folder.
  5. In the scope folder, right click on the testbench and select Add to wave window. This will display the waveforms run on the CI.

Editing our testbench

One of the major components of Continuous Integration is to make incremental changes that can then be continuously built and tested. To show an example of this, we will make a small change to our testbench and view the resulting waveform.