Bar
SpaceWire UK
Specialist providers of VHDL Intellectual Property & Design Services
BarBarBarBar
Tutorial
Missing Image!
Part 25 - Identification strings inside a Block RAM

Introduction

This tutorial details the steps required to create a design that allows the Project Identification information to be held inside an AXI4 controlled Block ROM.

Previously this information was passed to the build process via a pre-synthesis script. The script reading the project.txt file and querying GIT to gather up additional repository information. All this information then being passed along to the PL firmware using string generics at the top level that traverse down to signals fed in to the AXI Identification module. This method is sub-optimal at best but seemed to be one of the better approaches given the plethora of Block Design limitations.

Although the same information will be gathered and presented to the end-user in exactly the same manner as before, it will be provided via a Block ROM instead of a Register Bank.

The Block ROM will have its contents updated post-bitstream instead of pre-synthesis. The pre-synthesis approach was attempted but it crashed and burnt due to the creation of the COE being late to the Block Design evaluation party. The ID was always one build behind where it should have been!

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 AXI4 Block RAM identification to block design
    4. Edit HDL wrapper
    5. Create post-bitstream script
    6. Generate bitstream
    7. Quick check

    Part 3 - Hardware Deployment - 1

    1. Create a loadable binary from a bitstream & upload to the SD-Card
    2. Quick check
    3. Remove uploaded binary from the SD-Card

    Part 4 - Revision Control

    1. Commit new & updated files

    Part 5 - Firmware Development - 2

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

    Part 6 - Hardware Deployment - 2

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

    Part 7 - Conclusion

    1. Final thoughts
    #### 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_bram_id --baseline
    Enter details for the header blocks...
    File .......... zedboard_bram_id
    Author ........ Steve Haywood
    Company ....... SpaceWire UK
    Website ....... http://www.spacewire.co.uk
    Project ....... Zedboard Block RAM Identification
    Tutorial ...... SpaceWire UK Tutorial
    Date .......... 20 Feb 2026
    Version ....... 1.0
    Creating project directory structure...
    Creating baseline project...
    steve@Desktop:~/swuk_tutorial$ cd zedboard_bram_id
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ swuk_create_vivado_project
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ 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 AXI4 Block RAM identification 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 :- Create the update script.

    steve@Desktop:~/swuk_tutorial$ subl zedboard_bram_id/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 Block RAM Identifiction (SpaceWire UK Tutorial)
    # Date .......... 28 Jan 2026
    # 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 an AXI4 Block
    # RAM Identification example design.
    #
    
    
    #############################################################################
    # 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
    
    # - AXI Identification
    #   - Remove
    
    delete_bd_objs [get_bd_cells axi_identification_0]
    delete_bd_objs [get_bd_nets id_*]
    delete_bd_objs [get_bd_ports id_*]
    
    
    ###################################
    # Create instances & set properties
    
    # - AXI BRAM Controller
    #   - BRAM Options
    #     - Set 'Number of BRAM interfaces' to '1'
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:axi_bram_ctrl:4.1 axi_bram_ctrl_id
    set_property -dict [list \
      CONFIG.SINGLE_PORT_BRAM {1} \
    ] [get_bd_cells axi_bram_ctrl_id]
    
    # - Block Memory Generator
    #   - Basic
    #     - Set 'Memory Type' to 'Single Port ROM'
    
    create_bd_cell -type ip -vlnv xilinx.com:ip:blk_mem_gen:8.4 blk_mem_gen_id
    set_property -dict [list \
      CONFIG.Memory_Type {Single_Port_ROM} \
    ] [get_bd_cells blk_mem_gen_id]
    
    
    ##############################
    # Create interface connections
    
    connect_bd_intf_net -boundary_type upper [get_bd_intf_pins axi_interconnect_0/M00_AXI] \
      [get_bd_intf_pins axi_bram_ctrl_id/S_AXI]
    
    connect_bd_intf_net [get_bd_intf_pins axi_bram_ctrl_id/BRAM_PORTA] \
      [get_bd_intf_pins blk_mem_gen_id/BRAM_PORTA]
    
    
    #########################
    # Create port connections
    
    connect_bd_net [get_bd_pins processing_system7_0/FCLK_CLK0] \
      [get_bd_pins axi_interconnect_0/M03_ACLK] \
      [get_bd_pins axi_bram_ctrl_id/s_axi_aclk]
    
    connect_bd_net [get_bd_pins proc_sys_reset_0/peripheral_aresetn] \
      [get_bd_pins axi_interconnect_0/M03_ARESETN] \
      [get_bd_pins axi_bram_ctrl_id/s_axi_aresetn]
    
    
    #########################
    # Create address segments
    
    assign_bd_address \
      -offset 0x40000000 \
      -range 4K \
      -target_address_space \
        [get_bd_addr_spaces processing_system7_0/Data] \
        [get_bd_addr_segs axi_bram_ctrl_id/S_AXI/Mem0] \
      -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/0032/zedboard_bram_id/fw/src/script/user_update_system_bd.tcl -O zedboard_bram_id/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 block RAM identification design. Missing Image!

    5. Edit HDL wrapper

    Edit the top-level wrapper for the block design to remove the identification fields.
    steve@Desktop:~/swuk_tutorial$ subl zedboard_bram_id/fw/src/design/zedboard_bram_id.sv

    zedboard_bram_id.sv

    //
    // File .......... zedboard_bram_id.sv
    // Author ........ Steve Haywood
    // Website ....... http://www.spacewire.co.uk
    // Project ....... Zedboard Block RAM Identification (SpaceWire UK Tutorial)
    // Date .......... 28 Jan 2026
    // Version ....... 1.0
    // Description ...
    //   Top level wrapper for the system block design.
    //
    
    
    timeunit      1ns;
    timeprecision 1ps;
    
    
    module zedboard_bram_id
    (
      // 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
      // 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
    );
    
    
      // Top-Level Block Design
      system system_i
       (
        // LEDs
        .leds              ( leds              ),  // O:LEDs
        // DIP Switches
        .switches          ( switches          ),  // I:DIP Switches
        // Push Buttons
        .buttons           ( buttons           ),  // I:Push Buttons
        // 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/0032/zedboard_bram_id/fw/src/design/zedboard_bram_id.sv -O zedboard_bram_id/fw/src/design/zedboard_bram_id.sv

    6. Create post-bitstream script

    Create a post-bitstream TCL script to add the capability of creating a RAM initialisation file (.mem) that will hold the identification information. This will be heavily based on the pre-synthesis TCL script.
    steve@Desktop:~/swuk_tutorial$ cp common/fw/src/script/swuk_pre_synth.tcl common/fw/src/script/swuk_post_bit.tcl
    steve@Desktop:~/swuk_tutorial$ subl common/fw/src/script/swuk_post_bit.tcl

    swuk_post_bit.tcl

    #
    # File .......... swuk_post_bit.tcl
    # Author ........ Steve Haywood
    # Website ....... http://www.spacewire.co.uk
    # Project ....... Common (SpaceWire UK Tutorial)
    # Date .......... 28 Jan 2026
    # Version ....... 1.0
    # Description ...
    #   Script to read product/project information from a text file, obtain GIT
    # repository information and update the contents of the AXI Identification
    # Block RAM (post-implementation).
    #
    
    # Exit if BRAM Identification does not exists on BD
    if {[get_files -quiet system_blk_mem_gen_id_0.xci] == ""} {
      puts "NOTE: No AXI BRAM Identification found, not executing post-bitstream script."
      return
    } {
      puts "NOTE: Found AXI BRAM Identification, executing post-bitstream script."
    }
    
    # Get project name
    set parts [split [pwd] "/"]
    set project [lindex $parts end-4]
    
    # Read Product/Project Information
    if { [catch {set id_file [open "../../../project.txt" r]} msg] } {
      set id_description "?"
      set id_company "?"
      set id_author "?"
      set id_version "?"
      puts "ERROR :-"
      puts $msg
    } {
      gets $id_file id_description
      gets $id_file id_company
      gets $id_file id_author
      gets $id_file id_version
      close $id_file
    }
    
    # Get GIT timestamp
    set dfmt "%d-%b-%Y - %H:%M:%S"
    if { [catch {set id_timestamp [exec git log -1 --pretty=%cd --date=format:$dfmt]} msg] } {
      set id_timestamp "00-Xxx-0000 - 00:00:00"
      puts "ERROR :-"
      puts $msg
    }
    
    # Get GIT hash
    if { [catch {set id_hash [exec git log -1 --pretty=%H]} msg] } {
      set id_hash "0000000000000000000000000000000000000000"
      puts "ERROR :-"
      puts $msg
    }
    
    # Get GIT status
    if { [catch {set status [exec git status -s]} msg] } {
      append id_version " (undefined)"
      puts "ERROR :-"
      puts $msg
    } {
      if {$status ne ""} {
        append id_version " (unstaged)"
      } {
        if { [catch {set status [exec git branch -r --contains $id_hash]} msg] } {
          append id_version " (undefined)"
          puts "ERROR :-"
          puts $msg
        } {
          if {$status eq ""} {
            append id_version " (unpushed)"
          }
        }
      }
    }
    
    # String to Hex written into MEM file
    proc str2mem { fout field length last } {
      set str ""
      set term ","
      for {set i 0} {$i < $length} {incr i} {
        # Get character from string
        set char [string index $field $i]
        if { $char != "" } {
          # Get ASCII code from character
          scan $char %c code
          # Get 2-digit hex string from ASCII
          set hex [format %02X $code]
        } else {
          set hex "00"
        }
        # Append 2-digit hex string to existing hex string
        set str "$str$hex"
        # When hex string contains all 4-digits print it
        if { [expr $i % 4] == 3 } {
          puts $fout "$str"
          set str ""
        }
      }
    }
    
    # Write RAM contents file (COE format)
    if { [catch {set fout [open "$project.mem" w]} msg] } {
      puts "ERROR :-"
      puts $msg
    } {
      puts $fout "@40000000"
      str2mem $fout $id_description 128 128
      str2mem $fout $id_company      64  64
      str2mem $fout $id_author       64  64
      str2mem $fout $id_version      32  32
      str2mem $fout $id_timestamp    32  32
      str2mem $fout $id_hash         64  64
      str2mem $fout ""              128 127
      close $fout
    }
    
    # Update Identification BRAM inside the bitstream
    exec updatemem -force -meminfo $project.mmi -data $project.mem -bit $project.bit -proc system_i/processing_system7_0 -out $project.bit
    
    Direct download available here :-
    steve@Desktop:~/swuk_tutorial$ wget https://spacewire.co.uk/tutorial/shared/repos/0032/common/fw/src/script/swuk_post_bit.tcl -O common/fw/src/script/swuk_post_bit.tcl
    Add the new script to the project by executing the following from the Vivado Tcl Console.
    add_files -fileset utils_1 -norecurse ../../../common/fw/src/script/swuk_post_bit.tcl
    set_property STEPS.WRITE_BITSTREAM.TCL.POST [ get_files ../../../common/fw/src/script/swuk_post_bit.tcl -of [get_fileset utils_1] ] [get_runs impl_1]

    7. Generate bitstream

    Generate the programmable logic bitstream by clicking on Generate Bitstream under the PROGRAM AND DEBUG heading inside the Flow Navigator section.Missing Image!

    8. Quick check

    Once Vivado has completed the build & generated the Bitstream check the implementation directory for the update memory log file.
    steve@Desktop:~/swuk_tutorial$ cd zedboard_bram_id
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ cat fw/vivado/zedboard_bram_id.runs/impl_1/updatemem.log
    ::
    ::
    #-----------------------------------------------------------
    source /opt/Xilinx/Vivado/2024.2/scripts/updatemem/main.tcl -notrace
    Command: update_mem -meminfo zedboard_bram_id.mmi -data zedboard_bram_id.mem -proc system_i/processing_system7_0 -bit zedboard_bram_id.bit -out zedboard_bram_id.bit -force
    Loading bitfile zedboard_bram_id.bit
    Loading data files...
    Updating memory content...
    Creating bitstream...
    Writing bitstream zedboard_bram_id.bit...
    0 Infos, 0 Warnings, 0 Critical Warnings and 0 Errors encountered.
    update_mem completed successfully
    update_mem: Time (s): cpu = 00:00:05 ; elapsed = 00:00:05 . Memory (MB): peak = 942.418 ; gain = 449.512 ; free physical = 15752 ; free virtual = 98384
    INFO: [Common 17-206] Exiting updatemem at Wed Jan 28 19:00:12 2026...
    Looks good! If the log file does not exists double check the post-bitstream TCL script was added to the Vivado project correctly.
    #### Part 3 - Hardware Deployment - 1 ####

    9. 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's SD-Card. Select 0 from the menu.
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ swuk_upload_bin ${swuk_zedboard_ip}

    Bitstream files @ fw/vivado/zedboard_bram_id.runs/impl_1 :-

    0) - zedboard_bram_id.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_hdmi_v1.0.bit
    9) - zedboard_video_tpg_vga_v1.0.bit

    q) Quit

    Select file for upload or quit : 0

    Uploaded zedboard_bram_id.bin to /media/sd-mmcblk0p1/firmware @ 192.168.2.87.

    10. Quick check

    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 (refresh page if already open).

    In the Loadable Firmware table click on Load next to the newly uploaded binary zedboard_bram_id.bin to load the new firmware into the PL.

    The Firmware Information table should now show the new Zedboard Block RAM Identification description along with a version of 1.0 (unstaged).

    11. Remove uploaded binary from the SD-Card

    Clean up the SD-Card by removing the uploaded beta (uncontrolled) version of the Firmware.
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ sshpass -p root ssh -t root@${swuk_zedboard_ip} 'rm /media/sd-mmcblk0p1/firmware/zedboard_bram_id.bin'
    #### Part 4 - Revision Control ####

    12. Commit new & updated files

    Check GIT status to make sure all is well and there are no spurious elements.
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ cd ..
    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)
       common/fw/src/script/swuk_post_bit.tcl
       zedboard_bram_id/.gitignore
       zedboard_bram_id/fw/project.txt
       zedboard_bram_id/fw/src/constraint/zedboard_bram_id.xdc
       zedboard_bram_id/fw/src/design/zedboard_bram_id.sv
       zedboard_bram_id/fw/src/script/user_update_system_bd.tcl

    no changes added to commit (use "git add" and/or "git commit -a")
    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 -am "Basic Zedboard design consisting of a ZYNQ7 Processing System talking to an AXI4 Block RAM that provides product identification information."
    steve@Desktop:~/swuk_tutorial$ git push
    steve@Desktop:~/swuk_tutorial$ git tag -a my_zedboard_bram_id_v1.0 -m "ZYNQ & AXI4 Block RAM identification"
    steve@Desktop:~/swuk_tutorial$ git push origin my_zedboard_bram_id_v1.0
    #### Part 5 - Firmware Development - 2 ####

    13. Create production release

    Create a potential production release for the Zedboard Block RAM Identification (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_bram_id
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ rm -rf fw/vivado
    Double check GIT status.
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ git status
    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_bram_id$ swuk_create_vivado_project --build

    14. Archive build files for later retrieval

    Archive the generated bitstream for safe keeping. This file is not held in the repository as it can be recreated from source.
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ cp fw/vivado/zedboard_bram_id.runs/impl_1/zedboard_bram_id.bit ${swuk_user}/firmware/zedboard_bram_id_v1.0.bit
    #### Part 6 - Hardware Deployment - 2 ####

    15. 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's SD-Card. Select 1 from the menu (same as 0 but with a better name).
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ swuk_upload_bin ${swuk_zedboard_ip}

    Bitstream files @ fw/vivado/zedboard_bram_id.runs/impl_1 :-

    0) - zedboard_bram_id.bit

    Bitstream files @ /home/steve/Documents/swuk_tutorial/firmware :-

    1) - zedboard_bram_id_v1.0.bit
    2) - zedboard_hello_world_v1.0.bit
    3) - zedboard_leds_buttons_v1.0.bit
    4) - zedboard_leds_switches_v1.0.bit
    5) - zedboard_leds_switches_v2.0.bit
    6) - zedboard_leds_switches_v3.0.bit
    7) - zedboard_leds_switches_v4.0.bit
    8) - zedboard_leds_switches_v5.0.bit
    9) - zedboard_video_tpg_hdmi_v1.0.bit
    10) - zedboard_video_tpg_vga_v1.0.bit

    q) Quit

    Select file for upload or quit : 1

    Uploaded zedboard_bram_id_v1.0.bin to /media/sd-mmcblk0p1/firmware @ 192.168.2.87.

    16. 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 (refresh page if already open).

    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 Block RAM Identification description along with a version of 1.0. There should be no unsavoury comments after the version number! Missing Image! The Timestamp & Hash shown from GIT (first entry) should marry up perfectly with the displayed Firmware Information. All being well the second GIT entry should marry up perfectly with the displayed Operating System Information.
    steve@Desktop:~/swuk_tutorial/zedboard_bram_id$ git log -2
    commit 5af54b3eb2ffe1d0ed2c3c44b8296af4615edf3a (HEAD -> my_master, tag: my_zedboard_bram_id_v1.0, origin/my_master)
    Author: Steve Haywood <steve@spacewire.co.uk>
    Date:   Thu Feb 19 15:03:01 2026 +0000

        Basic Zedboard design consisting of a ZYNQ7 Processing System talking to an AXI4 Block RAM that provides product identification information.

    commit 457a58024d01d397f85e69d95983d7a98a38a1d0 (tag: zedboard_linux_v15.0)
    Author: Steve Haywood <steve@spacewire.co.uk>
    Date:   Mon Dec 22 19:46:13 2025 +0000

        Added ADV7511 configuration auto-start application. This version of PetaLinux includes the XSA from zedboard_video_tpg_hdmi v1.0.
    Looks good!
    #### Part 7 - Conclusion ####

    17. Final thoughts

    There are pros & cons for using a Block RAM to store the identification information vs. using HDL parameters. The best solution maybe to build in the GIT hash pre-synthesis (virtually impossible to change post-bitstream) and pass in the rest of the information post-bitstream (may actually be desirable).