Bar
SpaceWire UK
Specialist providers of VHDL Intellectual Property & Design Services
BarBarBarBar
Tutorial
Missing Image!
Part 23 - Create a cascading Video TPG design for VGA output

Introduction

This tutorial details the steps required to create an overlaying video TPG design using Vivado. The video output will be delivered via the VGA port on the Zedboard. The tutorial covers quite a range of activities and includes the use of numerous languages; TCL, Verilog, System Verilog & shell scripting. TCL will be used extensively to add elements to an existing Block Design and wire them up.

Note: Everywhere there is a text edit command (subl) there will be a wget below it to fast track the process.

Aims

The aims of this tutorial are as follows :-

    Part 1 - Setup environment

    1. Pre-requisites

    Part 2 - Firmware Development - 1

    1. Create a new firmware project
    2. Open block design
    3. Add video logic to block design
    4. Edit product identification
    5. Edit HDL wrapper
    6. Edit pin constraints

    Part 3 - Revision Control - 1

    1. Commit new & updated files

    Part 4 - Firmware Development - 2

    1. Create production release
    2. Archive build files for later retrieval

    Part 5 - Hardware Deployment

    1. Create a loadable binary from a bitstream & upload to the SD-Card
    2. Check everything is working as expected

    Part 6 - Revision Control - 2

    1. Block design vs. scripted options
    2. Final checks (BD build)
    #### Part 1 - Setup environment ####

    1. Pre-requisites

    Starting from this point is possible but requires a few pre-requisites.
    #### Part 2 - Firmware Development - 1 ####

    2. Create a new firmware project

    Create a brand new baseline project that can be expanded upon to include the new features required.
    steve@Desktop:~$ cd ${swuk_tutorial}
    steve@Desktop:~/swuk_tutorial$ swuk_create_project zedboard_video_tpg_vga --baseline
    Enter details for the header blocks...
    File .......... zedboard_video_tpg_hdmi
    Author ........ Steve Haywood
    Company ....... SpaceWire UK
    Website ....... http://www.spacewire.co.uk
    Project ....... Zedboard Video TPG VGA
    Tutorial ...... SpaceWire UK Tutorial
    Date .......... 9 Feb 2026
    Version ....... 1.0
    Creating project directory structure...
    Creating baseline project...
    steve@Desktop:~/swuk_tutorial$ cd zedboard_video_tpg_vga
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ swuk_create_vivado_project
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ cd ..
    

    3. Open block design

    Take a peek at the baseline block design by clicking on Open Block Design under IP INTEGRATOR. Get a better view of the Block Design by clicking on its Float Missing Image! icon. Resize the canvas to obtain a better view of the design and click on the Regenerate Layout Missing Image! icon to obtain a better layout. Missing Image!

    4. Add video logic to block design

    Instead of poking around on the Block Design a TCL script will be used to make the changes required. The commands used in the script are simply the ones Vivado displays in the Tcl Console when things are changed in the GUI.

    If it is more desirable to edit the Block Design manually then use the comments in the script to assist with the process.

    Changes required to existing IP & RTL blocks (brief) :- Additional IP & RTL blocks required :- Changes required to existing IP & RTL blocks (more detail) :-

    Step 1 - To add VGA video capability to the existing design the following Xilinx IP components are required. Step 2 - The following two additions are to add indicators on the top two LEDs to show Video Locked & Video Clock. Step 3 - Some of the new additions need customisation. Step 4 - Add an extra two ports on the Interconnect to deal with the new Test Pattern Generators.

    Step 5 - Add the newly required external I/O. Step 6 - Create port connections. Step 7 - Create interface connections. Step 8 - Create address segments. Create the additions script.
    steve@Desktop:~/swuk_tutorial$ subl zedboard_video_tpg_vga/fw/src/script/user_update_system_bd.tcl
    

    user_update_system_bd.tcl

    #
    # File .......... user_update_system_bd.tcl
    # Author ........ Steve Haywood
    # Website ....... http://www.spacewire.co.uk
    # Project ....... Zedboard Video TPG VGA (SpaceWire UK Tutorial)
    # Date .......... 17 Nov 2025
    # Version ....... 1.0
    # Description ...
    #   Add & connect up extra blocks on the baseline top-level block design for
    # the Zedboard. This script adds the required elements to create a cascading
    # video test pattern generator example design with VGA output.
    #
    
    
    #############################################################################
    # Set block design path
    
    set dir_user        "../src"
    set dir_diagram     "$dir_user/diagram"
    
    
    #############################################################################
    # Get block design name from script filename (xxx_xxx_yyy_xxx.tcl = yyy)
    
    set whoami [file normalize [info script]]
    set fbasename [file rootname [file tail $whoami]]
    set parts [split $fbasename "_"]
    set bdname [lindex $parts 2]
    
    
    ###################
    # Open block design
    
    open_bd_design project.srcs/sources_1/bd/$bdname/$bdname.bd
    
    
    #######################################
    # Adjust existing common design to suit
    
    # - Constant
    #   - Remove from BD
    
    delete_bd_objs [get_bd_nets xlconstant_0_dout] [get_bd_cells xlconstant_0]
    
    # - AXI GPIO ZED
    #   - Set 'C Leds Mask' to "11000000"
    
    set_property CONFIG.c_leds_mask {"11000000"} [get_bd_cells axi_gpio_zed_0]
    
    # - AXI Interconnect
    #   - Set 'Number of Master Interfaces' to 5
    
    set_property CONFIG.NUM_MI {5} [get_bd_cells axi_interconnect_0]
    
    
    ###################################
    # Create instances & set properties
    
    # - Clocking Wizard
    #   - Output Clocks
    #     - Set 'clk_out1' frequency to 148.5 MHz
    #     - Unset 'Reset'
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:clk_wiz:6.0 clk_wiz_0
    set_property -dict [list \
      CONFIG.CLKOUT1_JITTER {217.614} \
      CONFIG.CLKOUT1_PHASE_ERROR {245.344} \
      CONFIG.CLKOUT1_REQUESTED_OUT_FREQ {148.5} \
      CONFIG.MMCM_CLKFBOUT_MULT_F {37.125} \
      CONFIG.MMCM_CLKOUT0_DIVIDE_F {6.250} \
      CONFIG.MMCM_DIVCLK_DIVIDE {4} \
      CONFIG.USE_RESET {false} \
    ] [get_bd_cells clk_wiz_0]
    
    # - Processor System Reset
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:proc_sys_reset:5.0 proc_sys_reset_1
    
    # - Video Test Pattern Generator 0
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:v_tpg:8.2 v_tpg_0
    
    # - Video Test Pattern Generator 1
    #   - Enable 'HAS AXI4S SLAVE'
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:v_tpg:8.2 v_tpg_1
    set_property CONFIG.HAS_AXI4S_SLAVE {1} [get_bd_cells v_tpg_1]
    
    # - Video Timing Controller
    #   - Optional Features
    #     - Disable 'Include AXI4-Lite Interface'
    #   - Detection/Generation
    #     - Disable 'Enable Detection'
    #   - Default/Constant
    #     - Set 'Video Mode' to 1080p
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:v_tc:6.2 v_tc_0
    set_property -dict [list \
      CONFIG.HAS_AXI4_LITE {false} \
      CONFIG.VIDEO_MODE {1080p} \
      CONFIG.enable_detection {false} \
    ] [get_bd_cells v_tc_0]
    
    # - AXI4-Stream to Video Out
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:v_axi4s_vid_out:4.0 v_axi4s_vid_out_0
    
    # - Concat
    #   - Set 'Number of Ports' to 8
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:xlconcat:2.1 xlconcat_0
    set_property CONFIG.NUM_PORTS {8} [get_bd_cells xlconcat_0]
    
    # - Heartbeat
    #   - Set 'C Clk Freq' to 148500000
    
    create_bd_cell -type module -reference heartbeat heartbeat_0
    set_property CONFIG.c_clk_freq {148500000} [get_bd_cells heartbeat_0]
    
    # - Slice (Red)
    #   - Set 'Component Name' to slice_r
    #   - Set 'Din Width' to 24
    #   - Set 'Din From' to 7
    #   - Set 'Din Down To' to 4
    #   - Set 'Dout Width' to 4
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 xlslice_r
    set_property -dict \
    [list \
      CONFIG.DIN_WIDTH {24} \
      CONFIG.DIN_FROM {7} \
      CONFIG.DIN_TO {4} \
      CONFIG.DOUT_WIDTH {4} \
    ] [get_bd_cells xlslice_r]
    
    # - Slice (Green)
    #   - Set 'Component Name' to slice_g
    #   - Set 'Din Width' to 24
    #   - Set 'Din From' to 15
    #   - Set 'Din Down To' to 12
    #   - Set 'Dout Width' to 4
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 xlslice_g
    set_property -dict \
    [list \
    CONFIG.DIN_WIDTH {24} \
      CONFIG.DIN_FROM {15} \
      CONFIG.DIN_TO {12} \
      CONFIG.DOUT_WIDTH {4} \
    ] [get_bd_cells xlslice_g]
    
    # - Slice (Blue)
    #   - Set 'Component Name' to slice_b
    #   - Set 'Din Width' to 24
    #   - Set 'Din From' to 23
    #   - Set 'Din Down To' to 20
    #   - Set 'Dout Width' to 4
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:xlslice:1.0 xlslice_b
    set_property -dict \
    [list \
      CONFIG.DIN_WIDTH {24} \
      CONFIG.DIN_FROM {23} \
      CONFIG.DIN_TO {20} \
      CONFIG.DOUT_WIDTH {4} \
    ] [get_bd_cells xlslice_b]
    
    
    ##############################
    # Create interface connections
    
    connect_bd_intf_net -boundary_type upper [get_bd_intf_pins axi_interconnect_0/M03_AXI] [get_bd_intf_pins v_tpg_0/s_axi_CTRL]
    connect_bd_intf_net -boundary_type upper [get_bd_intf_pins axi_interconnect_0/M04_AXI] [get_bd_intf_pins v_tpg_1/s_axi_CTRL]
    connect_bd_intf_net [get_bd_intf_pins v_tpg_0/m_axis_video] [get_bd_intf_pins v_tpg_1/s_axis_video]
    connect_bd_intf_net [get_bd_intf_pins v_tpg_1/m_axis_video] [get_bd_intf_pins v_axi4s_vid_out_0/video_in]
    connect_bd_intf_net [get_bd_intf_pins v_tc_0/vtiming_out] [get_bd_intf_pins v_axi4s_vid_out_0/vtiming_in]
    
    
    #########################
    # Create port connections
    
    make_bd_pins_external  [get_bd_pins clk_wiz_0/clk_in1]
    set_property name sys_clock [get_bd_ports clk_in1_0]
    
    make_bd_pins_external  [get_bd_pins xlslice_r/Dout]
    set_property name vid_data_r [get_bd_ports Dout_0]
    
    make_bd_pins_external  [get_bd_pins xlslice_g/Dout]
    set_property name vid_data_g [get_bd_ports Dout_0]
    
    make_bd_pins_external  [get_bd_pins xlslice_b/Dout]
    set_property name vid_data_b [get_bd_ports Dout_0]
    
    connect_bd_net [get_bd_pins v_axi4s_vid_out_0/vid_data] \
      [get_bd_pins xlslice_r/Din] \
      [get_bd_pins xlslice_g/Din] \
      [get_bd_pins xlslice_b/Din]
    
    make_bd_pins_external  [get_bd_pins v_axi4s_vid_out_0/vid_hsync]
    set_property name vid_hsync [get_bd_ports vid_hsync_0]
    
    make_bd_pins_external  [get_bd_pins v_axi4s_vid_out_0/vid_vsync]
    set_property name vid_vsync [get_bd_ports vid_vsync_0]
    
    connect_bd_net [get_bd_pins heartbeat_0/beat] [get_bd_pins xlconcat_0/In6]
    connect_bd_net [get_bd_pins v_axi4s_vid_out_0/locked] [get_bd_pins xlconcat_0/In7]
    connect_bd_net [get_bd_pins xlconcat_0/dout] [get_bd_pins axi_gpio_zed_0/leds_in]
    
    connect_bd_net [get_bd_pins clk_wiz_0/clk_out1] \
      [get_bd_pins axi_interconnect_0/M03_ACLK] \
      [get_bd_pins axi_interconnect_0/M04_ACLK] \
      [get_bd_pins heartbeat_0/aclk] \
      [get_bd_pins proc_sys_reset_1/slowest_sync_clk] \
      [get_bd_pins v_axi4s_vid_out_0/aclk] \
      [get_bd_pins v_tc_0/clk] \
      [get_bd_pins v_tpg_0/ap_clk] \
      [get_bd_pins v_tpg_1/ap_clk]
    
    connect_bd_net [get_bd_pins proc_sys_reset_1/peripheral_aresetn] \
      [get_bd_pins axi_interconnect_0/M03_ARESETN] \
      [get_bd_pins axi_interconnect_0/M04_ARESETN] \
      [get_bd_pins heartbeat_0/aresetn] \
      [get_bd_pins v_axi4s_vid_out_0/aresetn] \
      [get_bd_pins v_tc_0/resetn] \
      [get_bd_pins v_tpg_0/ap_rst_n] \
      [get_bd_pins v_tpg_1/ap_rst_n]
    
    connect_bd_net [get_bd_pins clk_wiz_0/locked] [get_bd_pins proc_sys_reset_1/ext_reset_in]
    
    connect_bd_net [get_bd_pins v_axi4s_vid_out_0/vtg_ce] [get_bd_pins v_tc_0/gen_clken]
    
    
    #########################
    # Create address segments
    
    assign_bd_address -offset 0x40030000 -range 0x00010000 -target_address_space [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs v_tpg_0/s_axi_CTRL/Reg] -force
    assign_bd_address -offset 0x40040000 -range 0x00010000 -target_address_space [get_bd_addr_spaces processing_system7_0/Data] [get_bd_addr_segs v_tpg_1/s_axi_CTRL/Reg] -force
    
    
    #################################################
    # Regenerate, validate, save & close block design
    
    #regenerate_bd_layout
    validate_bd_design
    save_bd_design
    #close_bd_design $bdname
    
    Direct download available here :-
    steve@Desktop:~/swuk_tutorial$ wget https://spacewire.co.uk/tutorial/shared/repos/0029/zedboard_video_tpg_vga/fw/src/script/user_update_system_bd.tcl -O zedboard_video_tpg_vga/fw/src/script/user_update_system_bd.tcl
    
    Run the script from the Tcl Console.
    source ../src/script/user_update_system_bd.tcl
    Resize the canvas to obtain a better view of the design and click on the Regenerate Layout Missing Image! icon to obtain a better layout.

    Behold the cascading video test pattern example design. Missing Image!

    5. Edit product identification

    Edit the product identification file.
    steve@Desktop:~/swuk_tutorial$ subl zedboard_video_tpg_vga/fw/project.txt
    

    project.txt

    Zedboard Video TPG VGA
    SpaceWire UK
    Steve Haywood
    1.0
    
    Direct download available here :-
    steve@Desktop:~/swuk_tutorial$ wget https://spacewire.co.uk/tutorial/shared/repos/0029/zedboard_video_tpg_vga/fw/project.txt -O zedboard_video_tpg_vga/fw/project.txt
    

    6. Edit HDL wrapper

    Edit the top-level wrapper for the block design to add the Board Clock & VGA Video connections.
    steve@Desktop:~/swuk_tutorial$ subl zedboard_video_tpg_vga/fw/src/design/zedboard_video_tpg_vga.sv
    

    zedboard_video_tpg_vga.sv

    //
    // File .......... zedboard_video_tpg_vga.sv
    // Author ........ Steve Haywood
    // Website ....... http://www.spacewire.co.uk
    // Project ....... Zedboard Video TPG VGA (SpaceWire UK Tutorial)
    // Date .......... 17 Nov 2025
    // Version ....... 1.0
    // Description ...
    //   Top level wrapper for the system block design.
    //
    
    
    timeunit      1ns;
    timeprecision 1ps;
    
    
    module zedboard_video_tpg_vga #
    (
      // Parameters
      parameter string id_description = "",  // P:Description ............ Max 128 Characters
      parameter string id_company     = "",  // P:Company ................ Max  64 Characters
      parameter string id_author      = "",  // P:Author ................. Max  64 Characters
      parameter string id_version     = "",  // P:Version ................ Max  32 Characters
      parameter string id_timestamp   = "",  // P:Timestamp .............. Max  32 Characters
      parameter string id_hash        = ""   // P:Hash ................... Max  64 Characters
    )
    (
      // Board Clock (100MHz)
      input         sys_clock,          // I:Clock
      // LEDs
      output [ 7:0] leds,               // O:LEDs
      // DIP Switches
      input  [ 7:0] switches,           // I:DIP Switches
      // Push Buttons
      input  [ 4:0] buttons,            // I:Push Buttons
      // VGA
      output [ 3:0] vid_data_r,         // O:Red Component
      output [ 3:0] vid_data_g,         // O:Green Component
      output [ 3:0] vid_data_b,         // O:Blue Component
      output        vid_hsync,          // O:Horizontal Sync
      output        vid_vsync,          // O:Vertical Sync
      // System
      inout  [14:0] DDR_addr,           // B:Address
      inout  [ 2:0] DDR_ba,             // B:Bank Address
      inout         DDR_cas_n,          // B:Column Address Select
      inout         DDR_ck_n,           // B:Clock (Neg)
      inout         DDR_ck_p,           // B:Clock (Pos)
      inout         DDR_cke,            // B:Clock Enable
      inout         DDR_cs_n,           // B:Chip Select
      inout  [ 3:0] DDR_dm,             // B:Data Mask
      inout  [31:0] DDR_dq,             // B:Data Input/Output
      inout  [ 3:0] DDR_dqs_n,          // B:Data Strobe (Neg)
      inout  [ 3:0] DDR_dqs_p,          // B:Data Strobe (Pos)
      inout         DDR_odt,            // B:Output Dynamic Termination
      inout         DDR_ras_n,          // B:Row Address Select
      inout         DDR_reset_n,        // B:Reset
      inout         DDR_we_n,           // B:Write Enable
      inout         FIXED_IO_ddr_vrn,   // B:Termination Voltage
      inout         FIXED_IO_ddr_vrp,   // B:Termination Voltage
      inout  [53:0] FIXED_IO_mio,       // B:Peripheral Input/Output
      inout         FIXED_IO_ps_clk,    // B:System Reference Clock
      inout         FIXED_IO_ps_porb,   // B:Power On Reset
      inout         FIXED_IO_ps_srstb   // B:External System Reset
    );
    
    
      // Function to convert a string to a vector (max 128 characters)
      function automatic [1023:0] fmt(input string str);
        int len;
        bit [1023:0] tmp;
        len = str.len();
        for (int i=0; i<len; i++)
          tmp[8*i +: 8] = str.getc(i);
        fmt = tmp;
      endfunction
    
    
      // Top-Level Block Design
      system system_i
       (
        // Identification Strings
        .id_description    ( fmt(id_description) ),  // P:Description
        .id_company        ( fmt(id_company)     ),  // P:Company
        .id_author         ( fmt(id_author)      ),  // P:Author
        .id_version        ( fmt(id_version)     ),  // P:Version
        .id_timestamp      ( fmt(id_timestamp)   ),  // P:Timestamp
        .id_hash           ( fmt(id_hash)        ),  // P:Hash
        // Board Clock
        .sys_clock         ( sys_clock           ),  // I:Clock
        // LEDs
        .leds              ( leds                ),  // O:LEDs
        // DIP Switches
        .switches          ( switches            ),  // I:DIP Switches
        // Push Buttons
        .buttons           ( buttons             ),  // I:Push Buttons
        // VGA
        .vid_data_r        ( vid_data_r          ),  // O:Red Component
        .vid_data_g        ( vid_data_g          ),  // O:Green Component
        .vid_data_b        ( vid_data_b          ),  // O:Blue Component
        .vid_hsync         ( vid_hsync           ),  // O:Horizontal Sync
        .vid_vsync         ( vid_vsync           ),  // O:Vertical Sync
        // System
        .DDR_addr          ( DDR_addr            ),  // B:Address
        .DDR_ba            ( DDR_ba              ),  // B:Bank Address
        .DDR_cas_n         ( DDR_cas_n           ),  // B:Column Address Select
        .DDR_ck_n          ( DDR_ck_n            ),  // B:Clock (Neg)
        .DDR_ck_p          ( DDR_ck_p            ),  // B:Clock (Pos)
        .DDR_cke           ( DDR_cke             ),  // B:Clock Enable
        .DDR_cs_n          ( DDR_cs_n            ),  // B:Chip Select
        .DDR_dm            ( DDR_dm              ),  // B:Data Mask
        .DDR_dq            ( DDR_dq              ),  // B:Data Input/Output
        .DDR_dqs_n         ( DDR_dqs_n           ),  // B:Data Strobe (Neg)
        .DDR_dqs_p         ( DDR_dqs_p           ),  // B:Data Strobe (Pos)
        .DDR_odt           ( DDR_odt             ),  // B:Output Dynamic Termination
        .DDR_ras_n         ( DDR_ras_n           ),  // B:Row Address Select
        .DDR_reset_n       ( DDR_reset_n         ),  // B:Reset
        .DDR_we_n          ( DDR_we_n            ),  // B:Write Enable
        .FIXED_IO_ddr_vrn  ( FIXED_IO_ddr_vrn    ),  // B:Termination Voltage
        .FIXED_IO_ddr_vrp  ( FIXED_IO_ddr_vrp    ),  // B:Termination Voltage
        .FIXED_IO_mio      ( FIXED_IO_mio        ),  // B:Peripheral Input/Output
        .FIXED_IO_ps_clk   ( FIXED_IO_ps_clk     ),  // B:System Reference Clock
        .FIXED_IO_ps_porb  ( FIXED_IO_ps_porb    ),  // B:Power On Reset
        .FIXED_IO_ps_srstb ( FIXED_IO_ps_srstb   )   // B:External System Reset
       );
    
    
    endmodule
    
    Direct download available here :-
    steve@Desktop:~/swuk_tutorial$ wget https://spacewire.co.uk/tutorial/shared/repos/0029/zedboard_video_tpg_vga/fw/src/design/zedboard_video_tpg_vga.sv -O zedboard_video_tpg_vga/fw/src/design/zedboard_video_tpg_vga.sv
    

    7. Edit pin constraints

    Edit the pin constraints to add the Board Clock & VGA Video connections.
    steve@Desktop:~/swuk_tutorial$ subl zedboard_video_tpg_vga/fw/src/constraint/zedboard_video_tpg_vga.xdc
    

    zedboard_video_tpg_vga.xdc

    #
    # File .......... zedboard_video_tpg_vga.xdc
    # Author ........ Steve Haywood
    # Website ....... http://www.spacewire.co.uk
    # Project ....... Zedboard Video TPG VGA (SpaceWire UK Tutorial)
    # Date .......... 17 Nov 2025
    # Version ....... 1.0
    # Description ...
    #   Top level pin & timing constraints.
    #
    
    
    # Clock Source - Bank 13
    set_property PACKAGE_PIN Y9 [get_ports {sys_clock}];  # "GCLK"
    
    
    # User LEDs - Bank 33
    set_property PACKAGE_PIN T22 [get_ports {leds[0]}];  # "LD0"
    set_property PACKAGE_PIN T21 [get_ports {leds[1]}];  # "LD1"
    set_property PACKAGE_PIN U22 [get_ports {leds[2]}];  # "LD2"
    set_property PACKAGE_PIN U21 [get_ports {leds[3]}];  # "LD3"
    set_property PACKAGE_PIN V22 [get_ports {leds[4]}];  # "LD4"
    set_property PACKAGE_PIN W22 [get_ports {leds[5]}];  # "LD5"
    set_property PACKAGE_PIN U19 [get_ports {leds[6]}];  # "LD6"
    set_property PACKAGE_PIN U14 [get_ports {leds[7]}];  # "LD7"
    
    
    # VGA Output - Bank 33
    set_property PACKAGE_PIN Y21  [get_ports {vid_data_b[0]}];  # "VGA-B1"
    set_property PACKAGE_PIN Y20  [get_ports {vid_data_b[1]}];  # "VGA-B2"
    set_property PACKAGE_PIN AB20 [get_ports {vid_data_b[2]}];  # "VGA-B3"
    set_property PACKAGE_PIN AB19 [get_ports {vid_data_b[3]}];  # "VGA-B4"
    set_property PACKAGE_PIN AB22 [get_ports {vid_data_g[0]}];  # "VGA-G1"
    set_property PACKAGE_PIN AA22 [get_ports {vid_data_g[1]}];  # "VGA-G2"
    set_property PACKAGE_PIN AB21 [get_ports {vid_data_g[2]}];  # "VGA-G3"
    set_property PACKAGE_PIN AA21 [get_ports {vid_data_g[3]}];  # "VGA-G4"
    set_property PACKAGE_PIN AA19 [get_ports {vid_hsync}];      # "VGA-HS"
    set_property PACKAGE_PIN V20  [get_ports {vid_data_r[0]}];  # "VGA-R1"
    set_property PACKAGE_PIN U20  [get_ports {vid_data_r[1]}];  # "VGA-R2"
    set_property PACKAGE_PIN V19  [get_ports {vid_data_r[2]}];  # "VGA-R3"
    set_property PACKAGE_PIN V18  [get_ports {vid_data_r[3]}];  # "VGA-R4"
    set_property PACKAGE_PIN Y19  [get_ports {vid_vsync}];      # "VGA-VS"
    
    
    # User Push Buttons - Bank 34
    set_property PACKAGE_PIN P16 [get_ports {buttons[0]}];  # "BTNC"
    set_property PACKAGE_PIN R16 [get_ports {buttons[1]}];  # "BTND"
    set_property PACKAGE_PIN N15 [get_ports {buttons[2]}];  # "BTNL"
    set_property PACKAGE_PIN R18 [get_ports {buttons[3]}];  # "BTNR"
    set_property PACKAGE_PIN T18 [get_ports {buttons[4]}];  # "BTNU"
    
    
    # User DIP Switches - Bank 34 & 35
    set_property PACKAGE_PIN F22 [get_ports {switches[0]}];  # "SW0"
    set_property PACKAGE_PIN G22 [get_ports {switches[1]}];  # "SW1"
    set_property PACKAGE_PIN H22 [get_ports {switches[2]}];  # "SW2"
    set_property PACKAGE_PIN F21 [get_ports {switches[3]}];  # "SW3"
    set_property PACKAGE_PIN H19 [get_ports {switches[4]}];  # "SW4"
    set_property PACKAGE_PIN H18 [get_ports {switches[5]}];  # "SW5"
    set_property PACKAGE_PIN H17 [get_ports {switches[6]}];  # "SW6"
    set_property PACKAGE_PIN M15 [get_ports {switches[7]}];  # "SW7"
    
    
    # Banks
    set_property IOSTANDARD LVCMOS33 [get_ports -of_objects [get_iobanks 13]];
    set_property IOSTANDARD LVCMOS33 [get_ports -of_objects [get_iobanks 33]];
    set_property IOSTANDARD LVCMOS18 [get_ports -of_objects [get_iobanks 34]];
    set_property IOSTANDARD LVCMOS18 [get_ports -of_objects [get_iobanks 35]];
    
    
    # False Paths
    set_false_path -to [get_pins {system_i/axi_gpio_zed_0/inst/leds_meta_reg[*]/D}]
    
    Direct download available here :-
    steve@Desktop:~/swuk_tutorial$ wget https://spacewire.co.uk/tutorial/shared/repos/0029/zedboard_video_tpg_vga/fw/src/constraint/zedboard_video_tpg_vga.xdc -O zedboard_video_tpg_vga/fw/src/constraint/zedboard_video_tpg_vga.xdc
    
    #### Part 3 - Revision Control - 1 ####

    8. Commit new & updated files

    Check GIT status to make sure all is well and there are no spurious elements.
    steve@Desktop:~/swuk_tutorial$ git status -u
    On branch my_master
    Your branch is up-to-date with 'origin/my_master'.
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
            zedboard_video_tpg_vga/.gitignore      
            zedboard_video_tpg_vga/fw/project.txt      
            zedboard_video_tpg_vga/fw/src/constraint/zedboard_video_tpg_vga.xdc      
            zedboard_video_tpg_vga/fw/src/design/zedboard_video_tpg_vga.sv      
            zedboard_video_tpg_vga/fw/src/script/user_update_system_bd.tcl      
    
    nothing added to commit but untracked files present (use "git add" to track)
    
    Looks good! Commit the updates, create an annotated tag and push the commit & tag up to the remote repository.
    steve@Desktop:~/swuk_tutorial$ git add -A
    steve@Desktop:~/swuk_tutorial$ git commit -a -m "Basic Zedboard design consisting of a ZYNQ7 Processing System controlling a pair of cascading Test Pattern Generators that output video via VGA."
    steve@Desktop:~/swuk_tutorial$ git push
    steve@Desktop:~/swuk_tutorial$ git tag -a my_zedboard_video_tpg_vga_v1.0 -m "ZYNQ & Cascading TPG's with VGA output"
    steve@Desktop:~/swuk_tutorial$ git push origin my_zedboard_video_tpg_vga_v1.0
    
    #### Part 4 - Firmware Development - 2 ####

    9. Create production release

    Create a potential production release for the Zedboard Video TPG VGA (v1.0) project using pure repository source.

    Close Vivado.

    Clear out all the superfluous files from the project area (non-tracked files).
    steve@Desktop:~/swuk_tutorial$ cd zedboard_video_tpg_vga
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ rm -rf fw/vivado
    
    Double check GIT status.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ git status -u
    On branch master
    Your branch is up-to-date with 'origin/master'.
    
    nothing to commit, working tree clean
    
    Build the design from clean repository source.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ swuk_create_vivado_project --build
    

    10. Archive build files for later retrieval

    Archive the generated hardware platform & bitstream for safe keeping. These files are not held in the repository as they can be recreated from source.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ cp fw/vivado/system_wrapper.xsa ${swuk_user}/hardware/zedboard_video_tpg_vga_v1.0.xsa
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ cp fw/vivado/zedboard_video_tpg_vga.runs/impl_1/zedboard_video_tpg_vga.bit ${swuk_user}/firmware/zedboard_video_tpg_vga_v1.0.bit
    
    #### Part 5 - Hardware Deployment ####

    11. Create a loadable binary from a bitstream & upload to the SD-Card

    Execute the following script to create the binary file and upload it to the Zedboard. Select 8.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ swuk_upload_bin ${swuk_zedboard_ip}
    
    Bitstream files @ fw/vivado/zedboard_video_tpg_vga.runs/impl_1 :-
    
    0) - zedboard_video_tpg_vga.bit
    
    Bitstream files @ /home/steve/Documents/swuk_tutorial/firmware :-
    
    1) - zedboard_hello_world_v1.0.bit
    2) - zedboard_leds_buttons_v1.0.bit
    3) - zedboard_leds_switches_v1.0.bit
    4) - zedboard_leds_switches_v2.0.bit
    5) - zedboard_leds_switches_v3.0.bit
    6) - zedboard_leds_switches_v4.0.bit
    7) - zedboard_leds_switches_v5.0.bit
    8) - zedboard_video_tpg_vga_v1.0.bit
    
    q) Quit
    
    Select bin file for upload or exit : 8
    
    Uploaded zedboard_video_tpg_vga_v1.0.bin to /media/sd-mmcblk0p1/firmware @ 192.168.2.87.
    

    12. Check everything is working as expected

    Access the webserver running on the Zedboard using a browser pointing at the Zedboard's IP address (192.168.2.87). Select System from the menu bar.

    The Operating System Information table should show Zedboard PetaLinux Example Design description along with a version of 14.0.

    The Firmare Information table should show Zedboard LEDs & Switches Example Design description along with a version of 5.0.

    In the Loadable Firmware table click on Load next to the newly uploaded binary to load the new firmware into the PL. Missing Image! The Firmare Information table should now show the new Zedboard Video TPG VGA Example Design description along with a version of 1.0.

    There should be no unsavoury comments after the version numbers! Missing Image! The Timestamp & Hash shown from GIT should marry up perfectly with the Firmware Information.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ git log -1
    commit a6212153bd0a72eec48c0b132f31a2ee8478ec73 (HEAD -> my_master, tag: my_zedboard_video_tpg_vga_v1.0, origin/my_master)
    Author: Steve Haywood <steve@spacewire.co.uk>
    Date:   Mon Jan 26 11:31:45 2026 +0000
    
        Basic Zedboard design consisting of a ZYNQ7 Processing System controlling a pair of cascading Test Pattern Generators that output video via VGA.
    
    To get some video out of the Zedboard's VGA connector the two TPG's need to be configured and enabled. Lets aim for a colour bar background with two moving box overlays, one green and one blue.

    Test Pattern Generator 1 Test Pattern Generator 2 There are quite a lot of registers that need to be configured for the above setup to work. Many ways to go about this, a shell script or compiled C running on PetaLinux for example. For an opening gambit a simple Peek & Poke Addresses configuration file will be created. Although this looks a little involved it is simply a list of address locations with default values associated. The widgets add a little complication but the effort is worth it in the end as it makes the bit-bashing very much more user friendly.
    steve@Desktop:~/swuk_tutorial$ subl ${swuk_user}/configuration/zedboard_video_tpg_vga.txt
    

    zedboard_video_tpg_vga.txt

    sec|Test Pattern Generator 0
    reg|0x40030010|false|true|1080|true|Active Height
    reg|0x40030018|false|true|1920|true|Active Width
    select|0x40030040|false|true|0#0^RGB#1^YUV 444#2^YUV 422#3^YUV 420|true|Color Format
    select|0x40030020|false|true|9#0^Pass through#1^Horizontal Ramp#2^Vertical Ramp#3^Temporal Ramp#4^Solid red#5^Solid green#6^Solid blue#7^Solid black#8^Solid white#9^Color bars#10^Zone Plate#11^Tartan Color Bars#12^Cross hatch pattern#13^Color sweep pattern#14^Combined V & H ramp#15^B & W checker board#16^Pseudorandom pattern#17^DP color ramp#18^DP B & W vertical lines#19^DP color square|true|Background Pattern ID
    reg|0x40030000|true|true|0x81|true|Control
    range|0x40030078|false|true|256#0#511|true|Box Size
    range|0x40030088|false|true|0#0#255|true|Box Color (Red)
    range|0x40030090|false|true|180#0#255|true|Box Color (Green)
    range|0x40030080|false|true|0#0#255|true|Box Color (Blue)
    range|0x40030038|false|true|10#0#31|true|Motion Speed
    select|0x40030028|false|true|1#0^No overlay#1^Moving box#2^Cross hairs|true|Forground Pattern ID
    range|0x40030048|false|true|960#0#1919|true|Cross hair horizontal
    range|0x40030050|false|true|540#0#1079|true|Cross hair vertical
    
    sec|Test Pattern Generator 1
    reg|0x40040010|false|true|1080|true|Active Height
    reg|0x40040018|false|true|1920|true|Active Width
    select|0x40040040|false|true|0#0^RGB#1^YUV 444#2^YUV 422#3^YUV 420|true|Color Format
    select|0x40040020|false|true|0#0^Pass through#1^Horizontal Ramp#2^Vertical Ramp#3^Temporal Ramp#4^Solid red#5^Solid green#6^Solid blue#7^Solid black#8^Solid white#9^Color bars#10^Zone Plate#11^Tartan Color Bars#12^Cross hatch pattern#13^Color sweep pattern#14^Combined V & H ramp#15^B & W checker board#16^Pseudorandom pattern#17^DP color ramp#18^DP B & W vertical lines#19^DP color square|true|Background Pattern ID
    reg|0x40040000|true|true|0x81|true|Control
    range|0x40040078|false|true|175#0#511|true|Box Size
    range|0x40040088|false|true|0#0#255|true|Box Color (Red)
    range|0x40040090|false|true|0#0#255|true|Box Color (Green)
    range|0x40040080|false|true|160#0#255|true|Box Color (Blue)
    range|0x40040038|false|true|8#0#31|true|Motion Speed
    select|0x40040028|false|true|1#0^No overlay#1^Moving box#2^Cross hairs|true|Forground Pattern ID
    range|0x40040048|false|true|960#0#1919|true|Cross hair horizontal
    range|0x40040050|false|true|540#0#1079|true|Cross hair vertical
    reg|0x40040098|false|true|1|true|Enable input
    
    Direct download available here :-
    steve@Desktop:~/swuk_tutorial$ wget https://spacewire.co.uk/tutorial/shared/documents/swuk_tutorial/configuration/zedboard_video_tpg_vga.txt -O ${swuk_user}/configuration/zedboard_video_tpg_vga.txt
    
    Access the webserver running on the Zedboard using a browser pointing at the Zedboard's IP address (192.168.2.87). Select Peek & Poke from the menu bar.

    Browse for the above configuration file and open it. Although this looks complicated in reality it isn't. With the register values defined all that is now required is to click on Poke All to fire up both TPG's and output video via the VGA connector. Missing Image! LED 7 should illuminate to indicate video lock & the following should be seen on the screen attached to the VGA port of the Zedboard. The color bars are provided from TPG 0 along with the larger green moving box, this video is then passed through TPG 1 and overlaid with the second smaller blue moving box.

    Note the glitch in the video when either box hits the right hand edge of the screen. To see how bad this is make one of the boxes small and then when it gets close to the right hand edge make it much larger.

    The hardware used for the following video captures was the Zedboard's VGA output connected to a VGA to HDMI adapter, which in turn was connected to a HDMI to USB video capture card.

    The software used to display the video from the HDMI to USB video capture card was Guvcview (Frame Rate: 60fps & Resolution: 1280x720). The window/screen area capture was done using Kazam (Frame rate: 60, Record with: VP8 (WEBM)).

    Note: The video looks much better on a monitor!



    Various elements of the TPG's can easily be controlled on-the-fly using the webpage widgets.



    Sadly some of the background patterns do not work as expected due to the RGB lines only being 4-bits wide instead of 8-bits wide. Not sure what is causing the right hand side artefact, this is something not seen in the HDMI version of this design!
    #### Part 6 - Revision Control - 2 ####

    13. Block design vs. scripted options

    Two options now exist for committing the zedboard_video_tpg_vga project (and others) to the repository.
    1. Block design with no script execution - commit fw/src/diagram/system/system.bd.
    2. Purely scripted - do not commit fw/src/diagram/system/system.bd.
    If this design was built from the repository source using only the scripts (common/fw/src/script/swuk_create_system_bd.tcl & zedboard_video_tpg_vga/fw/src/script/user_update_system_bd.tcl), i.e. the block design was not present in the repository (zedboard_video_tpg_vga/fw/src/diagram/system/system.bd) then a new block design will be created (from the scripts) at zedboard_video_tpg_vga/fw/vivado/project.srcs/sources_1/bd/system/system.bd.

    If the newly created block design (zedboard_video_tpg_vga/fw/vivado/project.srcs/sources_1/bd/system/system.bd) is manually edited then it MUST be copied to zedboard_video_tpg_vga/fw/src/diagram/system/system.bd so it can be committed to the repository and used for the next iteration of the design. Once the block design is safely committed it is best to clean the project directory using git clean -fdx and recreate a clean project using swuk_create_vivado_project. This will now use the block design from zedboard_video_tpg_vga/fw/src/diagram/system/system.bd instead of the two scripts.

    If an existing block design from the repository (zedboard_video_tpg_vga/fw/src/diagram/system/system.bd) is manually edited then it will automatically be included in any commit to the repository.

    14. Final checks (BD build)

    Sanity check the block design (not purely scripted) build process.

    Close Vivado.

    The previous build used the two scripts to create the block design (zedboard_video_tpg_vga/fw/vivado/zedboard_video_tpg_vga.srcs/sources_1/bd/system/system.bd).

    If this block design had been manually edited then it would be copied to zedboard_video_tpg_vga/fw/src/diagram/system/system.bd for inclusion in the repository and thus used to build a fresh design.

    Copy the block design to the acceptable location (zedboard_video_tpg_vga/fw/src/diagram/system/system.bd) so it will be used instead of the scripts. Remove the existing vivado directory.
    steve@Desktop:~/swuk_tutorial$ cd zedboard_video_tpg_vga
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ mkdir -p fw/src/diagram/system
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ cp fw/vivado/zedboard_video_tpg_vga.srcs/sources_1/bd/system/system.bd fw/src/diagram/system
    
    Check GIT status, which should now show the block design is part of the file set.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ git status -u
    On branch master
    Your branch is up to date with 'origin/master'.
    
    Untracked files:
      (use "git add <file>..." to include in what will be committed)
            fw/src/diagram/system/system.bd      
    
    nothing added to commit but untracked files present (use "git add" to track)
    
    Create the project from fresh source, now using the block design instead of the scripts.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ rm -rf fw/vivado
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ swuk_create_vivado_project
    
    Check all is well by expanding zedboard_video_tpg_vga under Design Sources. Click on system.bd and examine the Location under Source File Properties. The location should be ${swuk_tutorial}/zedboard_video_tpg_vga/fw/src/diagram/system.

    If the current files were now committed to the repository then going forward the block design would be used instead of the scripts.

    Since we don't really want that at the moment, quit Vivado and do a clean to get back to the previous state.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ git clean -fdx
    
    Double check GIT status.
    steve@Desktop:~/swuk_tutorial/zedboard_video_tpg_vga$ git status -u
    On branch master
    Your branch is up to date with 'origin/master'.
    
    nothing to commit, working tree clean
    
    All good!