def __init__(self, target: FPGATarget):
     super().__init__()
     self.project_dir = back2fwd(target.project_root)
     self.dcp_path = back2fwd(
         os.path.join(self.project_dir,
                      target.prj_cfg.vivado_config.project_name + r".runs",
                      r"synth_1", target.cfg.top_module + r".dcp"))
Beispiel #2
0
 def subst_path(self, drive):
     self.subst = drive
     if os.path.exists(self.subst):
         print(self.subst,
               " already exists, saving copy of existing subst path")
         self.old_subst = back2fwd(str(pathlib.Path(self.subst).resolve()))
         # deleting old subst
         self.writeln('exec subst ' + self.subst + ' /d')
     self.writeln('exec subst ' + self.subst + ' ' +
                  back2fwd(os.path.dirname(self.target.project_root)))
     project_root = self.subst + r"\\" + self.target.prj_cfg.vivado_config.project_name
     return project_root
Beispiel #3
0
 def add_vhdl_sources(self, vhdl_src):
     for src in vhdl_src:
         if src.files:
             self.add_files(src.files)
             if src.library is not None:
                 file_list = '{ ' + ' '.join('"' + back2fwd(file) + '"'
                                             for file in src.files) + ' }'
                 self.set_property('library',
                                   value=f'{{{src.library}}}',
                                   objects=f'[get_files {file_list}]')
             if src.version is not None:
                 file_list = '{ ' + ' '.join('"' + back2fwd(file) + '"'
                                             for file in src.files) + ' }'
                 self.set_property('file_type',
                                   value=f'{{{src.version}}}',
                                   objects=f'[get_files {file_list}]')
Beispiel #4
0
 def add_bd_file(self, bd_files: [BDFile]):
     for bd_file in bd_files:
         if bd_file.files:
             cmd = ['read_bd']
             cmd.append('{ ' + ' '.join('"' + back2fwd(file) + '"'
                                        for file in bd_file.files) + ' }')
             self.writeln(' '.join(cmd))
Beispiel #5
0
 def add_verilog_headers(self, ver_hdr):
     for src in ver_hdr:
         if src.files:
             self.add_files(src.files)
             file_list = '{ ' + ' '.join('"' + back2fwd(file) + '"'
                                         for file in src.files) + ' }'
             self.set_property('file_type', '{Verilog Header}',
                               f'[get_files {file_list}]')
Beispiel #6
0
 def add_ip_repo(self, ip_repos: [IPRepo]):
     for ip_repo in ip_repos:
         if ip_repo.files:
             self.set_property(name='ip_repo_paths',
                               value='{ ' +
                               ' '.join('"' + back2fwd(file) + '"'
                                        for file in ip_repo.files) + ' }',
                               objects='[current_project]')
     self.writeln('update_ip_catalog -rebuild')
Beispiel #7
0
 def add_verilog_sources(self, ver_src: [VerilogSource]):
     for src in ver_src:
         if src.files:
             self.add_files(src.files)
             if src.version is not None:
                 file_list = '{ ' + ' '.join('"' + back2fwd(file) + '"'
                                             for file in src.files) + ' }'
                 self.set_property('file_type',
                                   value=f'{{{src.version}}}',
                                   objects=f'[get_files {file_list}]')
Beispiel #8
0
    def add_files(self, files, norecurse=True, fileset=None):
        if files is None or len(files) == 0:
            # don't generate a command because add_files does not work with
            # an empty list of files
            return

        cmd = ['add_files']
        if fileset is not None:
            cmd.extend(['-fileset', fileset])
        if norecurse:
            cmd.append('-norecurse')
        cmd.append('{ ' + ' '.join('"' + back2fwd(file) + '"'
                                   for file in files) + ' }')
        self.writeln(' '.join(cmd))
Beispiel #9
0
    def __init__(self, ip_name, ip_module_name=None, props=None, ip_dir=None):
        super().__init__()
        # set defaults
        if props is None:
            props = {}

        if ip_module_name is None:
            ip_module_name = ip_name + '_0'

        self.ip_name = ip_name
        self.ip_module_name = ip_module_name
        self.ip_xci_path = back2fwd(
            os.path.join(ip_dir, ip_module_name, f'{ip_module_name}.xci'))

        self.props = props
Beispiel #10
0
    def create_project(self,
                       project_name,
                       project_directory,
                       force=False,
                       full_part_name=None,
                       board_part=None):
        # create the project
        cmd = ['create_project']
        if force:
            cmd.append('-force')
        cmd.append('"' + project_name + '"')
        cmd.append('"' + back2fwd(project_directory) + '"')
        if full_part_name is not None:
            cmd.extend(['-part', full_part_name])
        self.writeln(' '.join(cmd))

        # specify the board part if known
        if board_part is not None:
            self.writeln(
                f'set_property board_part {board_part} [current_project]')
    def __init__(self, pcfg: EmuConfig, scfg: StructureConfig, ltxfile_path,
                 server_addr: str):
        super().__init__(trim_blocks=False, lstrip_blocks=False)
        pcfg = pcfg
        scfg = scfg

        # set server address
        self.server_addr = server_addr

        # set the paths to the LTX file
        self.ltx_file = back2fwd(ltxfile_path)

        # set the JTAG frequency.  sometimes it is useful to try a slower frequency than default if there
        # are problems with the debug hub clock
        self.jtag_freq = str(int(pcfg.cfg.jtag_freq))

        # set the "short" device name which is used to distinguish the FPGA part from other USB devices
        self.device_name = pcfg.board.short_part_name

        # Set aliases for probes
        self.probe_aliases = SVAPI()
        for probe in scfg.digital_probes + scfg.analog_probes + [
                scfg.time_probe
        ]:
            self.probe_aliases.writeln(
                f'set {probe.name} [get_hw_probes "trace_port_gen_i/{probe.name}" -of_objects $ila_0_i]'
            )

        # Set radix for probes
        self.probe_radix = SVAPI()
        for digital_probe in (scfg.digital_probes + [scfg.time_probe]):
            signed = 'SIGNED' if digital_probe.signed else 'UNSIGNED'
            self.probe_radix.writeln(
                f'set_property DISPLAY_RADIX {signed} ${digital_probe.name}')

        for analog_probe in scfg.analog_probes:
            self.probe_radix.writeln(
                f'set_property DISPLAY_RADIX SIGNED ${analog_probe.name}')
    def __init__(self, pcfg: EmuConfig, scfg: StructureConfig, bitfile_path,
                 ltxfile_path, server_addr: str):
        super().__init__(trim_blocks=False, lstrip_blocks=False)
        pcfg = pcfg
        scfg = scfg

        # set server address
        self.server_addr = server_addr

        # set the paths to the BIT and LTX file
        self.bit_file = back2fwd(bitfile_path)
        self.ltx_file = back2fwd(ltxfile_path)

        # set the JTAG frequency.  sometimes it is useful to try a slower frequency than default if there
        # are problems with the debug hub clock
        self.jtag_freq = str(int(pcfg.cfg.jtag_freq))

        # save some parameters from the board configuration
        self.device_name = pcfg.board.short_part_name
        self.no_rev_check = pcfg.board.no_rev_check

        # Set aliases for VIOs
        self.ctrl_io_aliases = SVAPI()
        for io in scfg.digital_ctrl_inputs + scfg.digital_ctrl_outputs + \
                  scfg.analog_ctrl_inputs + scfg.analog_ctrl_outputs:
            self.ctrl_io_aliases.writeln(
                f'set {io.name} [get_hw_probes "sim_ctrl_gen_i/{io.name}" -of_objects $vio_0_i]'
            )

        # Set radix for VIOs
        self.ctrl_io_radix = SVAPI()
        for digital_in in scfg.digital_ctrl_inputs:
            signed = 'SIGNED' if digital_in.signed else 'UNSIGNED'
            self.ctrl_io_radix.writeln(
                f'set_property OUTPUT_VALUE_RADIX {signed} ${digital_in.name}')

        for digital_out in scfg.digital_ctrl_outputs:
            signed = 'SIGNED' if digital_out.signed else 'UNSIGNED'
            self.ctrl_io_radix.writeln(
                f'set_property INPUT_VALUE_RADIX {signed} ${digital_out.name}')

        for analog_in in scfg.analog_ctrl_inputs:
            self.ctrl_io_radix.writeln(
                f'set_property OUTPUT_VALUE_RADIX SIGNED ${analog_in.name}')

        for analog_out in scfg.analog_ctrl_outputs:
            self.ctrl_io_radix.writeln(
                f'set_property INPUT_VALUE_RADIX SIGNED ${analog_out.name}')

        # Set aliases for probes
        self.probe_aliases = SVAPI()
        for probe in scfg.digital_probes + scfg.analog_probes + [
                scfg.time_probe
        ]:
            self.probe_aliases.writeln(
                f'set {probe.name} [get_hw_probes "trace_port_gen_i/{probe.name}" -of_objects $ila_0_i]'
            )

        # Set radix for probes
        self.probe_radix = SVAPI()
        for digital_probe in (scfg.digital_probes + [scfg.time_probe]):
            signed = 'SIGNED' if digital_probe.signed else 'UNSIGNED'
            self.probe_radix.writeln(
                f'set_property DISPLAY_RADIX {signed} ${digital_probe.name}')

        for analog_probe in scfg.analog_probes:
            self.probe_radix.writeln(
                f'set_property DISPLAY_RADIX SIGNED ${analog_probe.name}')
Beispiel #13
0
 def set_header_files(self):
     file_list = '{ ' + ' '.join('"' + back2fwd(file) + '"'
                                 for file in self.files) + ' }'
     self.set_property('file_type', '{Verilog Header}',
                       f'[get_files {file_list}]')
Beispiel #14
0
    def build(self):
        #subst drive
        drive = 'V:'
        # Check if on-chip memory is sufficient on selected FPGA board
        if self.target.prj_cfg.board.bram is not None:
            bits_per_sample = 0
            probes = (self.target.str_cfg.digital_probes +
                      self.target.str_cfg.analog_probes +
                      [self.target.str_cfg.time_probe] +
                      [self.target.str_cfg.dec_cmp])
            for probe in probes:
                bits_per_sample += int(probe.width)
            if (bits_per_sample * self.target.prj_cfg.ila_depth) > (
                    self.target.prj_cfg.board.bram * 8):
                raise (
                    f'ERROR: Number ob samples to be recorded does not fit on FPGA board, please either select a '
                    f'board with more block memory, or change the ila_depth')
        else:
            print(
                f'WARNING: Check for sufficient BRAM could not be conducted, '
                f'not enough information given in board definition!')

        scfg = self.target.str_cfg
        """ type : StructureConfig """
        project_root = self.target.project_root
        # under Windows there is the problem with path length more than 146 characters, that's why we have to use
        # subst command to substitute project directory to a drive letter
        if os.name == 'nt':
            if len(back2fwd(self.target.project_root)) > 80:

                project_root = self.subst_path(drive=drive)

        # create a new project
        self.create_project(
            project_name=self.target.prj_cfg.vivado_config.project_name,
            project_directory=project_root,
            full_part_name=self.target.prj_cfg.board.full_part_name,
            board_part=self.target.prj_cfg.board.board_part,
            force=True)

        # add all source files to the project (including header files)
        self.add_project_sources(content=self.target.content)

        # define the top module
        self.set_property('top', f"{{{self.target.cfg.top_module}}}",
                          '[current_fileset]')

        # set define variables
        self.add_project_defines(content=self.target.content,
                                 fileset='[current_fileset]')

        # specify the level of flattening to use
        self.set_property('STEPS.SYNTH_DESIGN.ARGS.FLATTEN_HIERARCHY',
                          self.target.prj_cfg.cfg.flatten_hierarchy,
                          '[get_runs synth_1]')

        # append user constraints
        for xdc_file in self.target.content.xdc_files:
            for file in xdc_file.files:
                self.writeln(f'read_xdc "{back2fwd(file)}"')

        if not self.target.cfg.custom_top:
            # write constraints to file
            constrs = CodeGenerator()
            # generate constraints for external clk
            constrs.use_templ(TemplExtClk(target=self.target))
            # generate clock wizard IP core
            self.use_templ(TemplClkWiz(target=self.target))

            # Add IP cores necessary for control interface
            ip_core_templates = self.target.ctrl.add_ip_cores(
                scfg=scfg, ip_dir=self.target.ip_dir)
            for ip_core_template in ip_core_templates:
                self.use_templ(ip_core_template)

            ## Add constraints for additional generated emu_clks
            constrs.writeln(
                'create_generated_clock -name emu_clk -source [get_pins clk_gen_i/clk_wiz_0_i/clk_out1] -divide_by 2 [get_pins gen_emu_clks_i/buf_emu_clk/I]'
            )

            for k in range(scfg.num_gated_clks):
                constrs.writeln(
                    f'create_generated_clock -name clk_other_{k} -source [get_pins clk_gen_i/clk_wiz_0_i/clk_out1] -divide_by 4 [get_pins gen_emu_clks_i/buf_{k}/I]'
                )

            # Setup ILA for signal probing - only of at least one probe is defined
            if len(scfg.analog_probes + scfg.digital_probes +
                   [scfg.time_probe]) != 0:
                self.use_templ(
                    TemplILA(target=self.target,
                             depth=self.target.prj_cfg.ila_depth))

            # Setup Debug Hub
            constrs.use_templ(TemplDbgHub(target=self.target))

            # Add false paths for Zynq control signals.  This is necessary in some cases
            # to provide timing violations, since the ARM core is running on a different
            # clock that the emulator circuitry.  This is a real problem, but is handled
            # in firmware with handshaking and very short delays.
            if self.target.cfg.fpga_sim_ctrl == FPGASimCtrl.UART_ZYNQ:
                constrs.writeln(
                    'set_false_path -through [get_pins sim_ctrl_gen_i/zynq_gpio_i/*]'
                )

            # write master constraints to file and add to project
            master_constr_path = os.path.join(self.target.prj_cfg.build_root,
                                              'constrs.xdc')
            constrs.write_to_file(master_constr_path)
            self.add_files([master_constr_path], fileset='constrs_1')

        # read user-provided IPs
        self.writeln('# Custom user-provided IP cores')
        for xci_file in self.target.content.xci_files:
            for file in xci_file.files:
                self.writeln(f'read_ip "{back2fwd(file)}"')

        # read user-provided TCL scripts
        self.writeln('# Custom user-provided TCL scripts')
        for tcl_file in self.target.content.tcl_files:
            for file in tcl_file.files:
                self.writeln(f'source "{back2fwd(file)}"')

        # upgrade IPs as necessary
        self.writeln('if {[get_ips] ne ""} {')
        self.writeln('    upgrade_ip [get_ips]')
        self.writeln('}')

        # generate all IPs
        self.writeln('generate_target all [get_ips]')

        # create additional Hardware for control interface
        if self.target.cfg.fpga_sim_ctrl == FPGASimCtrl.UART_ZYNQ:
            self.use_templ(TemplZynqGPIO(is_ultrascale=scfg.is_ultrascale))

        # launch the build and wait for it to finish
        num_cores = min(int(self.target.prj_cfg.vivado_config.num_cores), 8)
        self.writeln(
            f'launch_runs impl_1 -to_step write_bitstream -jobs {num_cores}')
        self.writeln('wait_on_run impl_1')

        # re-generate the LTX file
        # without this step, the ILA probes are sometimes split into individual bits
        impl_dir = os.path.join(
            project_root,
            f'{self.target.prj_cfg.vivado_config.project_name}.runs',
            'impl_1',
        )

        ltx_file_path = os.path.join(impl_dir,
                                     f"{self.target.cfg.top_module}.ltx")

        self.writeln('open_run impl_1')
        self.writeln(
            f'write_debug_probes -force {{{back2fwd(ltx_file_path)}}}')

        # export the XSA if this is a more recent version of vivado
        if self.version_year >= 2020:
            xsa_file_path = os.path.join(impl_dir,
                                         f'{self.target.cfg.top_module}.xsa')
            xsa_file_path = back2fwd(xsa_file_path)
            self.writeln(
                f'write_hw_platform -fixed -include_bit -force -file {{{xsa_file_path}}}'
            )

        #remove and restore drive substitutions
        if self.subst:
            self.writeln('exec subst ' + self.subst + ' /d')
            if self.old_subst:
                self.writeln('exec subst ' + self.subst + ' ' + self.old_subst)

        # run bitstream generation
        ret_error = self.run(filename=r"bitstream.tcl",
                             stack=self.target.prj_cfg.cfg.vivado_stack,
                             return_error=True)
        if os.name == 'nt':
            if ret_error:
                #remove and restore drive substitutions
                if self.subst:
                    try:
                        subprocess.call(f'subst {drive} /d', shell=True)
                    except:
                        print(
                            f'WARNING: Removing mapped drive:{drive} did not work.'
                        )
                    if self.old_subst:
                        try:
                            subprocess.call(f'subst {drive} {self.old_subst}',
                                            shell=True)
                        except:
                            print(
                                f'WARNING: Mapping of drive:{drive} to network path: {self.old_subst} did not work.'
                            )
Beispiel #15
0
    def __init__(self, target):
        super().__init__(trim_blocks=True, lstrip_blocks=True)
        scfg = target.str_cfg
        """ :type: StructureConfig """

        pcfg = target.prj_cfg
        """ :type: EmuConfig """

        self.result_path_raw = back2fwd(target.result_path_raw)

        #####################################################
        # Add plugin specific includes
        #####################################################

        self.plugin_includes = SVAPI()
        for plugin in target.plugins:
            for include_statement in plugin.include_statements:
                self.plugin_includes.writeln(f'{include_statement}')

        #####################################################
        # Create module interface
        #####################################################
        self.module_ifc = SVAPI()

        module = ModuleInst(api=self.module_ifc, name='top')
        module.add_inputs(scfg.clk_i)
        if ((target.cfg.fpga_sim_ctrl is not None)
                and (target.cfg.fpga_sim_ctrl == FPGASimCtrl.UART_ZYNQ)
                and (not pcfg.board.is_ultrascale)):
            module.add_inouts(TemplZynqGPIO.EXT_IOS)
        module.generate_header()

        #####################################################
        # Manage clks
        #####################################################

        # Add clk in signals for simulation case
        self.clk_in_sim_sigs = SVAPI()

        for clk_i in scfg.clk_i:
            self.clk_in_sim_sigs.gen_signal(io_obj=clk_i)

        # Add dbg clk signals
        self.dbg_clk_sigs = SVAPI()
        self.dbg_clk_sigs.gen_signal(io_obj=scfg.dbg_clk)

        # Instantiation of clk_gen wrapper
        self.clk_gen_ifc = SVAPI()
        clk_gen = ModuleInst(api=self.clk_gen_ifc, name='clk_gen')
        clk_gen.add_inputs(scfg.clk_i, connections=scfg.clk_i)
        clk_gen.add_output(scfg.emu_clk_2x, connection=scfg.emu_clk_2x)
        clk_gen.add_output(scfg.dbg_clk, connection=scfg.dbg_clk)
        clk_gen.add_outputs(scfg.clk_independent,
                            connections=scfg.clk_independent)
        clk_gen.generate_instantiation()

        # Absolute path assignments for derived clks
        self.derived_clk_assigns = SVAPI()
        for k, clk in enumerate(scfg.clk_derived):
            self.derived_clk_assigns.writeln(f'// derived clock: {clk.name}')
            if clk.abspath_emu_dt is not None:
                self.derived_clk_assigns.writeln(
                    f'assign {clk.abspath_emu_dt} = emu_dt;')
            if clk.abspath_emu_clk is not None:
                self.derived_clk_assigns.writeln(
                    f'assign {clk.abspath_emu_clk} = emu_clk;')
            if clk.abspath_emu_rst is not None:
                self.derived_clk_assigns.writeln(
                    f'assign {clk.abspath_emu_rst} = emu_rst;')
            if clk.abspath_dt_req is not None:
                self.derived_clk_assigns.writeln(
                    f'assign dt_req_{clk.name} = {clk.abspath_dt_req};')
            if clk.abspath_gated_clk is not None:
                self.derived_clk_assigns.writeln(
                    f'assign clk_val_{clk.name} = {clk.abspath_gated_clk_req};'
                )
                self.derived_clk_assigns.writeln(
                    f'assign {clk.abspath_gated_clk} = clk_{clk.name};')

        self.num_dt_reqs = scfg.num_dt_reqs
        self.num_gated_clks = scfg.num_gated_clks

        #####################################################
        # Manage Ctrl Module
        #####################################################

        # provide information if default oscillator was used for template evaluation
        self.use_default_oscillator = scfg.use_default_oscillator

        ctrl_ios = scfg.analog_ctrl_inputs + scfg.analog_ctrl_outputs + scfg.digital_ctrl_inputs + \
                          scfg.digital_ctrl_outputs

        ## Instantiate all ctrl signals
        self.inst_itl_ctlsigs = SVAPI()
        for ctrl_io in ctrl_ios:
            self.inst_itl_ctlsigs.gen_signal(io_obj=ctrl_io)

        ## Instantiate ctrl module
        self.sim_ctrl_inst_ifc = SVAPI()
        sim_ctrl_inst = ModuleInst(api=self.sim_ctrl_inst_ifc,
                                   name='sim_ctrl_gen')
        sim_ctrl_inst.add_inputs(
            scfg.analog_ctrl_outputs + scfg.digital_ctrl_outputs,
            connections=scfg.analog_ctrl_outputs + scfg.digital_ctrl_outputs)
        sim_ctrl_inst.add_outputs(
            scfg.analog_ctrl_inputs + scfg.digital_ctrl_inputs,
            connections=scfg.analog_ctrl_inputs + scfg.digital_ctrl_inputs)

        ## Wire through Zynq connections if needed
        if ((target.cfg.fpga_sim_ctrl is not None)
                and (target.cfg.fpga_sim_ctrl == FPGASimCtrl.UART_ZYNQ)
                and (not pcfg.board.is_ultrascale)):
            sim_ctrl_inst.add_inouts(TemplZynqGPIO.EXT_IOS,
                                     connections=TemplZynqGPIO.EXT_IOS)

        # add master clk to ctrl module
        emu_clk_sig = DigitalSignal(name='emu_clk', width=1, abspath=None)
        sim_ctrl_inst.add_input(emu_clk_sig, emu_clk_sig)
        sim_ctrl_inst.generate_instantiation()

        ## Assign custom ctrl signals via abs paths into design
        self.assign_custom_ctlsigs = SVAPI()
        for ctrl_input in scfg.digital_ctrl_inputs + scfg.analog_ctrl_inputs:
            if ctrl_input.abs_path is not None:
                self.assign_custom_ctlsigs.assign_to(
                    io_obj=ctrl_input.abs_path, exp=ctrl_input.name)

        for ctrl_output in scfg.digital_ctrl_outputs + scfg.analog_ctrl_outputs:
            self.assign_custom_ctlsigs.assign_to(io_obj=ctrl_output.name,
                                                 exp=ctrl_output.abs_path)

        ######################################################
        # Manage trace port Module
        ######################################################

        probes = scfg.digital_probes + scfg.analog_probes + [
            scfg.time_probe
        ] + [scfg.dec_cmp]

        ## Instantiate all probe signals
        self.inst_probesigs = SVAPI()
        for probe in probes:
            self.inst_probesigs.gen_signal(probe)

        ## Instantiate traceport module
        self.num_probes = len(probes)
        self.trap_inst_ifc = SVAPI()
        trap_inst = ModuleInst(api=self.trap_inst_ifc, name='trace_port_gen')
        trap_inst.add_inputs(probes, connections=probes)
        trap_inst.add_input(scfg.emu_clk, connection=scfg.emu_clk)
        trap_inst.generate_instantiation()

        ## Assign probe signals via abs paths into design except for time probe
        self.assign_probesigs = SVAPI()
        for probe in scfg.digital_probes + scfg.analog_probes:
            self.assign_probesigs.assign_to(io_obj=probe, exp=probe.abs_path)

        ######################################################
        # Manage emulation clks Module
        ######################################################

        ## Instantiate all emulation clk signals
        self.inst_emu_clk_sigs = SVAPI()

        clk_io_pairs = []
        for derived_clk in scfg.clk_derived:
            if derived_clk.abspath_gated_clk is None:
                continue
            clk_val = digsig(f'clk_val_{derived_clk.name}')
            clk = digsig(f'clk_{derived_clk.name}')
            self.inst_emu_clk_sigs.gen_signal(clk_val)
            self.inst_emu_clk_sigs.gen_signal(clk)
            clk_io_pairs.append((clk_val, clk))

        # add default oscillator signals, in case default oscillator was used
        if self.use_default_oscillator:
            clk_val = digsig(f'clk_val_default_osc')
            clk = digsig(f'clk_default_osc')
            self.inst_emu_clk_sigs.gen_signal(clk_val)
            self.inst_emu_clk_sigs.gen_signal(clk)
            clk_io_pairs.append((clk_val, clk))

        ## Instantiate gen emulation clk module
        self.emu_clks_inst_ifc = SVAPI()

        emu_clks_inst = ModuleInst(api=self.emu_clks_inst_ifc,
                                   name="gen_emu_clks")
        emu_clks_inst.add_input(scfg.emu_clk_2x, connection=scfg.emu_clk_2x)
        emu_clks_inst.add_output(scfg.emu_clk, connection=scfg.emu_clk)

        for clk_val, clk in clk_io_pairs:
            emu_clks_inst.add_input(clk_val, connection=clk_val)
            emu_clks_inst.add_output(clk, connection=clk)

        emu_clks_inst.generate_instantiation()

        ######################################################
        # Manage default oscillator module
        ######################################################

        emu_dt = digsig('emu_dt', width=pcfg.cfg.dt_width)
        dt_req_default_osc = DigitalSignal(name=f'dt_req_default_osc',
                                           abspath='',
                                           width=pcfg.cfg.dt_width,
                                           signed=False)

        if scfg.use_default_oscillator:
            # instantiate API
            self.def_osc_api = SVAPI()

            # generate clock and reset signals

            # instantiate the default oscillator
            def_osc_inst = ModuleInst(api=self.def_osc_api,
                                      name='osc_model_anasymod',
                                      inst_name='def_osc_i')

            emu_dt_req = digsig('emu_dt_req', width=pcfg.cfg.dt_width)

            def_osc_inst.add_output(scfg.emu_clk, connection=scfg.emu_clk)
            def_osc_inst.add_output(scfg.reset_ctrl,
                                    connection=scfg.reset_ctrl)
            def_osc_inst.add_output(emu_dt, connection=emu_dt)
            def_osc_inst.add_output(emu_dt_req, connection=dt_req_default_osc)
            def_osc_inst.add_output(digsig('cke'),
                                    connection=digsig('clk_val_default_osc'))
            def_osc_inst.generate_instantiation()
        else:
            self.def_osc_api = None

        ######################################################
        # Manage time manager Module
        ######################################################

        ## Instantiate all time manager signals
        self.inst_timemanager_sigs = SVAPI()

        self.inst_timemanager_sigs.gen_signal(emu_dt)

        dt_reqs = []
        for derived_clk in scfg.clk_derived:
            if derived_clk.abspath_dt_req is None:
                continue
            dt_req_sig = digsig(f'dt_req_{derived_clk.name}',
                                width=pcfg.cfg.dt_width)
            self.inst_timemanager_sigs.gen_signal(dt_req_sig)
            dt_reqs.append(dt_req_sig)

        # add input for anasymod control dt request signal
        dt_req_stall = DigitalSignal(name=f'dt_req_stall',
                                     abspath='',
                                     width=pcfg.cfg.dt_width,
                                     signed=False)
        dt_reqs.append(dt_req_stall)

        # add input for dt request signal, in case a default oscillator is used
        if scfg.use_default_oscillator:
            dt_reqs.append(dt_req_default_osc)

        ## Instantiate time manager module
        self.time_manager_inst_ifc = SVAPI()
        time_manager_inst = ModuleInst(api=self.time_manager_inst_ifc,
                                       name='gen_time_manager')
        time_manager_inst.add_input(scfg.emu_clk, connection=scfg.emu_clk)
        time_manager_inst.add_input(scfg.reset_ctrl,
                                    connection=scfg.reset_ctrl)
        time_manager_inst.add_output(scfg.time_probe, scfg.time_probe)
        time_manager_inst.add_output(emu_dt, emu_dt)
        for dt_req_sig in dt_reqs:
            time_manager_inst.add_input(dt_req_sig, connection=dt_req_sig)

        time_manager_inst.generate_instantiation()

        ######################################################
        # Control module
        ######################################################

        self.ctrl_anasymod_inst_ifc = SVAPI()

        ctrl_anasymod_inst = ModuleInst(api=self.ctrl_anasymod_inst_ifc,
                                        name='ctrl_anasymod',
                                        inst_name='ctrl_anasymod_i')

        ctrl_anasymod_inst.add_input(scfg.emu_ctrl_data,
                                     connection=scfg.emu_ctrl_data)
        ctrl_anasymod_inst.add_input(scfg.emu_ctrl_mode,
                                     connection=scfg.emu_ctrl_mode)
        ctrl_anasymod_inst.add_input(scfg.time_probe,
                                     connection=scfg.time_probe)
        ctrl_anasymod_inst.add_input(scfg.dec_thr_ctrl,
                                     connection=scfg.dec_thr_ctrl)
        ctrl_anasymod_inst.add_input(scfg.emu_clk, connection=scfg.emu_clk)
        ctrl_anasymod_inst.add_input(scfg.reset_ctrl,
                                     connection=scfg.reset_ctrl)
        ctrl_anasymod_inst.add_output(scfg.dec_cmp, connection=scfg.dec_cmp)
        ctrl_anasymod_inst.add_output(dt_req_stall, connection=dt_req_stall)

        ctrl_anasymod_inst.generate_instantiation()

        # indicate whether TSTOP_MSDSL should be used
        self.use_tstop = target.cfg.tstop is not None

        #####################################################
        # Instantiate testbench
        #####################################################
        self.tb_inst_ifc = SVAPI()
        tb_inst = ModuleInst(api=self.tb_inst_ifc, name='tb')
        tb_inst.add_inputs(scfg.clk_independent,
                           connections=scfg.clk_independent)
        tb_inst.generate_instantiation()

        #####################################################
        # CPU debug mode
        #####################################################
        self.dump_debug_signals = SVAPI()
        if pcfg.cfg.cpu_debug_mode:
            dbg_mods_list = pcfg.cfg.cpu_debug_hierarchies
            if isinstance(dbg_mods_list, list):
                for dbg_module in dbg_mods_list:
                    if isinstance(dbg_module, list):
                        self.dump_debug_signals.writeln(
                            f'$dumpvars({dbg_module[0]}, {dbg_module[1]});')
                    elif isinstance(dbg_module, int) and len(
                            dbg_mods_list
                    ) == 2:  # only one single debug module was provided
                        self.dump_debug_signals.writeln(
                            f'$dumpvars({dbg_mods_list[0]}, {dbg_mods_list[1]});'
                        )
                        break
                    else:
                        raise Exception(
                            f'ERROR: unexpected format for cpu_debug_hierarchies attribute of '
                            f'project_config: {dbg_mods_list}, expecting a list including <depth>, '
                            f'<path_to_module> or a lists of such a list.')
            elif not dbg_mods_list:
                self.dump_debug_signals.writeln(f'$dumpvars(0, top.tb_i);')
            else:
                raise Exception(
                    f'ERROR: unexpected format for cpu_debug_hierarchies attribute of '
                    f'project_config: {dbg_mods_list}, expecting tuple, list or None'
                )
Beispiel #16
0
    def __init__(self, target: FPGATarget, start_time: float, stop_time: float,
                 server_addr: str):
        '''
        :param start_time:  Point in time from which recording run data will start
        :param stop_time:   Point in time where FPGA run will be stopped
        :param server_addr: Hardware server address for hw server launched by Vivado
        '''

        super().__init__(trim_blocks=False, lstrip_blocks=False)
        pcfg = target.prj_cfg
        scfg = target.str_cfg

        # set server address
        self.server_addr = server_addr

        # set the paths to the BIT and LTX file
        self.bit_file = back2fwd(target.bitfile_path)
        self.ltx_file = back2fwd(target.ltxfile_path)

        # set the JTAG frequency.  sometimes it is useful to try a slower frequency than default if there
        # are problems with the debug hub clock
        self.jtag_freq = str(int(pcfg.cfg.jtag_freq))

        # set the "short" device name which is used to distinguish the FPGA part from other USB devices
        self.device_name = pcfg.board.short_part_name

        # set the path where the CSV file of results from the ILA should be written
        self.output = back2fwd(target.result_path_raw)
        self.ila_reset = target.prj_cfg.vivado_config.ila_reset
        #tbd remove vio_reset
        self.vio_reset = target.prj_cfg.vivado_config.vio_reset

        # set the window count to half the ILA depth.  this is required because the window depth will be "2"
        # unfortunately a window depth of "1" is not allowed in "BASIC" capture mode, which needed to allow
        # decimation of the sampling rate.
        self.window_count = str(pcfg.ila_depth / 2)

        # calculate decimation ratio
        if stop_time is None:
            decimation_ratio_float = 2.0
        else:
            decimation_ratio_float = (
                (stop_time - start_time) / pcfg.cfg.dt) / (pcfg.ila_depth / 2)

        # enforce a minimum decimation ratio of 2x since the window depth is 2
        decimation_ratio_float = max(decimation_ratio_float, 2.0)

        # we have to subtract 1 from decimation ratio due to the FPGA implementation of this feature
        # that is, a decimation ratio setting of "1" actually corresponds to a decimation factor of "2"; a setting
        # of "2" corresponds to a decimation ratio of "3", and so on.
        decimation_ratio_setting = int(round(decimation_ratio_float)) - 1

        # determine starting time as an integer value
        time = target.str_cfg.time_probe
        start_time_int = int(round(start_time / pcfg.cfg.dt_scale))

        # export the decimation ratio, starting time, and time signal name to the template
        self.time_name = time.name
        self.decimation_ratio_setting = str(decimation_ratio_setting)
        self.start_time_int = f"{int(time.width)}'u{start_time_int}"

        # set display radix for analog probes
        # TODO: is it necessary to wrap the commands in "catch"?
        self.analog_probe_radix = []
        for probe in scfg.analog_probes:
            self.analog_probe_radix += [
                f'catch {{set_property DISPLAY_RADIX SIGNED [get_hw_probes trace_port_gen_i/{probe.name}]}}'
            ]
        self.analog_probe_radix = '\n'.join(self.analog_probe_radix)

        # set display radix for digital probes
        # TODO: is it necessary to wrap the commands in "catch"?
        self.digital_probe_radix = []
        for probe in (scfg.digital_probes + [scfg.time_probe]):
            signed = 'SIGNED' if probe.signed else 'UNSIGNED'
            self.digital_probe_radix += [
                f'catch {{set_property DISPLAY_RADIX {signed} [get_hw_probes trace_port_gen_i/{probe.name}]}}'
            ]
        self.digital_probe_radix = '\n'.join(self.digital_probe_radix)