def __write_asterics_core__(
     self,
     path: str,
     use_symlinks: bool = True,
     allow_deletion: bool = False,
     module_driver_dirs: bool = False,
 ) -> bool:
     path = self.__check_and_get_output_path__(path)
     if not path:
         return False
     try:
         as_build.prepare_output_path(None, path, allow_deletion)
     except IOError as err:
         LOG.error(
             ("Could not prepare the output directory '%s'" "! - '%s'"),
             path,
             str(err),
         )
         return False
     try:
         self.__write_hw__(
             append_to_path(path, "hardware"), use_symlinks, allow_deletion
         )
         self.__write_sw__(
             append_to_path(path, "software"),
             use_symlinks,
             allow_deletion,
             module_driver_dirs,
         )
     except (IOError, AsError) as err:
         LOG.error(str(err))
         return False
     return True
    def __write_system__(
        self,
        path: str,
        use_symlinks: bool = True,
        allow_deletion: bool = False,
        module_driver_dirs: bool = False,
        add_vears: bool = False,
    ):
        # Make sure path is good
        path = self.__check_and_get_output_path__(path)
        ip_path = append_to_path(path, self.IP_CORE_REL_PATH)
        if not path:
            return False
        # Clean up if not empty
        try:
            src_path = append_to_path(self.asterics_dir, self.SYSTEM_TEMPLATE_PATH)
            as_build.prepare_output_path(src_path, path, allow_deletion)
        except IOError as err:
            LOG.error(
                ("Could not prepare the output directory '%s'" "! - '%s'"),
                path,
                str(err),
            )
            return False
        # Get paths for HW and SW gen
        sw_path = append_to_path(ip_path, self.DRIVERS_REL_PATH)
        hw_path = append_to_path(ip_path, self.HW_SRC_REL_PATH)
        # Generate and collect source files
        try:
            self.__gen_sw__(sw_path, use_symlinks, module_driver_dirs)
            self.__gen_hw__(hw_path, use_symlinks)
        except (IOError, AsError) as err:
            LOG.error(str(err))
            return False
        # Run packaging
        LOG.info("Running packaging in '%s'.", ip_path)

        add_c1 = self.TCL_ADDITIONS.format(
            design=self.design_name,
            part=self.partname_hw,
            board=self.board_target,
            display_name=self.ipcore_name,
            description=self.ipcore_descr,
        )
        as_build.run_vivado_packaging(self.current_chain, ip_path, add_c1)

        # Add VEARS core
        if add_vears:
            try:
                as_build.add_vears_core(
                    append_to_path(path, "vivado_cores"),
                    self.asterics_dir,
                    use_symlinks,
                )
            except (IOError, AsError) as err:
                LOG.error(str(err))
                return False
        return True
示例#3
0
 def _write_ip_core_xilinx(
     self,
     path: str,
     use_symlinks: bool = True,
     allow_deletion: bool = False,
     module_driver_dirs: bool = False,
 ):
     err_mgr = self.current_chain.err_mgr
     # Make sure path is good
     path = self._check_and_get_output_path(path)
     if not path:
         return False
     # Clean up if not empty
     try:
         src_path = append_to_path(self.asterics_home,
                                   self.IP_CORE_TEMPLATE_PATH)
         as_build.prepare_output_path(src_path, path, allow_deletion)
     except IOError as err:
         LOG.error(
             ("Could not prepare the output directory '%s'"
              "! - '%s'"),
             path,
             str(err),
         )
         return False
     # Get paths for HW and SW gen
     sw_path = append_to_path(path, self.DRIVERS_REL_PATH)
     hw_path = append_to_path(path, self.HW_SRC_REL_PATH)
     # Generate and collect source files
     try:
         self._gen_sw(sw_path, use_symlinks, module_driver_dirs)
         if err_mgr.has_errors():
             LOG.critical("Abort! Errors occurred during system build:")
             err_mgr.print_errors()
             return False
         self._gen_hw(hw_path, use_symlinks)
         if err_mgr.has_errors():
             LOG.critical("Abort! Errors occurred during system build:")
             err_mgr.print_errors()
             return False
     except (IOError, AsError) as err:
         LOG.error(str(err))
         return False
     add_c1 = self.TCL_ADDITIONS.format(
         design=self.design_name,
         part=self.partname_hw,
         board=self.board_target,
         display_name=self.ipcore_name,
         description=self.ipcore_descr,
     )
     # Run packaging
     LOG.info("Running packaging in '%s'.", path)
     try:
         as_build.run_vivado_packaging(self.current_chain, path, add_c1)
     except (IOError, AsError) as err:
         LOG.error(str(err))
         return False
     return True
示例#4
0
def run_vivado_packaging(chain: AsProcessingChain,
                         output_path: str,
                         tcl_additions: str = ""):
    """! @brief Write the necessary TCL fragments and run the TCL packaging script.
    Requires Vivado to be installed and in callable from the current terminal.
    Parameters:
    chain: The current processing chain.
    output_path: The root of the output folder structure.
    No return value."""
    # Write the necessary tcl fragments
    write_vivado_package_tcl(chain, output_path, tcl_additions)
    # Clean path
    path = append_to_path(os.path.realpath(output_path), "/")
    # Input path to launch string
    launch_string = VIVADO_TCL_COMMANDLINE_TEMPLATE.format(
        automatics_home + "/", path)
    cwd = os.getcwd()

    LOG.info("Running Vivado IP-Core packaging...")
    try:
        # Move to output path
        os.chdir(output_path)
        # Launch Vivado there, packaging the IP Core
        os.system(launch_string)
        # Move back home
        os.chdir(cwd)
    except Exception as err:
        LOG.critical("Packaging via Vivado has failed!\nError: '%s'", str(err))
        raise err
    # Cleanup
    ooc_runs_present = any(
        (isinstance(mod, AsModuleWrapper) for mod in chain.modules))
    if not ooc_runs_present:
        for target_suf in HOUSE_CLEANING_LIST_VIVADO:
            target = append_to_path(output_path, target_suf, False)
            # Choose remove function
            if os.path.isdir(target):
                rm_op = rmtree
            else:
                rm_op = os.unlink
            # Try to remove file/directory
            try:
                rm_op(target)
            except FileNotFoundError:
                pass  # This is fine, we wanted it gone anyways ;)
            except IOError as err:
                LOG.warning(
                    "Packaging: Can't remove temporary file(s) '%s' - %s.",
                    target,
                    str(err),
                )
    else:
        LOG.warning(
            "Vivado Project including Out-of-Context runs generated to '{}'.".
            format(output_path))
    LOG.info("Packaging complete!")
示例#5
0
def write_config_hc(chain, output_path: str):
    """! @brief Write the files 'as_config.[hc]'
    The files contain the build date, version string and configuration macros."""
    LOG.info("Generating as_config.c source file...")
    # Fetch and format todays date
    date_string = datetime.today().strftime("%Y-%m-%d")
    version_string = chain.parent.version
    hashstr = "'" + "', '".join(chain.get_hash()) + "'"
    filepath = append_to_path(output_path,
                              AS_CONFIG_C_NAME,
                              add_trailing_slash=False)

    try:
        with open(filepath, "w") as file:
            file.write(
                AS_CONFIG_C_TEMPLATE.format(
                    header=ASTERICS_HEADER_SW.format(
                        filename=AS_CONFIG_C_NAME,
                        description=AS_CONFIG_C_DESCRIPTION,
                    ),
                    hashstr=hashstr,
                    date=date_string,
                    version=version_string,
                ))
    except IOError as err:
        LOG.error("Could not write '%s'! '%s'", AS_CONFIG_C_NAME, str(err))
        raise AsFileError(
            filepath,
            detail=str(err),
            msg="Could not write to file",
        )

    LOG.info("Generating as_config.h source file...")
    filepath = append_to_path(output_path,
                              AS_CONFIG_H_NAME,
                              add_trailing_slash=False)
    try:
        with open(filepath, "w") as file:
            file.write(
                AS_CONFIG_H_TEMPLATE.format(header=ASTERICS_HEADER_SW.format(
                    filename=AS_CONFIG_H_NAME,
                    description=AS_CONFIG_H_DESCRIPTION,
                )))
    except IOError as err:
        LOG.error("Could not write '%s'! '%s'", AS_CONFIG_H_NAME, str(err))
        raise AsFileError(
            filepath,
            detail=str(err),
            msg="Could not write to file",
        )
 def __write_sw__(
     self,
     path: str,
     use_symlinks: bool = True,
     allow_deletion: bool = False,
     module_driver_dirs: bool = False,
 ):
     # Make sure path is good
     path = self.__check_and_get_output_path__(path)
     if not path:
         return False
     path = append_to_path(path, "/")
     # Clean up if not empty
     try:
         as_build.prepare_output_path(None, path, allow_deletion)
     except IOError as err:
         LOG.error(
             ("Could not prepare the output directory '%s'" "! - '%s'"),
             path,
             str(err),
         )
         return False
     # Generate and collect software files
     try:
         self.__gen_sw__(path, use_symlinks, module_driver_dirs)
     except (IOError, AsError) as err:
         LOG.error(str(err))
         return False
     return True
    def __get_modules_from_dir__(cls, module_dir: str) -> Sequence[AsModule]:
        # Make sure the module path is valid syntactically and ends in a "/"
        module_dir = append_to_path(module_dir, "/")
        module_list = []
        # Get all module initialization scripts
        script_list = cls.__get_module_scripts_in_dir__(module_dir)

        for script in script_list:
            module_folder = script[0]
            script_path = script[1]
            script_name = script_path.rsplit("/", maxsplit=1)[-1]

            # For each valid script: run the contained function
            # 'get_module_instance'
            LOG.debug("Modlib importing script '%s' ...", script_name)
            # Get Python module spec
            spec = importutil.spec_from_file_location(script_name, script_path)
            # Get Python module and run / load it
            imported_script = importutil.module_from_spec(spec)
            spec.loader.exec_module(imported_script)
            LOG.debug("Modlib calls 'get_module_inst' of script '%s'",
                      script_name)
            # Execute the function "get_module_instance"
            module_inst = imported_script.get_module_instance(module_folder)
            LOG.debug("Modlib received '%s' from script '%s'",
                      str(module_inst), script_name)
            # If the output is an AsModule, add it to the library
            if isinstance(module_inst, AsModule):
                # Add the module source dir, making sure it
                module_inst.module_dir = module_folder
                module_list.append(module_inst)
        return module_list
示例#8
0
    def write_module_group_vhd(self, folder: str, module_group: AsModuleGroup):
        """! @brief Generate the VHDL file for a module group (AsModuleGroup)"""
        LOG.info("Writing ASTERICS module group file '%s'.", module_group.name)
        filename = "{}.vhd".format(module_group.name)
        outfile = as_help.append_to_path(folder,
                                         filename,
                                         add_trailing_slash=False)

        # Generate the list of glue signals
        self.generate_glue_signal_strings(module_group.signals)

        header = self._generate_header_and_library_string(module_group)
        vhdl_list = []
        # Generate the module's entity declaration
        vhdl_list.extend(self._generate_entity(module_group, None))
        # Generate the toplevel architecture
        vhdl_list.extend(
            self._generate_module_group_architecture(module_group, None))
        # Open the output file
        with open(outfile, "w") as ofile:
            # Make sure we can write to the file
            if not ofile.writable():
                raise AsFileError(msg="File not writable", filename=filename)
            ofile.write(header)
            vhdl_write.write_list_to_file(vhdl_list, ofile)

        # Reset to init state
        self.clear_lists()
 def __write_hw__(
     self, path: str, use_symlinks: bool = True, allow_deletion: bool = False
 ):
     # Make sure path is good
     opath = self.__check_and_get_output_path__(path)
     if not opath:
         raise AsFileError(path, "Could not create output folder!")
     opath = append_to_path(opath, "/")
     # Clean up if not empty
     try:
         as_build.prepare_output_path(None, opath, allow_deletion)
     except IOError as err:
         LOG.error(
             ("Could not prepare the output directory '%s'" "! - '%s'"),
             opath,
             str(err),
         )
         raise AsFileError(opath, "Could not write to output folder!")
     # Generate and collect hardware files
     try:
         self.__gen_hw__(opath, use_symlinks)
     except IOError:
         LOG.error(
             ("Cannot write to '%s'! - " "Could not create VHDL source files!"),
             opath,
         )
         return False
     except AsError as err:
         LOG.error(str(err))
         return False
示例#10
0
    def __get_modules_from_dir__(cls, module_dir: str) -> Sequence[AsModule]:
        # Make sure the module path is valid syntactically and ends in a "/"
        module_dir = append_to_path(module_dir, "/")
        module_list = []
        # Get all module initialization scripts
        script_list = cls.__get_module_scripts_in_dir__(module_dir)

        for script in script_list:
            module_folder = script[0]
            script_path = script[1]
            script_name = script_path.rsplit("/", maxsplit=1)[-1]

            # For each valid script: run the contained function
            # 'get_module_instance'
            LOG.debug("Modlib importing script '%s' ...", script_name)
            # Get Python module spec
            spec = importutil.spec_from_file_location(script_name, script_path)
            # Get Python module and run / load it
            imported_script = importutil.module_from_spec(spec)
            spec.loader.exec_module(imported_script)
            LOG.debug("Modlib calls 'get_module_inst' of script '%s'",
                      script_name)
            # Execute the function "get_module_instance"
            module_inst = imported_script.get_module_instance(module_folder)
            LOG.debug(
                "Modlib received '%s' from script '%s'",
                str(module_inst),
                script_name,
            )
            # If the output is an AsModule, add it to the library
            if isinstance(module_inst, AsModule):
                # Add the module source dir, making sure it
                module_inst.module_dir = module_folder
                module_list.append(module_inst)
                # Discover driver files for this module:
                # If this module already has files manually assigned,
                # don't scan default location
                if not module_inst.driver_files:
                    # Find files in default location
                    module_inst.driver_files = get_software_drivers_from_dir(
                        append_to_path(module_folder, cls.DRIVER_FOLDER))
                else:
                    # If files are manually assigned, normalize path format
                    module_inst.driver_files = [
                        os.path.realpath(df) for df in module_inst.driver_files
                    ]
        return module_list
示例#11
0
    def _write_asterics_core(
        self,
        path: str,
        use_symlinks: bool = True,
        allow_deletion: bool = False,
        module_driver_dirs: bool = False,
    ) -> bool:
        err_mgr = self.current_chain.err_mgr
        path = self._check_and_get_output_path(path)
        if not path:
            return False
        try:
            as_build.prepare_output_path(None, path, allow_deletion)
        except IOError as err:
            LOG.error(
                ("Could not prepare the output directory '%s'"
                 "! - '%s'"),
                path,
                str(err),
            )
            return False
        try:
            self._write_hw(append_to_path(path, "hardware"), use_symlinks,
                           allow_deletion)

            if err_mgr.has_errors():
                LOG.critical("Abort! Errors occurred during system build:")
                err_mgr.print_errors()
                return False
            self._write_sw(
                append_to_path(path, "software"),
                use_symlinks,
                allow_deletion,
                module_driver_dirs,
            )
            if err_mgr.has_errors():
                LOG.critical("Abort! Errors occurred during system build:")
                err_mgr.print_errors()
                return False
        except (IOError, AsError) as err:
            LOG.error(str(err))
            err_mgr.print_errors()
            return False
        return True
示例#12
0
def set_asterics_directory(path: str) -> bool:
    # Cleanup path input
    path = os.path.realpath(append_to_path(path, "/"))
    if os.path.isdir(path):
        Auto.asterics_dir = path
        LOG.info("ASTERICS home directory set to '%s'.", path)
        return True
    # -> Else
    LOG.error("Path '%s' is not a directory! ASTERICS home not set!", path)
    return False
示例#13
0
def new_chain() -> AsProcessingChain:
    """Provide a new AsProcessingChain object.
    This allows you to specify and build a new ASTERICS processing chain.
    When building multiple systems in one script, make sure build the system,
    before calling this again to start the second system!"""
    AsProcessingChain.err_mgr = as_err.AsError.err_mgr
    # Add "standard" ASTERICS modules
    Auto.add_module_repository(append_to_path(as_path, "modules"), "default")
    Auto.current_chain = AsProcessingChain(Auto.library, parent=Auto)
    return Auto.current_chain
示例#14
0
 def __get_module_scripts_in_dir__(cls, module_dir: str) -> Sequence[str]:
     scripts = []
     module_dir = os.path.realpath(module_dir)
     try:
         mod_folders = os.listdir(append_to_path(module_dir, ""))
     except IOError:
         LOG.error("Could not find module repository folder '%s'!",
                   module_dir)
         raise AsFileError(
             "Could not find module repository folder {}!".format(
                 module_dir))
     for folder in mod_folders:
         folder_path = append_to_path(module_dir, folder)
         if not os.path.isdir(folder_path):
             continue
         script_path = append_to_path(folder_path, cls.SCRIPT_FOLDER)
         if not os.path.isdir(script_path):
             continue
         for file in os.listdir(script_path):
             if cls.__script_name_valid__(file):
                 scripts.append((folder_path, script_path + file))
     return scripts
    def write_asterics_vhd(self, folder: str):
        """Generate the Toplevel ASTERICS VHDL file"""
        LOG.info("Writing ASTERICS toplevel VHDL file...")
        # Generate path to the output file
        outfile = as_help.append_to_path(folder, as_static.AS_TOP_FILENAME, False)

        # Generate the list of glue signals
        self.generate_glue_signal_strings(self.chain.top.signals)

        library_use_str = ""
        lib_use_template = "use asterics.{};\n"
        module_entities = []
        for mod in self.chain.top.modules:
            if mod.entity_name not in module_entities:
                module_entities.append(mod.entity_name)
        for entity in module_entities:
            library_use_str += lib_use_template.format(entity)

        # Open the output file
        with open(outfile, "w") as ofile:
            # Make sure we can write to the file
            if not ofile.writable():
                raise AsFileError(
                    msg="File not writable", filename=as_static.AS_TOP_FILENAME
                )
            # Write the header
            ofile.write(
                as_static.HEADER.format(
                    entity_name=as_static.AS_TOP_ENTITY,
                    filename=as_static.AS_TOP_FILENAME,
                    longdesc=as_static.AS_TOP_DESC,
                    briefdesc=as_static.AS_TOP_DESC,
                )
            )
            # and the basic library 'use' declaration
            ofile.write(
                "\n{}{}{}\n".format(
                    as_static.LIBS_IEEE, as_static.LIBS_ASTERICS, library_use_str
                )
            )
            # Generate and write the entity descritpion
            self.__write_entity__(self.chain.top, ofile)
            # Generate and write the toplevel architecture
            self.__write_module_group_architecture__(self.chain.top, ofile)
            # Done writing to file
        # Reset to init state
        self.clear_lists()
示例#16
0
    def __init__(self, asterics_home: str, version_no: str):
        self.asterics_home = append_to_path(os.path.realpath(asterics_home),
                                            "//")
        self.version = version_no
        self.library = AsModuleLibrary(asterics_home)
        self.current_chain = None
        self.windowpipes = []

        self.design_name = "asterics"
        self.board_target = ""
        self.partname_hw = "xc7z010clg400-1"

        self.ipcore_name = "ASTERICS"
        self.ipcore_descr = "ASTERICS Image Processing Chain"

        # Construct and assign interface templates
        as_templates.add_templates()
def write_asterics_h(chain: AsProcessingChain, output_path: str):
    """Write the toplevel ASTERICS driver header containing include
    statements for all driver header files and the definition of the register
    ranges and base addresses."""
    LOG.info("Generating ASTERICS main software driver header file...")
    asterics_h_path = append_to_path(output_path, "/")
    include_list = ""
    include_template = '#include "{}" \n'

    module_base_reg_template = "#define AS_MODULE_BASEREG_{modname} {offset}\n"
    module_base_addr_template = (
        "#define AS_MODULE_BASEADDR_{modname} ((uint32_t*)(ASTERICS_BASEADDR + "
        "(AS_MODULE_BASEREG_{modname} * 4 * AS_REGISTERS_PER_MODULE)))\n")

    # Build a list of module additions to asterics.h
    # Additions should be unique
    # (two HW instances of an ASTERICS module use the same driver)
    module_additions = set()
    for module in chain.modules:
        module_additions.update(module.get_software_additions())
    # Format module additions: One line per additional string
    module_additions = "\n".join(module_additions)
    module_additions = (
        "/************************** Module Defines and "
        "Additions ***************************/\n\n") + module_additions

    # Get list of modules
    unique_modules = get_unique_modules(chain)

    # Collect driver header files that need to be included
    for entity in unique_modules:
        module = chain.library.get_module_template(entity)
        driver_path = module.module_dir + "software/driver/"
        if not os.path.isdir(driver_path):
            continue
        for file in os.listdir(driver_path):
            if file[-2:] == ".h":
                if not any(file in include for include in include_list):
                    include_list += include_template.format(file)

    # Register base definition list and register range order
    reg_bases = ""
    reg_addrs = ""
    # Generate register definitions
    for addr in chain.address_space:
        # Get register interface object
        regif = chain.address_space[addr]
        # Build register interface module name
        regif_modname = regif.parent.name
        if regif.name_suffix:
            regif_modname += regif.name_suffix
        reg_bases += module_base_reg_template.format(
            modname=regif_modname.upper(), offset=regif.regif_num)
        reg_addrs += module_base_addr_template.format(
            modname=regif_modname.upper())

    try:
        with open(asterics_h_path + ASTERICS_H_NAME, "w") as file:
            # Write asterics.h
            file.write(
                ASTERICS_H_TEMPLATE.format(
                    base_addr=chain.asterics_base_addr,
                    regs_per_mod=chain.max_regs_per_module,
                    module_driver_includes=include_list,
                    base_regs=reg_bases,
                    addr_map=reg_addrs,
                    module_additions=module_additions,
                ))

    except IOError as err:
        print("Couldn't write {}: '{}'".format(
            asterics_h_path + ASTERICS_H_NAME, err))
        raise AsFileError(
            asterics_h_path + ASTERICS_H_NAME,
            detail=str(err),
            msg="Could not write to file",
        )
def gather_sw_files(
    chain: AsProcessingChain,
    output_folder: str,
    use_symlinks: bool = True,
    sep_dirs: bool = False,
) -> bool:
    """Collect all available software driver files in 'drivers' folders
    of the module source directories in the output folder structure.
    Parameters:
      chain: The current AsProcessingChain. Source of the modules list.
      output_folder: The root of the output folder structure.
    Returns True on success, False otherwise."""
    LOG.info("Gathering ASTERICS module software driver source files...")
    out_path = os.path.realpath(output_folder)
    # We don't want the trailing slash if we're not using separate folders
    out_path = append_to_path(out_path, "/", sep_dirs)
    # Collect all module entity names
    unique_modules = get_unique_modules(chain)

    for entity in unique_modules:
        module = chain.library.get_module_template(entity)
        source_path = os.path.realpath(
            append_to_path(module.module_dir, "/software/driver/"))
        if not os.path.exists(source_path):
            # If driver folder not present:
            # This module doesn't need drivers -> skip
            LOG.debug(
                ("Gather SW files: Skipped '%s' (%s): "
                 "Directory doesn't exist."),
                entity,
                source_path,
            )
            continue

        if sep_dirs:
            # Build destination path: out + entity name (cut off trailing '/')
            dest_path = append_to_path(out_path, entity, False)
        else:
            # If drivers should not be stored in separate directories
            dest_path = out_path

        # Linking / copying the driver folders / files
        if use_symlinks and sep_dirs:
            LOG.debug("Gather SW files: Link '%s' to '%s'", source_path,
                      dest_path)
            try:
                os.symlink(source_path, dest_path, target_is_directory=True)
            except FileExistsError:
                os.unlink(dest_path)
                try:
                    os.symlink(source_path,
                               dest_path,
                               target_is_directory=True)
                except IOError as err:
                    LOG.critical(
                        "Could not link drivers of module '%s'! - '%s", entity,
                        str(err))
                    return False
            except IOError as err:
                LOG.critical("Could not link drivers of module '%s'! - '%s",
                             entity, str(err))
                return False
        elif not use_symlinks and sep_dirs:
            LOG.debug("Gather SW files: Copy '%s' to '%s'", source_path,
                      dest_path)
            try:
                os.makedirs(dest_path, 0o755)
            except FileExistsError:
                rmtree(dest_path)
                os.makedirs(dest_path, 0o755)
            try:
                copytree(source_path, dest_path)
            except IOError as err:
                LOG.critical("Could not copy drivers of module '%s'! - '%s",
                             entity, str(err))
                return False
        else:
            # Get mode of operation
            mode = "link" if use_symlinks else "copy"
            copy_op = os.symlink if use_symlinks else copy

            LOG.debug("Gather SW files: %sing drivers of module '%s'...",
                      mode.title(), entity)
            # For every drive file
            for sw_file in os.listdir(source_path):
                source_file = append_to_path(source_path, sw_file, False)
                if use_symlinks:
                    dest = append_to_path(dest_path, sw_file, False)
                else:
                    dest = dest_path
                # try to copy/link
                try:
                    copy_op(source_file, dest)
                # Remove existing files on error
                except FileExistsError:
                    os.unlink(append_to_path(dest_path, sw_file, False))
                    # Retry copy/link
                    try:
                        copy_op(source_file, dest)
                    except IOError as err:
                        LOG.critical(
                            ("Could not %s driver file '%s' of module '%s'!"
                             " - '%s"),
                            mode,
                            sw_file,
                            entity,
                            str(err),
                        )
                        return False
                except IOError as err:
                    LOG.critical(
                        ("Could not %s driver file '%s' of module '%s'"
                         "! - '%s"),
                        mode,
                        sw_file,
                        entity,
                        str(err),
                    )
                    return False
    return True
示例#19
0
def add_vears_core(
    output_path: str,
    asterics_path: str,
    use_symlinks: bool = True,
    force: bool = False,
):
    """! @brief Link or copy the VEARS IP-Core.
    VEARS is copied/linked from the ASTERICS installation to the output path.
    @param output_path: Directory to link/copy VEARS to.
    @param asterics_path: Toplevel folder of the ASTERICS installation.
    @param use_symlinks: If True, VEARS will be linked, else copied.
    @param force: If True, the link or folder will be deleted if already present."""
    vears_path = append_to_path(asterics_path, VEARS_REL_PATH)
    vears_path = os.path.realpath(vears_path)
    target = append_to_path(output_path, "VEARS", add_trailing_slash=False)

    if force and os.path.exists(target):
        if os.path.islink(target) or os.path.isfile(target):
            try:
                os.remove(target)
            except IOError as err:
                LOG.error("Could not remove file '%s'! VEARS not added!",
                          target)
                raise AsFileError(
                    target,
                    "Could not remove file to link/copy VEARS!",
                    str(err),
                )
        else:
            try:
                rmtree(target)
            except IOError as err:
                LOG.error("Could not remove folder '%s'! VEARS not added!",
                          target)
                raise AsFileError(
                    target,
                    "Could not remove folder to link/copy VEARS!",
                    str(err),
                )

    if use_symlinks:
        if not os.path.exists(output_path):
            try:
                os.makedirs(output_path, mode=0o755, exist_ok=True)
            except IOError as err:
                LOG.error(
                    "Could not create directory for VEARS: '%s'! - '%s'",
                    output_path,
                    str(err),
                )
                raise AsFileError(
                    output_path,
                    "Could not create directory for VEARS!",
                    str(err),
                )
        try:
            target = os.path.realpath(target)
            os.symlink(vears_path, target, target_is_directory=True)
        except IOError as err:
            LOG.error("Could not create a link to the VEARS IP-Core! - '%s'",
                      str(err))
            raise AsFileError(target, "Could not create link to VEARS!",
                              str(err))
    else:
        try:
            os.makedirs(target, mode=0o755, exist_ok=True)
            target = os.path.realpath(target)
            copytree(vears_path, target)
        except IOError as err:
            LOG.error("Could not copy the VEARS IP-Core!")
            raise AsFileError(output_path, "Could not copy VEARS!", str(err))
示例#20
0
def write_asterics_h(chain: AsProcessingChain, output_path: str):
    """! @brief Write the toplevel ASTERICS driver C header
    The header contains include statements for all driver header files
    and the definition of the register ranges and base addresses."""

    LOG.info("Generating ASTERICS main software driver header file...")
    asterics_h_path = append_to_path(output_path, "/")
    include_list = set()
    include_str = ""
    include_template = '#include "{}" \n'

    module_base_reg_template = "#define AS_MODULE_BASEREG_{modname} {offset}\n"
    module_base_addr_template = (
        "#define AS_MODULE_BASEADDR_{modname} ((uint32_t*)(ASTERICS_BASEADDR + "
        "(AS_MODULE_BASEREG_{modname} * 4 * AS_REGISTERS_PER_MODULE)))\n")

    # Build a list of module additions to asterics.h
    # Additions should be unique
    # (two HW instances of an ASTERICS module use the same driver)
    module_additions = set()
    for module in chain.modules:
        module_additions.update(module.get_software_additions())
    # Format module additions: One line per additional string
    module_additions = "\n".join(module_additions)
    module_additions = (
        "/************************** Module Defines and "
        "Additions ***************************/\n\n") + module_additions

    # Get list of modules
    unique_modules = get_unique_modules(chain)

    # Collect driver header files that need to be included
    def add_header(mod: AsModule):
        for driver in mod.driver_files:
            if driver.endswith(".h"):
                include_list.add(driver.rsplit("/", maxsplit=1)[-1])

    for mod in list(ittls.chain(chain.modules, chain.pipelines)):
        add_header(mod)
    for entity in unique_modules:
        mod = chain.library.get_module_template(entity)
        if mod is not None:
            add_header(mod)
    # Build include list
    include_str = "".join(
        [include_template.format(i) for i in sorted(include_list)])

    # Register base definition list and register range order
    reg_bases = ""
    reg_addrs = ""
    # Generate register definitions
    for addr in chain.address_space:
        # Get register interface object
        regif = chain.address_space[addr]
        # Build register interface module name
        regif_modname = regif.parent.name
        if regif.name_suffix:
            regif_modname += regif.name_suffix
        reg_bases += module_base_reg_template.format(
            modname=regif_modname.upper(), offset=regif.regif_num)
        reg_addrs += module_base_addr_template.format(
            modname=regif_modname.upper())

    try:
        with open(asterics_h_path + ASTERICS_H_NAME, "w") as file:
            # Write asterics.h
            file.write(
                ASTERICS_H_TEMPLATE.format(
                    header=ASTERICS_HEADER_SW.format(
                        filename=ASTERICS_H_NAME,
                        description=ASTERICS_H_DESCRIPTION,
                    ),
                    base_addr=chain.asterics_base_addr,
                    regs_per_mod=chain.max_regs_per_module,
                    module_driver_includes=include_str,
                    base_regs=reg_bases,
                    addr_map=reg_addrs,
                    module_additions=module_additions,
                ))

    except IOError as err:
        print("Couldn't write {}: '{}'".format(
            asterics_h_path + ASTERICS_H_NAME, err))
        raise AsFileError(
            asterics_h_path + ASTERICS_H_NAME,
            detail=str(err),
            msg="Could not write to file",
        )
示例#21
0
def write_vivado_package_tcl(chain: AsProcessingChain,
                             output_path: str,
                             additions_c1: str = "") -> bool:
    """! @brief Write two TCL script fragments sourced by the packaging TCL script.
    This function generates Vivado-specific TCL commands!
    The first fragment is sourced very early in the packaging script and
    contains basic information like the project directory,
    source file directory, etc.
    The second fragment contains packaging commands setting up the
    AXI interface configuration.
    This function needs to access the toplevel modules in the current
    processing chain to generate the TCL code.

    Parameters:
    chain - AsProcessingChain: The current processing chain to build
    output_path - String: Toplevel folder of the current project
    Returns a boolean value: True on success, False otherwise"""

    # Class to manage the AXI interface information for the TCL packaging
    # script
    class TCL_AXI_Interface:
        """'Private' class capsuling methods to write the TCL fragments
        required for the packaging script for Xilinx targets."""
        def __init__(self, axi_type: str):
            # Type of AXI interface ("AXI Slave" / "AXI Master")
            self.axi_type = axi_type
            self.refname = ""  # Variable name of this interface
            self.bus_if_name = ""  # Name of this bus interface in Vivado TCL
            self.clock_name = "_aclk"  # Name of the associated clock
            self.reset_name = "_aresetn"  # Name of the associated reset
            self.if_type = ""  # AXI slave register address block name (Slave)
            self.memory_range = 0  # Range of the address block (Slave)

        def update(self):
            """Update the clock and reset names
            after setting the bus interface name"""
            self.clock_name = self.bus_if_name + self.clock_name
            self.reset_name = self.bus_if_name + self.reset_name

        def get_tcl_bus_assoc_commands(self) -> str:
            """Generate the bus interface association TCL commands"""
            return BUS_IF_ASSOCIATION_TCL_TEMPLATE.format(
                busif=self.bus_if_name,
                clk=self.clock_name,
                rst=self.reset_name,
                ref=self.refname,
            )

        def get_tcl_mem_commands(self) -> str:
            """Generate the memory mapping TCL commands"""
            if any((not self.if_type, not self.memory_range)):
                LOG.debug(
                    ("Generating TCL packaging script: Interface type "
                     "of slave memory range not set for '%s'!"),
                    self.bus_if_name,
                )
                return ""
            # Else ->
            return MEMORY_MAP_TCL_TEMPLATE.format(
                ref=self.refname,
                axi_type=self.if_type,
                mem_range=self.memory_range,
                busif=self.bus_if_name,
                mem_map_ref=self.refname + "_mem_ref",
            )

    LOG.info("Generating TCL packaging scripts...")
    # Generate the necessary paths:
    # IP-Core project directory
    project_dir = append_to_path(os.path.realpath(output_path), "/")
    # Subdirectory containing the HDL sources
    hdl_dir = append_to_path(project_dir, "/hw/hdl/vhdl/")

    # Populate the fragment files with a generic file header
    content1 = TCL_HEADER.format(
        TCL1_NAME, "TCL fragment (1) part of the IP packaging TCL script")
    content2 = TCL_HEADER.format(
        TCL2_NAME, "TCL fragment (2) part of the IP packaging TCL script")
    content3 = TCL_HEADER.format(
        TCL3_NAME, "TCL fragment (2) part of the IP packaging TCL script")

    # Generate the commands for the first basic fragment
    content1 += "\nset projdir " + project_dir
    content1 += "\nset hdldir " + hdl_dir
    if additions_c1:
        content1 += "\n" + additions_c1 + "\n"

    # Possible AXI interface types
    templates = ("AXI_Slave", "AXI_Master")

    for inter in chain.top.interfaces:
        temp = None
        if inter.type.lower() in ("axi_slave_external", "axi_master_external"):
            slave = templates[0] in inter.type
            if slave:
                # For AXI slaves: Populate the TCL AXI class
                temp = TCL_AXI_Interface(templates[0])
                # And set parameters for the memory map (slave registers)
                temp.memory_range = 65536
                temp.if_type = "axi_lite"
            else:
                temp = TCL_AXI_Interface(templates[1])
            temp.refname = (minimize_name(inter.name_prefix).replace(
                temp.axi_type.lower(), "").strip("_"))
            temp.bus_if_name = inter.ports[0].code_name.rsplit("_", 1)[0]

            # Set the reference name and update the clock and reset names
            temp.update()
            # Generate the bus association commands for all interfaces
            content2 += temp.get_tcl_bus_assoc_commands()
            if slave:
                # Only slaves have a memory map
                content2 += temp.get_tcl_mem_commands()

    # Build interface instantiation strings for as_iic modules
    iic_if_inst_str = ["\n"]
    for module in chain.modules:
        if module.entity_name == "as_iic":
            if_name = module.name
            top_if = chain.top.__get_interface_by_un_fuzzy__(
                module.get_interface("in",
                                     if_type="iic_interface").unique_name)
            if top_if is None:
                LOG.error(
                    ("Was not able to determine port names for IIC "
                     "interface '%s' - IIC interface not found!"),
                    if_name,
                )
                mod_prefix = ""
            else:
                mod_prefix = minimize_name(
                    top_if.name_prefix,
                    chain.NAME_FRAGMENTS_REMOVED_ON_TOPLEVEL)
            iic_if_inst_str.append(
                "#Instantiate interface for {}\n".format(if_name))
            iic_if_inst_str.append(
                AS_IIC_MAP_TCL_TEMPLATE.format(iic_signal_prefix=mod_prefix,
                                               iic_if_name=if_name))
            iic_if_inst_str.append(
                "# END Instantiate interface for {}\n\n".format(if_name))
    # Assemble the IIC interface string and add to the TCL fragment
    content2 += "\n".join(iic_if_inst_str)

    tcl_ooc_remove_outsourced_template = "set_property is_enabled false -quiet [get_files -quiet -of_objects [get_filesets sources_1] {{{files}}}]\n"

    outsourced_files = []
    ooc_modules = [
        mod for mod in chain.modules if isinstance(mod, AsModuleWrapper)
    ]
    if ooc_modules:
        tcl_ooc_commands = [
            "# Create OOC blocks\n",
            'puts "Generating Out-of-Context Synthesis Runs..."\n',
        ]
    else:
        tcl_ooc_commands = []
    count = 1
    for mod in ooc_modules:
        source_files = set()
        modfilename = mod.name + ".vhd"
        source_files.add(modfilename)
        outsourced_files.append(modfilename)
        source_files.update(mod.modules[0].files)
        dep_mods = []
        get_dependencies(chain, mod.modules[0], dep_mods)
        if dep_mods:
            for dmod in dep_mods:
                modtemplate = chain.library.get_module_template(dmod)
                source_files.update(modtemplate.files)
        source_files = (sf.rsplit("/", maxsplit=1)[-1]
                        for sf in sorted(source_files))
        tcl_ooc_commands.append(
            TCL_OOC_TEMPLATE.format(
                ent_name=mod.entity_name,
                source_files=" ".join(source_files),
                top_source=mod.name + ".vhd",
                progress=str(count) + " of " + str(len(ooc_modules)),
            ))
        count += 1
    tcl_ooc_commands.append(
        tcl_ooc_remove_outsourced_template.format(
            files=" ".join(outsourced_files)))

    content3 += "\n".join(tcl_ooc_commands)

    # Make sure all files are newline-terminated
    content1 += "\n"
    content2 += "\n"
    content3 += "\n"

    for name, content in zip((TCL1_NAME, TCL2_NAME, TCL3_NAME),
                             (content1, content2, content3)):
        try:
            with open(project_dir + name, "w") as file:
                file.write(content)
        except IOError as err:
            LOG.error("Could not write '%s' in '%s'.", name, project_dir)
            raise AsFileError(project_dir + name, "Could not write file!",
                              str(err))
    # Plz no remove :3 - Thank!
    from as_automatics_env import AsAutomatics
    from as_automatics_proc_chain import AsProcessingChain
    from as_automatics_module import AsModule
    from as_automatics_port import Port
    from as_automatics_interface import Interface
    from as_automatics_module_lib import AsModuleLibrary
    from as_automatics_generic import Generic
    from as_automatics_templates import AsMain, AsTop
    from as_automatics_helpers import append_to_path

    print("Success!")
    # Init Automatics and load standard modules...
    print("Getting default modules from '{}'...".format(asterics_dir))
    auto = AsAutomatics(asterics_dir)
    auto.add_module_repository(append_to_path(asterics_dir, "modules"),
                               "default")

    # User prompt:
    print("Done.")
    print("")
    print("Automatics initialized!")
    print("Use 'as_help()' to list available functions.")

    # User functions start:
    # ----------------------
    def as_help():
        """Print list of available functions"""
        print("")
        print("ASTERICS Automatics: Automatic Processing Chain generator tool")
        print("")
示例#23
0
def gather_sw_files(
    chain: AsProcessingChain,
    output_folder: str,
    use_symlinks: bool = True,
    sep_dirs: bool = False,
) -> bool:
    """! @brief Copy or link to software files for an ASTERICS chain.
    Collect all available software driver files in 'drivers' folders
    of the module source directories in the output folder structure.
    @param chain: The current AsProcessingChain. Source of the modules list.
    @param output_folder: The root of the output folder structure.
    @param use_symlinks: Whether or not to link (True) or copy (False) files
    @param sep_dirs: Whether or not to generate separate directories per module driver
    @return True on success, False otherwise."""

    LOG.info("Gathering ASTERICS module software driver source files...")
    out_path = os.path.realpath(output_folder)
    # We don't want the trailing slash if we're not using separate folders
    out_path = append_to_path(out_path, "/", sep_dirs)
    # Collect all module entity names
    unique_modules = get_unique_modules(chain)
    modules = list(ittls.chain(chain.modules, chain.pipelines))
    handled_entities = []

    # Initialize driver list with asterics support package drivers
    drivers = [(
        "as_support",
        list(
            asp_driver.format(asterics_root=asterics_home)
            for asp_driver in ASP_FILES),
    )]

    for mod in modules:
        if mod.entity_name not in handled_entities:
            drivers.append((mod.entity_name, mod.driver_files))
            handled_entities.append(mod.entity_name)

    for entity in filter(lambda ent: ent not in handled_entities,
                         unique_modules):
        module = chain.library.get_module_template(entity)
        drivers.append((module.entity_name, module.driver_files))

    driver_dir = {}
    for entity, paths in drivers:
        if not paths:
            continue
        try:
            driver_dir[entity].extend(paths)
        except KeyError:
            driver_dir[entity] = paths

    for entity in driver_dir:
        driverlist = driver_dir[entity]
        if sep_dirs:
            # Build destination path: out + entity name (cut off trailing '/')
            dest_path = append_to_path(out_path, entity, False)
        else:
            # If drivers should not be stored in separate directories
            dest_path = out_path
        # Linking / copying the driver files
        # Get mode of operation
        mode = "link" if use_symlinks else "copy"
        copy_op = os.symlink if use_symlinks else copy

        for driverfile in driverlist:
            filename = driverfile.rsplit("/", maxsplit=1)[-1]
            dest_file = append_to_path(dest_path, filename, False)
            if os.path.exists(dest_file):
                os.unlink(dest_file)
            try:
                copy_op(driverfile, dest_file)
            except IOError as err:
                LOG.critical(
                    ("Could not %s driver file '%s' of module '%s'!"
                     " - '%s"),
                    mode,
                    filename,
                    entity,
                    str(err),
                )
                return False
    return True


## @}
示例#24
0
def gather_hw_files(chain: AsProcessingChain,
                    output_folder: str,
                    use_symlinks: bool = True) -> bool:
    """! @brief Copy or link to module VHDL files of an ASTERICS chain.
    Collect all required hardware descriptive files
    for the current ASTERICS system. Mainly looks at the AsModule.files,
    .module_dir and .dependencies attributes to find required files.
    @param chain: current processing chain
    @param output_folder: The root of the output folder structure
    @param use_symlinks: Whether or not to link (True) or copy (False) files
    @return  True on success, else False"""

    LOG.info("Gathering HDL source files...")
    out_path = os.path.realpath(output_folder)

    # Collect all module entity names
    unique_modules = get_unique_modules(chain)

    for entity in unique_modules:
        this_path = append_to_path(out_path, entity)
        try:
            os.makedirs(this_path, 0o755, exist_ok=True)
        except FileExistsError:
            pass
        module = chain.library.get_module_template(entity)
        if module is None:
            continue
        module_dir = os.path.realpath(module.module_dir)
        for hw_file in module.files:
            source = os.path.realpath(hw_file)
            if not hw_file.startswith("/"):
                comp = os.path.commonprefix([module_dir, source])
                if comp != module_dir:
                    # Append the file path to the module directory, cutting off '/'
                    source = append_to_path(module_dir,
                                            hw_file,
                                            add_trailing_slash=False)
            if not os.path.isfile(source):
                raise AsFileError(source, "File not found!")
            filename = source.rsplit("/", maxsplit=1)[-1]
            dest = this_path + filename

            LOG.debug("Gather HW files: Link '%s' to '%s'", source, dest)

            if use_symlinks:
                # Try to create a symlink
                try:
                    os.symlink(source, dest)
                except FileExistsError:
                    # If a symlink already exists, delete it and retry
                    os.unlink(dest)
                    try:
                        os.symlink(source, dest)
                    except IOError as err:
                        LOG.critical(
                            ("Could not link file '%s' of module '%s'!"
                             " - '%s'"),
                            filename,
                            entity,
                            str(err),
                        )
                        return False
                except IOError as err:
                    LOG.critical(
                        ("Could not link file '%s' of module '%s'! "
                         "- '%s'"),
                        filename,
                        entity,
                        str(err),
                    )
                    return False
            else:
                try:
                    copy(source, dest)
                except IOError as err:
                    LOG.critical(
                        ("Could not copy file '%s' of module '%s'!"
                         " - '%s'"),
                        filename,
                        entity,
                        str(err),
                    )
                    return False
    return True
def write_vivado_package_tcl(chain: AsProcessingChain,
                             output_path: str,
                             additions_c1: str = "") -> bool:
    """Write two TCL script fragments sourced by the packaging TCL script.
    This function generates Vivado-specific TCL commands!
    The first fragment is sourced very early in the packaging script and
    contains basic information like the project directory,
    source file directory, etc.
    The second fragment contains packaging commands setting up the
    AXI interface configuration.
    This function needs to access the toplevel modules in the current
    processing chain to generate the TCL code.

    Parameters:
    chain - AsProcessingChain: The current processing chain to build
    output_path - String: Toplevel folder of the current project
    Returns a boolean value: True on success, False otherwise"""

    as_iic_map_tcl_template = (
        "# Set up interface properties:\n"
        "ipx::add_bus_interface {iic_if_name} [ipx::current_core]\n"
        "set_property abstraction_type_vlnv xilinx.com:interface:iic_rtl:1.0 "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]\n"
        "set_property bus_type_vlnv xilinx.com:interface:iic:1.0 "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]\n"
        "set_property interface_mode master "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]\n"
        "set_property display_name asterics_{iic_if_name} "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]\n"
        "# IIC port mapping:\n"
        "ipx::add_port_map SCL_T [ipx::get_bus_interfaces {iic_if_name} "
        "-of_objects [ipx::current_core]]\n"
        "set_property physical_name {iic_signal_prefix}scl_out_enable "
        "[ipx::get_port_maps SCL_T -of_objects "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]]\n"
        "ipx::add_port_map SDA_O [ipx::get_bus_interfaces {iic_if_name} "
        "-of_objects [ipx::current_core]]\n"
        "set_property physical_name {iic_signal_prefix}sda_out "
        "[ipx::get_port_maps SDA_O -of_objects "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]]\n"
        "ipx::add_port_map SDA_I [ipx::get_bus_interfaces {iic_if_name} "
        "-of_objects [ipx::current_core]]\n"
        "set_property physical_name {iic_signal_prefix}sda_in "
        "[ipx::get_port_maps SDA_I -of_objects "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]]\n"
        "ipx::add_port_map SDA_T [ipx::get_bus_interfaces {iic_if_name} "
        "-of_objects [ipx::current_core]]\n"
        "set_property physical_name {iic_signal_prefix}sda_out_enable "
        "[ipx::get_port_maps SDA_T -of_objects "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]]\n"
        "ipx::add_port_map SCL_O [ipx::get_bus_interfaces {iic_if_name}"
        " -of_objects [ipx::current_core]]\n"
        "set_property physical_name {iic_signal_prefix}scl_out "
        "[ipx::get_port_maps SCL_O -of_objects "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]]\n"
        "ipx::add_port_map SCL_I [ipx::get_bus_interfaces {iic_if_name} "
        "-of_objects [ipx::current_core]]\n"
        "set_property physical_name {iic_signal_prefix}scl_in "
        "[ipx::get_port_maps SCL_I -of_objects "
        "[ipx::get_bus_interfaces {iic_if_name} -of_objects [ipx::current_core]]]\n"
    )

    # Class to manage the AXI interface information for the TCL packaging
    # script
    class TCL_AXI_Interface:
        """'Private' class capsuling methods to write the TCL fragments
        required for the packaging script for Xilinx targets."""

        # TCL command templates:
        bus_if_association_tcl_template = (
            "ipx::associate_bus_interfaces -clock {clk} -busif {busif} -clear "
            "[ipx::current_core]\n"
            "# ^ Dissassociate any signals with this AXI interface"
            " (to be save)\n"
            "# Associate the correct clock and reset signals\n"
            "ipx::associate_bus_interfaces -clock {clk} -reset {rst} "
            "-busif {busif} [ipx::current_core]\n"
            "# Store the interface object in a variable with known name\n"
            "set {ref} [ipx::get_bus_interfaces -of_objects "
            "[ipx::current_core] {busif}]\n")
        memory_map_tcl_template = (
            "ipx::remove_memory_map slave_s_axi [ipx::current_core]\n"
            "ipx::remove_memory_map {ref} [ipx::current_core]\n"
            "# ^ Remove any memory maps from the interface\n"
            "# (potentially) Re-add a memory map\n"
            "ipx::add_memory_map {mem_map_ref} [ipx::current_core]\n"
            "# Add a slave memory map reference\n"
            "set_property slave_memory_map_ref {mem_map_ref} ${ref}\n"
            "# Add an address block to the memory map "
            "using the above reference\n"
            "ipx::add_address_block {{{axi_type}}} [ipx::get_memory_maps "
            "{mem_map_ref} -of_objects [ipx::current_core]]\n"
            "# Set the address block range\n"
            "set_property range {{{mem_range}}} [ipx::get_address_blocks "
            "{{{axi_type}}} -of_objects [ipx::get_memory_maps "
            "{{{mem_map_ref}}}  -of_objects [ipx::current_core]]]\n")

        def __init__(self, axi_type: str):
            # Type of AXI interface ("AXI Slave" / "AXI Master")
            self.axi_type = axi_type
            self.refname = ""  # Variable name of this interface
            self.bus_if_name = ""  # Name of this bus interface in Vivado TCL
            self.clock_name = "_aclk"  # Name of the associated clock
            self.reset_name = "_aresetn"  # Name of the associated reset
            self.if_type = ""  # AXI slave register address block name (Slave)
            self.memory_range = 0  # Range of the address block (Slave)

        def update(self):
            """Update the clock and reset names
            after setting the bus interface name"""
            self.clock_name = self.bus_if_name + self.clock_name
            self.reset_name = self.bus_if_name + self.reset_name

        def get_tcl_bus_assoc_commands(self) -> str:
            """Generate the bus interface association TCL commands"""
            return self.bus_if_association_tcl_template.format(
                busif=self.bus_if_name,
                clk=self.clock_name,
                rst=self.reset_name,
                ref=self.refname,
            )

        def get_tcl_mem_commands(self) -> str:
            """Generate the memory mapping TCL commands"""
            if any((not self.if_type, not self.memory_range)):
                LOG.debug(
                    ("Generating TCL packaging script: Interface type "
                     "of slave memory range not set for '%s'!"),
                    self.bus_if_name,
                )
                return ""
            # Else ->
            return self.memory_map_tcl_template.format(
                ref=self.refname,
                axi_type=self.if_type,
                mem_range=self.memory_range,
                busif=self.bus_if_name,
                mem_map_ref=self.refname + "_mem_ref",
            )

    LOG.info("Generating TCL packaging scripts...")
    # Generate the necessary paths:
    # IP-Core project directory
    project_dir = append_to_path(os.path.realpath(output_path), "/")
    # Subdirectory containing the HDL sources
    hdl_dir = append_to_path(project_dir, "/hw/hdl/vhdl/")

    # Populate the fragment files with a generic file header
    content1 = TCL_HEADER.format(
        TCL1_NAME, "TCL fragment (1) part of the IP packaging TCL script")
    content2 = TCL_HEADER.format(
        TCL2_NAME, "TCL fragment (2) part of the IP packaging TCL script")

    # Generate the commands for the first basic fragment
    content1 += "\nset projdir " + project_dir
    content1 += "\nset hdldir " + hdl_dir
    if additions_c1:
        content1 += "\n" + additions_c1 + "\n"

    # Possible AXI interface types
    templates = ("AXI_Slave", "AXI_Master")

    for inter in chain.top.interfaces:
        temp = None
        if inter.type.lower() in ("axi_slave_external", "axi_master_external"):
            slave = templates[0] in inter.type
            if slave:
                # For AXI slaves: Populate the TCL AXI class
                temp = TCL_AXI_Interface(templates[0])
                # And set parameters for the memory map (slave registers)
                temp.memory_range = 65536
                temp.if_type = "axi_lite"
            else:
                temp = TCL_AXI_Interface(templates[1])
            temp.refname = (as_help.minimize_name(inter.name_prefix).replace(
                temp.axi_type.lower(), "").strip("_"))
            temp.bus_if_name = inter.ports[0].code_name.rsplit("_", 1)[0]

            # Set the reference name and update the clock and reset names
            temp.update()
            # Generate the bus association commands for all interfaces
            content2 += temp.get_tcl_bus_assoc_commands()
            if slave:
                # Only slaves have a memory map
                content2 += temp.get_tcl_mem_commands()

    # Build interface instantiation strings for as_iic modules
    iic_if_inst_str = ["\n"]
    for module in chain.modules:
        if module.entity_name == "as_iic":
            if_name = module.name
            top_if = chain.top.__get_interface_by_un_fuzzy__(
                module.get_interface("in",
                                     if_type="iic_interface").unique_name)
            if top_if is None:
                LOG.error(
                    ("Was not able to determine port names for IIC "
                     "interface '%s' - IIC interface not found!"),
                    if_name,
                )
                mod_prefix = ""
            else:
                mod_prefix = as_help.minimize_name(
                    top_if.name_prefix,
                    chain.NAME_FRAGMENTS_REMOVED_ON_TOPLEVEL)
            iic_if_inst_str.append(
                "#Instantiate interface for {}\n".format(if_name))
            iic_if_inst_str.append(
                as_iic_map_tcl_template.format(iic_signal_prefix=mod_prefix,
                                               iic_if_name=if_name))
            iic_if_inst_str.append(
                "# END Instantiate interface for {}\n\n".format(if_name))
    # Assemble the IIC interface string and add to the TCL fragment
    content2 += "\n".join(iic_if_inst_str)

    # Make sure both files are newline-terminated
    content1 += "\n"
    content2 += "\n"

    # Write fragment 1
    try:
        with open(project_dir + TCL1_NAME, "w") as file:
            file.write(content1)
    except IOError as err:
        LOG.error("Could not write '%s' in '%s'.", TCL1_NAME, project_dir)
        raise AsFileError(project_dir + TCL1_NAME, "Could not write file!",
                          str(err))

    # Write fragment 2
    try:
        with open(project_dir + TCL2_NAME, "w") as file:
            file.write(content2)
    except IOError as err:
        LOG.error("Could not write '%s' in '%s'.", TCL2_NAME, project_dir)
        raise AsFileError(project_dir + TCL2_NAME, "Could not write file!",
                          str(err))