Skip to content

Commit

Permalink
Merge pull request #8 in INICIO/anasymod from feature/interactive_vio…
Browse files Browse the repository at this point in the history
…_ctrl to devel/1_3_4

* commit 'fe6c74b3f7ab4cb8c3678c0be8df5da0bd303484': (41 commits)
  Small adaptations for PS Pilot INICIO_DEV-2029
  FIXED execute FPGA link to result root directory
  Revert "ADDED risetime in preserve function to avoid that our sqaure wave is interpolated in a wrong way."
  ADDED support in waveform conversion to also record signal changes that are not linked to a time event properly ADDED a flag to indicate whether or not a signal shall be associated to the original cycle count, or emu time
  fix broken master branch
  v0.2.0
  prepare for release
  try running sim/emu test through pytest
  fix missing requirement
  fix broken tests
  FIXED minor issue occurring after merge regarding msdsl changes on features that were newly added to anasymod and features from interactive sim ctrl that were not tested extensively before. UPDATED all existing testcases to be compliant to msdsl and svreal changes UPDATED anasymod interactive sim ctrl testcase from Steven to work with latest anasymod changes -> FPGA simulation case updated but not tested yet!!
  REMOVED hard wired path to vivado bin folder and make use of generic vivado path query feature.
  FIXED float_type instance attribute treatment in Analysis class. Previously, it was not initialized properly in case that msdsl plugin was not used.
  FIXED adding libraries for VHDL sources FIXED conversion from multi bit digital signals to integer ADDED Tobi's fix for displaying stdout when running external tools properly
  UPDATED documentation
  ADDED initial API for interactive FPGA sim control ADDED interactive testcase for filter example, is passing NOTE regression test will be added within Inicio 2.0 regression, until then the test needs to be started manually due to incompatibility of wexpect and any python IDE -> building the regression test is a little more cumbersome
  Fix build badge
  v0.1.9
  try to fix buildkite
  try to fix buildkite
  ...
  • Loading branch information
ponteset committed Mar 17, 2020
2 parents 25da3f1 + fe6c74b commit 6fc3c00
Show file tree
Hide file tree
Showing 62 changed files with 910 additions and 256 deletions.
36 changes: 36 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
steps:
- command: |
# set up environment
source /etc/environment
echo $$PATH
# create virtual environment
python3.7 -m venv venv
source venv/bin/activate
# upgrade pip
pip install -U pip
# install various python dependencies
pip install wheel
pip install pytest pytest-cov
# install anasymod
pip install -e .
# specify python location (needed for msdsl)
export PYTHON_MSDSL=`which python`
echo $$PYTHON_MSDSL
# run tests
pytest --cov-report=xml --cov=anasymod tests -v -r s
# upload coverage information
bash <(curl -s https://codecov.io/bash)
# deactivate virtual environment
deactivate
label: "test_emu"
timeout_in_minutes: 60
agents:
fpga_verif: "true"
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
*.log
*.egg-info
__pycache__

build
dist/
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include anasymod/verilog/*.*v
include anasymod/verilog/*.bd
16 changes: 6 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
# Introduction
# anasymod
[![BuildKite status](https://badge.buildkite.com/7f10348afca3b631bbbb2175919b9039101c2a5e55c3371460.svg?branch=master)](https://buildkite.com/stanford-aha/anasymod)
[![Code Coverage](https://codecov.io/gh/sgherbst/anasymod/branch/master/graph/badge.svg)](https://codecov.io/gh/sgherbst/anasymod)
[![License:BSD-3-Clause](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)

**anasymod** is a Python package for running FPGA emulations of mixed-signal systems. It supports digital blocks described with Verilog or VHDL and synthesizable analog models created using [msdsl](https://github.com/sgherbst/msdsl) and [svreal](https://github.com/sgherbst/svreal).
**anasymod** is a tool for running FPGA emulations of mixed-signal systems. It supports digital blocks described with Verilog or VHDL and synthesizable analog models created using [msdsl](https://github.com/sgherbst/msdsl) and [svreal](https://github.com/sgherbst/svreal).

# Installation

1. Open a terminal, and note the current directory, since the **pip** commands below will clone some code from GitHub and place it in a subdirectory called **src**. If you prefer to place the cloned code in a different directory, you can specify that by providing the **--src** flag to **pip**.
2. If you haven't already, install **msdsl** and **svreal**:
```shell
> pip install -e git+https://github.com/sgherbst/svreal.git#egg=svreal
> pip install -e git+https://github.com/sgherbst/msdsl.git#egg=msdsl
```
3. Then install **anasymod**.
```shell
pip install -e git+https://github.com/sgherbst/anasymod.git#egg=anasymod
> pip install anasymod
```

If you get a permissions error when running one of the **pip** commands, you can try adding the **--user** flag to the **pip** command. This will cause **pip** to install packages in your user directory rather than to a system-wide location.
Expand Down
70 changes: 42 additions & 28 deletions anasymod/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from anasymod.viewer.scansion import ScansionViewer
from anasymod.viewer.simvision import SimVisionViewer
from anasymod.emu.vivado_emu import VivadoEmulation
from anasymod.files import get_full_path, get_from_module, mkdir_p
from anasymod.files import get_full_path, get_from_anasymod, mkdir_p
from anasymod.sources import *
from anasymod.filesets import Filesets
from anasymod.defines import Define
Expand Down Expand Up @@ -94,20 +94,20 @@ def __init__(self, input=None, build_root=None, simulator_name=None, synthesizer
self._plugin_args = []
for plugin in self._prj_cfg.cfg.plugins:
try:
i = import_module(f"plugin.{plugin}")
i = import_module(f"{plugin}.plugin")
inst = i.CustomPlugin(prj_cfg=self._prj_cfg, cfg_file=self.cfg_file, prj_root=self.args.input)
self._plugins.append(inst)
setattr(self, inst._name, inst)
self._plugin_args.append(inst._return_args())
except:
raise KeyError(f"Could not process plugin:{plugin} properly! Check spelling")

# Set float type to true, in case floating-point data types are used during simulation.
# This is needed when converting result files.
self.float_type = True
for args in self._plugin_args:
if 'float' in args.__dict__.keys():
self.float_type = args.float
else:
self.float_type = True


#Set active target
self.set_target(self.args.active_target)
Expand Down Expand Up @@ -204,7 +204,7 @@ def setup_filesets(self):
if not custom_top:
#ToDo: check if file inclusion should be target specific -> less for simulation only for example
self.filesets.add_source(source=VerilogSource(files=os.path.join(self.args.input, 'tb.sv'), config_path=config_path, fileset=fileset))
get_from_module('anasymod', 'verilog', 'zynq_uart.bd')
get_from_anasymod('verilog', 'zynq_uart.bd')

# Set define variables specifying the emulator control architecture
# TODO: find a better place for these operations, and try to avoid directly accessing the config dictionary
Expand Down Expand Up @@ -273,9 +273,9 @@ def build(self):
Generate bitstream for FPGA target
"""

shutil.rmtree(self._prj_cfg.build_root) # Remove target speciofic build dir to make sure there is no legacy
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)
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)
Expand All @@ -293,6 +293,10 @@ def emulate(self, server_addr=None):
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')):
Expand All @@ -311,18 +315,27 @@ def emulate(self, server_addr=None):

# post-process results

ConvertWaveform(target=target, float_type=self.float_type)
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)

def launch(self, server_addr=None):
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')):
Expand All @@ -332,8 +345,8 @@ def launch(self, server_addr=None):
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.cfg.csv_path)):
mkdir_p(os.path.dirname(target.cfg.csv_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)
Expand All @@ -352,7 +365,7 @@ def simulate(self, unit=None, id=None):

shutil.rmtree(self._prj_cfg.build_root) # Remove target speciofic build dir to make sure there is no legacy
mkdir_p(self._prj_cfg.build_root)
self._setup_targets(target=self.act_cpu_target)
self._setup_targets(target=self.act_cpu_target, gen_structures=True)

target = getattr(self, self.act_cpu_target)

Expand Down Expand Up @@ -382,7 +395,11 @@ def simulate(self, unit=None, id=None):
statpro.statpro_update(statpro.FEATURES.anasymod_sim + self.args.simulator_name)

# post-process results
ConvertWaveform(target=target, float_type=self.float_type)
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)

def probe(self, name, emu_time=False):
"""
Expand All @@ -401,7 +418,7 @@ def probes(self):
probeobj = self._setup_probeobj(target=getattr(self, self.args.active_target))
return probeobj._probes()

def preserve(self, wave, risetime=None):
def preserve(self, wave):
"""
This function preserve the stepping of the waveform 'wave'. This is necessary, if limit checks should be
conducted on the waveform later on.
Expand All @@ -410,17 +427,13 @@ def preserve(self, wave, risetime=None):
:return: 2d numpy.ndarray
"""
if risetime is None:
timestep = (wave[0][-1]-wave[0][0])/len(wave[0]) # calculating average timestep
risetime = 0.001*timestep

temp_data = None
wave_step =[]

for d in wave.transpose():
if temp_data is not None:
if d[1] != temp_data:
wave_step.append([d[0]-risetime,temp_data]) #old value with same timestep to preserve stepping
wave_step.append([d[0],temp_data]) #old value with same timestep to preserve stepping
wave_step.append(d)
temp_data = d[1]

Expand Down Expand Up @@ -566,7 +579,7 @@ def _parse_args(self):
python analysis.py -i filter --models --sim --view
-i, --input: Path to project root directory of the project that shall be opened and worked with.
default=get_from_module('anasymod', 'tests', 'filter'))
default=None
--simulator_name: Simulator that shall be used for logic simulation.
default=icarus for windows, xrun for linux
Expand Down Expand Up @@ -621,7 +634,7 @@ def _parse_args(self):
pass


parser.add_argument('-i', '--input', type=str, default=get_from_module('anasymod', 'tests', 'filter'))
parser.add_argument('-i', '--input', type=str, default=None)
parser.add_argument('--simulator_name', type=str, default=default_simulator_name)
parser.add_argument('--synthesizer_name', type=str, default='vivado')
parser.add_argument('--viewer_name', type=str, default=default_viewer_name)
Expand All @@ -640,7 +653,7 @@ def _parse_args(self):

self.args, _ = parser.parse_known_args()

def _setup_targets(self, target):
def _setup_targets(self, target, gen_structures=False, debug=False):
"""
Setup targets for project.
This may differ from one project to another and needs customization.
Expand All @@ -659,7 +672,7 @@ def _setup_targets(self, target):
#######################################################
# Create and setup simulation target
#######################################################
self.__setattr__(target, CPUTarget(prj_cfg=self._prj_cfg, plugins=self._plugins, name=target))
self.__setattr__(target, CPUTarget(prj_cfg=self._prj_cfg, plugins=self._plugins, name=target, float_type=self.float_type))
getattr(getattr(self, target), 'assign_fileset')(fileset=filesets['default'])
if target in filesets:
getattr(getattr(self, target), 'assign_fileset')(fileset=filesets[target])
Expand All @@ -668,14 +681,14 @@ def _setup_targets(self, target):
getattr(getattr(getattr(self, target), 'cfg'), 'update_config')(subsection=target)
getattr(getattr(self, target), 'set_tstop')()
getattr(getattr(self, target), 'update_structure_config')()
if not getattr(getattr(getattr(self, target), 'cfg'), 'custom_top'):
if (not getattr(getattr(getattr(self, target), 'cfg'), 'custom_top') and gen_structures):
getattr(getattr(self, target), 'gen_structure')()

elif target in self.fpga_targets:
#######################################################
# Create and setup FPGA target
#######################################################
self.__setattr__(target, FPGATarget(prj_cfg=self._prj_cfg, plugins=self._plugins, name=target))
self.__setattr__(target, FPGATarget(prj_cfg=self._prj_cfg, plugins=self._plugins, name=target, float_type=self.float_type))
getattr(getattr(self, target), 'assign_fileset')(fileset=filesets['default'])
if target in filesets:
getattr(getattr(self, target), 'assign_fileset')(fileset=filesets[target])
Expand All @@ -685,8 +698,9 @@ def _setup_targets(self, target):
getattr(getattr(self, target), 'set_tstop')()
getattr(getattr(self, target), 'update_structure_config')()
if not getattr(getattr(getattr(self, target), 'cfg'), 'custom_top'):
getattr(getattr(self, target), 'setup_ctrl_ifc')()
getattr(getattr(self, target), 'gen_structure')()
getattr(getattr(self, target), 'setup_ctrl_ifc')(debug=debug)
if gen_structures:
getattr(getattr(self, target), 'gen_structure')()

# Copy generated sources by plugin from plugin build_root to target-specific build_root
for plugin in self._plugins:
Expand Down
9 changes: 5 additions & 4 deletions anasymod/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

from sys import platform
from glob import glob
from anasymod.files import get_full_path, get_from_module, mkdir_p
from anasymod.util import back2fwd, vivado_search_key
from anasymod.files import get_full_path, mkdir_p
from anasymod.util import vivado_search_key
from os import environ as env
from anasymod.enums import BoardNames
from anasymod.plugins import *
from anasymod.fpga_boards.boards import *
from anasymod.base_config import BaseConfig

class EmuConfig:
def __init__(self, root, cfg_file, active_target, build_root=None):

Expand Down Expand Up @@ -101,14 +102,14 @@ def __init__(self, parent: EmuConfig, vivado=None):
# set project name
self.project_name = 'project'
# intermediate variables for generic Xilinx path
if 'win' in platform.lower():
if platform in {'win32', 'cygwin'}:
xilinx_version_path = parent.cfg_dict['TOOLS_xilinx']
xilinx_version = "20" + ".".join(xilinx_version_path.split(".")[0:2]).split("-")[1]
# set path to vivado binary
self.hints = [lambda: os.path.join(env['VIVADO_INSTALL_PATH'], 'bin'),
lambda: os.path.join(parent.cfg_dict['INICIO_TOOLS'], xilinx_version_path, "Vivado", xilinx_version, "bin" ),]

if platform == 'linux' or platform == 'linux2':
if platform in {'linux', 'linux2'}:
sorted_dirs = sorted(glob('/tools/Xilinx/Vivado/*.*'), key=vivado_search_key)
self.hints.extend(lambda: os.path.join(dir_, 'bin') for dir_ in sorted_dirs)

Expand Down
4 changes: 3 additions & 1 deletion anasymod/emu/vivado_emu.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ def build(self):
self.writeln(f'read_ip "{back2fwd(file)}"')

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

# generate all IPs
self.writeln('generate_target all [get_ips]')
Expand Down
17 changes: 17 additions & 0 deletions anasymod/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class ConfigSections:
STRUCTURE = "STRUCTURE"
FPGASIM = "FPGASIM"


class BoardNames:
"""
Container including enums for all supported boards.
Expand All @@ -29,6 +30,7 @@ class BoardNames:
TE0720 = 'TE0720'
ARTY_200T_CUSTOM_LIDAR = 'ARTY_200T_CUSTOM_LIDAR'


class PortDir:
"""
Container including enums for all supported port directions.
Expand All @@ -37,20 +39,35 @@ class PortDir:
OUT = "output"
INOUT = "inout"


class TraceUnitOperators:
"""
Container including enums for all valid operators that can be used for setting up the trace unit
"""
EQUAL = 'eq'
NOTEQUAL = 'neq'
GREATER = 'gt'
GREATEREQUAL = 'gteq'
LESSER = 'lt'
LESSEREQUAL = 'lteq'


class CtrlOps:
"""
Container including enums for all supported control operations for controlling the FPGA.
"""
WRITE_PARAMETER = 0
READ_PARAMETER = 1


class FPGASimCtrl:
"""
Container including enums for all supported FPGA control interfaces.
"""
UART_ZYNQ = 'UART_ZYNQ'
VIVADO_VIO = 'VIVADO_VIO'


class ResultFileTypes:
"""
Container including enums for all supported data formats to store simulation/emulation results.
Expand Down
Loading

0 comments on commit 6fc3c00

Please sign in to comment.