def __init__(self, root, cfg_file, active_target, build_root=None): self._valid_ila_values = [1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072] self.root = root # define and create build root self.build_root_base = build_root if build_root is not None else os.path.join(root, 'build') # define build root for functional models self.build_root_functional_models = os.path.join(self.build_root_base, 'models') self.build_root = os.path.join(self.build_root_base, active_target) if not os.path.exists(self.build_root): mkdir_p(self.build_root) self.cfg_file = cfg_file # Initialize config dict self.cfg = Config(cfg_file=self.cfg_file) # Update config options by reading from config file self.cfg.update_config() # Try to initialize Inicio config_dict # TODO: add more reasonable defaults try: from inicio import config_dict self.cfg_dict = config_dict() except: self.cfg_dict = { 'TOOLS_xilinx': '', 'INICIO_TOOLS': '', 'TOOLS_iverilog': '', 'TOOLS_gtkwave': '' } # FPGA board configuration self.board = self._fetch_board() # Vivado configuration self.vivado_config = VivadoConfig(parent=self) # GtkWave configuration self.gtkwave_config = GtkWaveConfig(parent=self) # SimVision configuration self.simvision_config = SimVisionConfig(parent=self) # Icarus configuration self.icarus_config = IcarusConfig(parent=self) # Xcelium configuration self.xcelium_config = XceliumConfig(parent=self)
def wait_on_and_dump_trace(self, result_file=None, emu_time_scaled=True): """ Wait until the trace unit stopped recording data. Transmit this data to the host PC, store by default to the raw result file path, or a custom path provided by the user, and convert analog values from fixed-point to float. Finally store it to a .vcd file in the default location. :param result_file: Optionally, it is possible to provide a custom result file path. """ if result_file is not None: # Expand provided path, paths relative to project root are also supported result_path = expand_path(result_file, rel_path_reference=self.pcfg.root) # Create raw result path by adding _raw to the filename result_path_raw = os.path.join( os.path.dirname(result_path), os.path.basename(os.path.splitext(result_path)[0]) + '_raw' + os.path.splitext(result_path)[1]) print(f'Simulation results will be stored in:{result_path}') else: result_path = self.result_path result_path_raw = self.result_path_raw if not result_path: raise Exception( f'ERROR: provided result_file:{result_file} is not valid!') # wait until trace buffer is full self.sendline( f'wait_on_hw_ila -timeout {self.record_timeout} $ila_0_i') # transmit and dump trace buffer data to a CSV file self.sendline('current_hw_ila_data [upload_hw_ila_data $ila_0_i]') if not os.path.isdir(os.path.dirname(result_path_raw)): mkdir_p(os.path.dirname(result_path_raw)) self.sendline( f'write_hw_ila_data -csv_file -force {{{result_path_raw}}} [current_hw_ila_data]' ) # Convert to .vcd and from fixed-point to float ConvertWaveform(result_path_raw=result_path_raw, result_type_raw=self.result_type_raw, result_path=result_path, str_cfg=self.scfg, float_type=self.float_type, dt_scale=self.pcfg.cfg.dt_scale, emu_time_scaled=emu_time_scaled)
def build(self): """ Generate bitstream for FPGA target """ shutil.rmtree( self._prj_cfg.build_root ) # Remove target specific build dir to make sure there is no legacy mkdir_p(self._prj_cfg.build_root) self._setup_targets(target=self.act_fpga_target, gen_structures=True) # Check if active target is an FPGA target target = getattr(self, self.act_fpga_target) VivadoEmulation(target=target).build() statpro.statpro_update(statpro.FEATURES.anasymod_build_vivado)
def emulate(self, server_addr=None, convert_waveform=True): """ Program bitstream to FPGA and run simulation/emulation on FPGA :param server_addr: Address of Vivado hardware server used for communication to FPGA board """ if server_addr is None: server_addr = self.args.server_addr # create target object, but don't generate instrumentation structure again in case target object does not exist yet if not hasattr(self, self.act_fpga_target): self._setup_targets(target=self.act_fpga_target) # check if bitstream was generated for active fpga target target = getattr(self, self.act_fpga_target) if not os.path.isfile(getattr(target, 'bitfile_path')): raise Exception( f'Bitstream for active FPGA target was not generated beforehand; please do so before running emulation.' ) # create sim result folders if not os.path.exists(os.path.dirname(target.cfg.vcd_path)): mkdir_p(os.path.dirname(target.cfg.vcd_path)) if not os.path.exists(os.path.dirname(target.result_path_raw)): mkdir_p(os.path.dirname(target.result_path_raw)) # run the emulation VivadoEmulation(target=target).run_FPGA( start_time=self.args.start_time, stop_time=self.args.stop_time, server_addr=server_addr) statpro.statpro_update(statpro.FEATURES.anasymod_emulate_vivado) # post-process results if convert_waveform: ConvertWaveform(result_path_raw=target.result_path_raw, result_type_raw=target.cfg.result_type_raw, result_path=target.cfg.vcd_path, str_cfg=target.str_cfg, float_type=self.float_type, dt_scale=self._prj_cfg.cfg.dt_scale)
def models(self): """ Call gen.py to generate analog models. """ # make model directory, removing the old one if necessary rm_rf(self.cfg.model_dir) mkdir_p(self.cfg.model_dir) # run generator script gen_script = os.path.join(self._prj_root, 'gen.py') if 'PYTHON_MSDSL' in os.environ: python_name = os.environ['PYTHON_MSDSL'] else: python_name = which('python') call([ python_name, gen_script, '-o', self.cfg.model_dir, '--dt', str(self.dt) ])
def build(self, *args, **kwargs): """ Generate bitstream for FPGA target """ shutil.rmtree( self._prj_cfg.build_root ) # Remove target specific build dir to make sure there is no legacy mkdir_p(self._prj_cfg.build_root) self._setup_targets(target=self.act_fpga_target, gen_structures=True) # Check if active target is an FPGA target target = getattr(self, self.act_fpga_target) VivadoEmulation(target=target).build() # Build firmware for ctrl infrastructure if needed if target.cfg.fpga_sim_ctrl == FPGASimCtrl.UART_ZYNQ: self._build_firmware(*args, **kwargs) statpro.statpro_update(statpro.FEATURES.anasymod_build_vivado)
def launch(self, server_addr=None, debug=False): """ Program bitstream to FPGA, setup control infrastructure and wait for interactive commands. :param server_addr: Address of Vivado hardware server used for communication to FPGA board :param debug: Enable or disable debug mode when running an interactive simulation """ if server_addr is None: server_addr = self.args.server_addr # create target object, but don't generate instrumentation structure again in case target object does not exist yet if not hasattr(self, self.act_fpga_target): self._setup_targets(target=self.act_fpga_target, debug=debug) # check if bitstream was generated for active fpga target target = getattr(self, self.act_fpga_target) if not os.path.isfile(getattr(target, 'bitfile_path')): raise Exception( f'Bitstream for active FPGA target was not generated beforehand; please do so before running emulation.' ) # create sim result folders if not os.path.exists(os.path.dirname(target.cfg.vcd_path)): mkdir_p(os.path.dirname(target.cfg.vcd_path)) if not os.path.exists(os.path.dirname(target.result_path_raw)): mkdir_p(os.path.dirname(target.result_path_raw)) # launch the emulation ctrl_handle = VivadoEmulation(target=target).launch_FPGA( server_addr=server_addr) statpro.statpro_update(statpro.FEATURES.anasymod_emulate_vivado) # Return ctrl handle for interactive control return ctrl_handle
def models(self): """ Call gen.py to generate analog models. """ # make model directory, removing the old model directory if necessary rm_rf(self._build_root) # run generator script if 'PYTHON_MSDSL' in os.environ: python_name = os.environ['PYTHON_MSDSL'] else: python_name = which('python') for generator_source in self.generator_sources: # make model directory if necessary mkdir_p( os.path.join(self._build_root, generator_source.fileset, generator_source.name)) for file in generator_source.files: call([ python_name, file, '-o', os.path.join(self._build_root, generator_source.fileset, generator_source.name), '--dt', str(self.dt) ])
def build(self, *args, **kwargs): """ Generate bitstream for FPGA target """ shutil.rmtree( self._prj_cfg.build_root ) # Remove target specific build dir to make sure there is no legacy mkdir_p(self._prj_cfg.build_root) self._setup_targets(target=self.act_fpga_target, gen_structures=True) # Check if active target is an FPGA target target = getattr(self, self.act_fpga_target) VivadoEmulation(target=target).build() # Build firmware for ctrl infrastructure if needed, first # waiting a short time for outputs from Vivado to sync # to disk. This seems to be an issue with NFS. if target.cfg.fpga_sim_ctrl == FPGASimCtrl.UART_ZYNQ: time.sleep(1) self._build_firmware(*args, **kwargs) statpro.statpro_update(statpro.FEATURES.anasymod_build_vivado)
def simulate(self, unit=None, id=None, convert_waveform=True, flags=None): """ Run simulation on a pc target. 'flags' contains a list of simulator-specific flags, as a sort of escape hatch for features that are not yet supported natively through anasymod. """ # Remove target-specific build dir to make sure there are no old files. # However, don't fail when certain files can't be removed, because that # might indicate that a waveform window is open shutil.rmtree(self._prj_cfg.build_root, ignore_errors=True) mkdir_p(self._prj_cfg.build_root) self._setup_targets(target=self.act_cpu_target, gen_structures=True) target = getattr(self, self.act_cpu_target) # create sim result folder if not os.path.exists(os.path.dirname(target.cfg.vcd_path)): mkdir_p(os.path.dirname(target.cfg.vcd_path)) if not os.path.exists(os.path.dirname(target.result_path_raw)): mkdir_p(os.path.dirname(target.result_path_raw)) # pick simulator sim_cls = { 'icarus': IcarusSimulator, 'vivado': VivadoSimulator, 'xrun': XceliumSimulator }[self.args.simulator_name] # run simulation sim = sim_cls(target=target, flags=flags) if self.args.simulator_name == "xrun": sim.unit = unit sim.id = id sim.simulate() statpro.statpro_update(statpro.FEATURES.anasymod_sim + self.args.simulator_name) # post-process results if convert_waveform: ConvertWaveform(result_path_raw=target.result_path_raw, result_type_raw=target.cfg.result_type_raw, result_path=target.cfg.vcd_path, str_cfg=target.str_cfg, float_type=self.float_type, debug=self._prj_cfg.cfg.cpu_debug_mode, dt_scale=self._prj_cfg.cfg.dt_scale)
def _update_build_root(self, active_target): self.build_root = os.path.join(self.build_root_base, active_target) if not os.path.exists(self.build_root): mkdir_p(self.build_root)