Forum | Documentation | Website | Blog

Skip to content
Snippets Groups Projects
generate_gateware_overlays.py 5.02 KiB
Newer Older
import os
import struct
import ctypes
import sys
import subprocess

from gather_dtso import gather_dtso

global dtbo_info


def gen_magic():
    global dtbo_info
    struct.pack_into('cccc', dtbo_info, 0, b'M', b'C', b'H', b'P')


def gen_descriptor_length(no_of_contexts, no_of_dtbo):
    global dtbo_info
    descriptor_length = 12 + (4 * no_of_contexts) + (4 * no_of_dtbo)
    struct.pack_into('I', dtbo_info, 4, descriptor_length)


# 2 bytes longs version number
def gen_version():
    global dtbo_info
    version = 0
    struct.pack_into('H', dtbo_info, 8, version)


def gen_number_of_contexts(no_of_contexts):
    global dtbo_info
    in_number_of_contexts = no_of_contexts
    struct.pack_into('H', dtbo_info, 10, in_number_of_contexts)


def get_dtbo_files_list():
    initial_directory = os.getcwd()
    context_dir = os.path.join(initial_directory, "work", "dtbo", "context-0")
    dtbo_files_list = []
    for root, dirs, files in os.walk(context_dir):
        for file in files:
            if file.endswith(".dtbo"):
                dtbo_files_list.append(os.path.join(root, file))
    return dtbo_files_list


def get_dtbo_total_size(dtbo_list):
    size = 0
    for dtbo_file in dtbo_list:
        size = size + os.path.getsize(dtbo_file)
    return size


def gen_dtbo_info(overlay_dir_path, no_of_contexts, dtbo_list):
    dtbo_desc_list_start_offset = 12 + (no_of_contexts * 4)
    struct.pack_into('I', dtbo_info, 12, dtbo_desc_list_start_offset)
    no_of_dtbo = len(dtbo_list)
    struct.pack_into('I', dtbo_info, 16, no_of_dtbo)
    dtbo_data_offset = 20 + (no_of_dtbo * 12)
    dtbo_idx = 0
    for dtbo_file in dtbo_list:
        size = os.path.getsize(dtbo_file)
        struct.pack_into('I', dtbo_info, 20 + (dtbo_idx * 12), dtbo_data_offset)
        struct.pack_into('I', dtbo_info, 24 + (dtbo_idx * 12), dtbo_data_offset + size)
        struct.pack_into('I', dtbo_info, 28 + (dtbo_idx * 12), size)
        dtbo_data_offset += size
        dtbo_idx += 1

    dtbo_full_path = os.path.join(overlay_dir_path, "mpfs_dtbo.spi")
    with open(dtbo_full_path, "wb") as mpfs_dtbo:
        mpfs_dtbo.write(dtbo_info)

    #
    # Append the actual dtbo files to the dtbo_file
    #
    with open(dtbo_full_path, "ab") as mpfs_dtbo:
        for dtbo_file in dtbo_list:
            with open(dtbo_file, "rb") as in_dtbo_file:
                mpfs_dtbo.write(in_dtbo_file.read())


def create_dtbo_info(overlay_dir_path):
    global dtbo_info

    dtbo_list = get_dtbo_files_list()
    print("number of gateware device tree overlays: ", len(dtbo_list))
    for dtbo_file in dtbo_list:
        print(dtbo_file)
    no_of_contexts = 1
    no_of_dtbo = len(dtbo_list)

    #
    # Generate the DTBO info binary.
    #
    dtbo_info_length = 12 + (8 * no_of_contexts) + (12 * no_of_dtbo)

    dtbo_info = ctypes.create_string_buffer(dtbo_info_length)
    gen_magic()
    gen_descriptor_length(no_of_contexts, no_of_dtbo)
    gen_version()
    gen_number_of_contexts(no_of_contexts)
    gen_dtbo_info(overlay_dir_path, no_of_contexts, dtbo_list)
    print(dtbo_info[:])


def get_gateware_git_version(work_dir):
    try:
        git_hash = subprocess.check_output(['git', 'describe', '--tags'])
    except subprocess.CalledProcessError as e:
    return git_hash.decode('ascii').strip("'").strip("\n")


def inject_git_info_into_src_dtso(dtso_file, git_version):
    with open(dtso_file, "r") as f:
        dtso = f.read()
        dtso = dtso.replace('GATEWARE_GIT_VERSION', git_version)
        with open(dtso_file, "w") as fout:
            fout.write(dtso)


def compile_dtso(work_dir):
    root_dir = os.path.join(work_dir, 'dtbo', 'context-0')
    git_version = get_gateware_git_version(work_dir)
    for root, dirs, files in os.walk(root_dir):
        for file in files:
            if file.endswith(".dtso"):
                dtso_file = os.path.join(root, file)
                inject_git_info_into_src_dtso(dtso_file, git_version)
                dtbo_file = os.path.splitext(dtso_file)[0] + '.dtbo'
                cmd = 'dtc -O dtb -I dts -o ' + dtbo_file + ' ' + dtso_file
                os.system(cmd)


def generate_device_tree_overlays(overlay_dir_path, build_options_list):
    print("================================================================================")
    print("                            Generate Device Tree Overlays")
    print("================================================================================\r\n", flush=True)
    bitstream_builder_root = os.getcwd()
    gateware_dir = os.path.join(bitstream_builder_root, 'sources', 'FPGA-design')
    work_dir = os.path.join(bitstream_builder_root, 'work')
    gather_dtso(gateware_dir, work_dir, build_options_list)
    compile_dtso(work_dir)
    create_dtbo_info(overlay_dir_path)


def generate_gateware_overlays(overlay_dir_path, build_options_list):
    generate_device_tree_overlays(overlay_dir_path, build_options_list)


if __name__ == '__main__':
    if len(sys.argv) > 1:
        argument_list = sys.argv[1:]
    else:
        argument_list = 'NONE'
    generate_device_tree_overlays(argument_list)