diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 21b3a3c4bbefb604f149f9f30d2f0d695cd2ba14..c2fa9abe329270b6eb8450b734283426728a30f2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,7 +9,7 @@ test:rd53: - bash miniconda.sh -b -p $HOME/miniconda - export PATH=$HOME/miniconda/bin:$PATH - conda update --yes conda - - conda install --yes numpy bitarray pytest pyyaml scipy numba pytables pyqt matplotlib tqdm pyzmq blosc psutil pexpect coloredlogs + - conda install --yes numpy bitarray pytest pyyaml scipy numba pytables pyqt matplotlib tqdm pyzmq blosc psutil pexpect coloredlogs ptyprocess # Setup co-simulation - pip install cocotb==1.0.dev3 - git clone -b development --depth 1 https://github.com/SiLab-Bonn/basil.git; cd basil; python setup.py develop; cd ..; @@ -48,36 +48,43 @@ test:software: # - if [ -z "$CI_COMMIT_TAG"]; then git clone -b v3.0.0 --depth 1 https://github.com/SiLab-Bonn/basil.git; cd basil; python setup.py develop; cd ..; else git clone -b development --depth 1 https://github.com/SiLab-Bonn/basil.git; cd basil; python setup.py develop; cd ..; fi script: - python setup.py develop - - cd bdaq53/tests + # Try to activate conda evironment in the newest broken miniconda docker + - conda init bash # https://github.com/ContinuumIO/docker-images/issues/89 + - source ~/.bashrc # since ==> For changes to take effect, close and re-open your current shell. <== + - conda activate # to link properly to pytest # Do not run virtual x server tests (monitor) in this runner due to segfault - - pytest -v test_software --ignore=test_software/test_monitor.py + - pytest -v bdaq53/tests/test_software --ignore=bdaq53/tests/test_software/test_monitor.py # Tests that need bdaq53 readout hardware and RD53 FE +# Needs Ubuntu system with xvfb, Miniconda3 and full Xilinx installed and +# Gitlab-runner with shell executor: https://docs.gitlab.com/runner/executors/ test:hardware: allow_failure: true tags: # tags to differentiate runners able to run the job - hardware # Use Silab hardware runner - image: continuumio/miniconda3:latest # Ubuntu based miniconda image before_script: - # Update miniconda python and install required binary packages - - conda update --yes conda - - conda install --yes numpy bitarray pytest pyyaml scipy numba pytables pyqt matplotlib tqdm pyzmq blosc psutil pexpect coloredlogs + # Install required binary python packages + - export PATH=$HOME/miniconda/bin:$PATH + - conda install --yes numpy bitarray pytest pyyaml scipy numba pytables pyqt matplotlib tqdm pyzmq blosc psutil pexpect coloredlogs ptyprocess # Install virtual x server for matplotlib Qt error - - apt-get update - - apt-get install -y xvfb - pip install xvfbwrapper - # Install basil from github - - git clone -b development --depth 1 https://github.com/SiLab-Bonn/basil.git; cd basil; python setup.py develop; cd ..; - # - if [ -z "$CI_COMMIT_TAG"]; then git clone -b v3.0.0 --depth 1 https://github.com/SiLab-Bonn/basil.git; cd basil; python setup.py develop; cd ..; else git clone -b development --depth 1 https://github.com/SiLab-Bonn/basil.git; cd basil; python setup.py develop; cd ..; fi + # Update basil development from github + - git --git-dir=$HOME/git/basil/.git pull + # Clean SiTCP git checkout from potential preceding runner run + - rm -rf firmware/SiTCP/{*,.git} + - mkdir firmware/SiTCP + - touch firmware/SiTCP/.gitkeep # recreate gitkeep file script: - python setup.py develop - # FIXME: This should work - # - bdaq53 --firmware BDAQ53 # Flash newest development firmware - - cd bdaq53/tests - - pytest -v test_hardware + # Compile firmware if changes detected and flash + - if [[ `git diff ..development -- firmware` ]]; then bdaq53 --firmware BDAQ53_RX640 -c; bdaq53 --firmware BDAQ53_RX640.bit; else bdaq53 --firmware BDAQ53_RX640; fi + - pytest -v bdaq53/tests/test_hardware artifacts: + when: always # also upload verilog log on failure paths: + - "firmware/vivado/vivado.log" - "output_data/*.pdf" + - "BDAQ53_RX640.bit" expire_in: 1 month # Tests for code style violations in new code lines diff --git a/bdaq53/bdaq53.py b/bdaq53/bdaq53.py index 438ece2b66787ad9a297fa046dbe110475e50eaf..b55cd8622faf145a25efb9e8bd9551c4d86a2f1b 100644 --- a/bdaq53/bdaq53.py +++ b/bdaq53/bdaq53.py @@ -12,12 +12,8 @@ import time import struct import coloredlogs import numpy as np -import tables as tb - -from tables.exceptions import NoSuchNodeError from basil.dut import Dut -from basil.utils.BitLogic import BitLogic import pkg_resources VERSION = pkg_resources.get_distribution("bdaq53").version diff --git a/bdaq53/bdaq53_cli.py b/bdaq53/bdaq53_cli.py index 7879fe330043645903a2bc9e679985873231acfa..35a0eec9c8f13e04329ee0cfdbe7b563360361f4 100644 --- a/bdaq53/bdaq53_cli.py +++ b/bdaq53/bdaq53_cli.py @@ -12,7 +12,7 @@ import yaml from importlib import import_module from inspect import getmembers -from bdaq53 import firmware_downloader +from bdaq53 import firmware_manager logger = logging.getLogger('BDAQ53') @@ -68,10 +68,14 @@ def main(): nargs=1, help='Path of vivado installation',) + parser.add_argument('-c', '--compile', + action='store_true', + help='Compile firmware',) + args = parser.parse_args() if args.firmware is not None: - firmware_downloader.main(args.firmware[0], path=args.vivado_path[0]) + firmware_manager.main(args.firmware[0], path=args.vivado_path[0], create=args.compile) if args.scan: mod = import_module('bdaq53.scans.' + args.scan) diff --git a/bdaq53/firmware_downloader.py b/bdaq53/firmware_downloader.py deleted file mode 100644 index f8b766c4a897aa2009928d36fe89ce676264472e..0000000000000000000000000000000000000000 --- a/bdaq53/firmware_downloader.py +++ /dev/null @@ -1,257 +0,0 @@ -# -# ------------------------------------------------------------ -# Copyright (c) All rights reserved -# SiLab, Institute of Physics, University of Bonn -# ------------------------------------------------------------ -# - -import urllib -import re -import logging -import requests -import math -import pkg_resources -import tarfile -import os.path -from sys import platform -from tqdm import tqdm -import pexpect - -import bdaq53 - -repository = r'https://gitlab.cern.ch/silab/bdaq53/' - -firmware_dev_url = repository + r'wikis/Hardware/Firmware-(development-versions)' -firmware_url = repository + r'tags' - -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) - - -def get_web_page(url): - ''' Read web page. - ''' - response = urllib.request.urlopen(url) # Add md for markdown - return response.read() - - -def download_firmware(name, url): - ''' Download firmware tar.gz file from url - - The release firmwares are stored with the tag information (firmware_url) - and the development firmware is attached to a wiki page (firmware_dev_url) - ''' - response = get_web_page(url) - links = re.findall(r'\[%s\]\((.*?)\)' % name, response) - links = [repository + 'wikis/' + ''.join(link) for link in links] - - if not links: - all_firmwares = re.findall(r'%s(.*?)%s' % (r'/uploads/\w+/', '.tar.gz'), response) - logging.error('No firmware with name %s at %s\nPossible firmwares: %s', name, url, ', '.join(all_firmwares)) - return - if len(links) > 1: - raise RuntimeError('Found multiple firmwares with name %s at %s: %s', name, url, str(links)) - download_link = links[0] - logging.info('Downloading %s', download_link) - # Streaming, so we can iterate over the response. - r = requests.get(download_link, stream=True) - - # Total size in bytes. - total_size = int(r.headers.get('content-length', 0)) - block_size = 1024 - wrote = 0 - with open(name, 'wb') as f: - for data in tqdm(r.iter_content(block_size), total=math.ceil(total_size // block_size), unit='KB', unit_scale=True): - wrote = wrote + len(data) - f.write(data) - if total_size != 0 and wrote != total_size: - raise RuntimeError('Download failed!') - return name - - -def unpack_bit_file(name): - ''' Extracts the bit file from the tar.gz file - - name: string - Name of bit file (.tar.gz suffix) and - Name of compressed bitfile (name.bit) - ''' - tar = tarfile.open(name, "r:gz") - name_no_suffix = name[:name.find('.')] - for m in tar.getmembers(): - if name_no_suffix + '.bit' in m.name: - m.name = os.path.basename(m.name) # unpack without folder - tar.extract(m, path=".") - logging.debug('Unpacked %s', m.name) - tar.close() - return name_no_suffix + '.bit' - - -def flash_firmware(name): - ''' Flash firmware using vivado in tcl mode - ''' - - def get_return_string(timeout=1): - ''' Helper function to get full return string. - - More complexity needed here since Xilinx does multi line returns - ''' - flushed = '' - try: - while not vivado.expect(r'.+', timeout=timeout): - flushed += vivado.match.group(0) - except pexpect.exceptions.TIMEOUT: - pass - return flushed - - logger.info('Flash firmware %s', name) - - try: - vivado = pexpect.spawn('vivado_lab -mode tcl', timeout=10) # try lab version - vivado.expect('Vivado', timeout=5) - except pexpect.exceptions.ExceptionPexpect: - try: - vivado = pexpect.spawn('vivado -mode tcl', timeout=10) # try full version - vivado.expect('Vivado', timeout=5) - except pexpect.exceptions.ExceptionPexpect: - logger.error('Cannot execute vivado / vivado_lab commend') - return - vivado.expect(['vivado_lab%', 'Vivado%']) # Booted up when showing prompt - - vivado.sendline('open_hw') - vivado.expect(['vivado_lab%', 'Vivado%']) # Command finished when showing prompt - - vivado.sendline('connect_hw_server') - vivado.expect('localhost') # Printed when successfull - get_return_string() - - vivado.sendline('current_hw_target') - ret = get_return_string() - if 'WARNING' in ret: - logger.error('Cannot find programmer hardware, Xilinx warning:\n%s', ret) - vivado.sendline('exit') - vivado.expect('Exiting') - return - - vivado.sendline('open_hw_target') - vivado.expect('Opening hw_target') # Printed when programmer found - - vivado.sendline('current_hw_device [lindex [get_hw_devices] 0]') - vivado.expect(['vivado_lab%', 'Vivado%']) # Printed when finished - - vivado.sendline('set devPart [get_property PART [current_hw_device]]') - vivado.expect(['vivado_lab%', 'Vivado%']) # Printed when finished - - vivado.sendline('set_property PROGRAM.FILE {%s} [current_hw_device]' % name) - vivado.expect(['vivado_lab%', 'Vivado%']) # Printed when finished - - vivado.sendline('program_hw_devices [current_hw_device]') - vivado.expect('End of startup status: HIGH') # firmware upload successfull - - vivado.sendline('exit') - vivado.expect('Exiting') - - logger.info('SUCCESS!') - - -def find_vivado(path): - ''' Search in std. installation paths for vivado(_lab) binary - ''' - - if platform == "linux" or platform == "linux2": - linux_install_path = '/opt/' if not path else path - # Try vivado full install - paths = where(name='vivado', path=linux_install_path) - for path in paths: - if 'bin' in path: - return os.path.dirname(os.path.realpath(path)) - # Try vivado lab install - paths = where(name='vivado_lab', path=linux_install_path) - for path in paths: - if 'bin' in path: - return os.path.dirname(os.path.realpath(path)) - else: - raise NotImplementedError('Only Linux supported thus far') - - -def where(name, path, flags=os.F_OK): - result = [] - paths = [path] - for outerpath in paths: - for innerpath, _, _ in os.walk(outerpath): - path = os.path.join(innerpath, name) - if os.access(path, flags): - result.append(os.path.normpath(path)) - return result - - -def main(name, path=None): - ''' All steps to upload matching firmware to FPGA - - If name has .bit suffix try to flash from local file - If not available find suitable firmware online, download, extract, and flash - ''' - - vivado_path = find_vivado(path) - if vivado_path: - logger.debug('Found vivado binary at %s', vivado_path) - os.environ["PATH"] += os.pathsep + vivado_path - else: - if path: - logger.error('Cannot find vivado installation in %s', path) - else: - logger.error('Cannot find vivado installation! Install vivado lab from here:\nhttps://www.xilinx.com/support/download.html') - return - - if os.path.isfile(name): - logger.info('Found existing local bit file') - bit_file = name - else: - if not name.endswith('.tar.gz'): - name += '.tar.gz' - stable_firmware = True # std. setting: use stable (tag) firmware - version = pkg_resources.get_distribution("bdaq53").version - try: - import git - try: - bdaq53_path = os.path.dirname(bdaq53.__file__) - repo = git.Repo(search_parent_directories=True, path=bdaq53_path) - active_branch = repo.active_branch - if active_branch != 'master': - stable_firmware = False # use development firmware - except git.InvalidGitRepositoryError: # no github repo --> use stable firmware - pass - except ImportError: # git not available - logger.warning( - 'Git not properly installed, assume software release %s', version) - pass - if stable_firmware: - tag_list = get_tag_list(firmware_url) - matches = [i for i in range(len(tag_list)) if version in tag_list[i]] - if not matches: - raise RuntimeError('Cannot find tag version %s at %s', version, firmware_url) - tag_url = firmware_url + '/' + tag_list[matches[0]] - logger.info('Download stable firmware version %s', version) - archiv_name = download_firmware(name, tag_url) - else: - logger.info('Download development firmware') - archiv_name = download_firmware(name, firmware_dev_url + '.md') - if not archiv_name: - return - bit_file = unpack_bit_file(archiv_name) - flash_firmware(bit_file) - - -def get_tag_list(url): - ''' Extracts all tag names from firmware_url - - This is needed since the naming scheme is inconsistent - ''' - - response = get_web_page(url) - return re.findall(r'href="/silab/bdaq53/tags/(.*?)"', response) - - -if __name__ == '__main__': - logging.basicConfig(level=logging.DEBUG) - main('BDAQ53_RX640') diff --git a/bdaq53/firmware_manager.py b/bdaq53/firmware_manager.py new file mode 100644 index 0000000000000000000000000000000000000000..3279664e4a571c76b895c77236260525e515b003 --- /dev/null +++ b/bdaq53/firmware_manager.py @@ -0,0 +1,407 @@ +# +# ------------------------------------------------------------ +# Copyright (c) All rights reserved +# SiLab, Institute of Physics, University of Bonn +# ------------------------------------------------------------ +# + +''' Module to manage firmware download, compilation and flashing using vivado. + Mainly for CI runner but also useful during headless session (e.g. test beams) +''' + +import urllib +import re +import logging +import requests +import math +import fileinput +import pkg_resources +import tarfile +import shutil +import os.path +from sys import platform + +import pexpect +from tqdm import tqdm +import git + +import bdaq53 + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + +repository = r'https://gitlab.cern.ch/silab/bdaq53/' +firmware_dev_url = repository + r'wikis/Hardware/Firmware-(development-versions)' +firmware_url = repository + r'tags' + +sitcp_repo = r'https://github.com/BeeBeansTechnologies/SiTCP_Netlist_for_Kintex7' + +bdaq53_path = os.path.dirname(bdaq53.__file__) + + +def get_web_page(url): + ''' Read web page. + ''' + response = urllib.request.urlopen(url) # Add md for markdown + return response.read().decode('utf-8') + + +def download_firmware(name, url): + ''' Download firmware tar.gz file from url + + The release firmwares are stored with the tag information (firmware_url) + and the development firmware is attached to a wiki page (firmware_dev_url) + ''' + response = get_web_page(url) + links = re.findall(r'\[%s\]\((.*?)\)' % name, response) + links = [repository + 'wikis/' + ''.join(link) for link in links] + + if not links: + all_firmwares = re.findall(r'%s(.*?)%s' % (r'/uploads/\w+/', '.tar.gz'), response) + logging.error('No firmware with name %s at %s\nPossible firmwares: %s', name, url, ', '.join(all_firmwares)) + return + if len(links) > 1: + raise RuntimeError('Found multiple firmwares with name %s at %s: %s', name, url, str(links)) + download_link = links[0] + logging.info('Downloading %s', download_link) + # Streaming, so we can iterate over the response. + r = requests.get(download_link, stream=True) + + # Total size in bytes. + total_size = int(r.headers.get('content-length', 0)) + block_size = 1024 + wrote = 0 + with open(name, 'wb') as f: + for data in tqdm(r.iter_content(block_size), total=math.ceil(total_size // block_size), unit='KB', unit_scale=True): + wrote = wrote + len(data) + f.write(data) + if total_size != 0 and wrote != total_size: + raise RuntimeError('Download failed!') + return name + + +def unpack_bit_file(name): + ''' Extracts the bit file from the tar.gz file + + name: string + Name of bit file (.tar.gz suffix) and + Name of compressed bitfile (name.bit) + ''' + tar = tarfile.open(name, "r:gz") + name_no_suffix = name[:name.find('.')] + for m in tar.getmembers(): + if name_no_suffix + '.bit' in m.name: + m.name = os.path.basename(m.name) # unpack without folder + tar.extract(m, path=".") + logging.debug('Unpacked %s', m.name) + tar.close() + return name_no_suffix + '.bit' + + +def flash_firmware(name): + ''' Flash firmware using vivado in tcl mode + ''' + + def get_return_string(timeout=1): + ''' Helper function to get full return string. + + This complexity needed here since Xilinx does multi line returns + ''' + flushed = bytearray() + try: + while not vivado.expect(r'.+', timeout=timeout): + flushed += vivado.match.group(0) + except pexpect.exceptions.TIMEOUT: + pass + return flushed.decode('utf-8') + + logger.info('Flash firmware %s', name) + + try: + vivado = pexpect.spawn('vivado_lab -mode tcl', timeout=10) # try lab version + vivado.expect('Vivado', timeout=5) + except pexpect.exceptions.ExceptionPexpect: + try: + vivado = pexpect.spawn('vivado -mode tcl', timeout=10) # try full version + vivado.expect('Vivado', timeout=5) + except pexpect.exceptions.ExceptionPexpect: + logger.error('Cannot execute vivado / vivado_lab commend') + return + vivado.expect(['vivado_lab%', 'Vivado%']) # Booted up when showing prompt + + vivado.sendline('open_hw') + vivado.expect(['vivado_lab%', 'Vivado%']) # Command finished when showing prompt + + vivado.sendline('connect_hw_server') + vivado.expect('localhost') # Printed when successfull + get_return_string() + + vivado.sendline('current_hw_target') + ret = get_return_string() + if 'WARNING' in ret: + logger.error('Cannot find programmer hardware, Xilinx warning:\n%s', ret) + vivado.sendline('exit') + vivado.expect('Exiting') + return + + vivado.sendline('open_hw_target') + vivado.expect('Opening hw_target') # Printed when programmer found + + vivado.sendline('current_hw_device [lindex [get_hw_devices] 0]') + vivado.expect(['vivado_lab%', 'Vivado%']) # Printed when finished + + vivado.sendline('set devPart [get_property PART [current_hw_device]]') + vivado.expect(['vivado_lab%', 'Vivado%']) # Printed when finished + + vivado.sendline('set_property PROGRAM.FILE {%s} [current_hw_device]' % name) + vivado.expect(['vivado_lab%', 'Vivado%']) # Printed when finished + + vivado.sendline('program_hw_devices [current_hw_device]') + vivado.expect('End of startup status: HIGH') # firmware upload successfull + + vivado.sendline('exit') + vivado.expect('Exiting') + + logger.info('SUCCESS!') + + +def compile_firmware(name): + ''' Compile firmware using vivado in tcl mode + ''' + + def get_return_string(timeout=1): + ''' Helper function to get full return string. + + This complexity needed here since Xilinx does multi line returns + ''' + flushed = bytearray() + try: + while not vivado.expect(r'.+', timeout=timeout): + flushed += vivado.match.group(0) + except (pexpect.exceptions.TIMEOUT, pexpect.exceptions.EOF): + pass + return flushed.decode('utf-8') + + supported_firmwares = ['BDAQ53', 'USBPIX3', 'KC705', + 'BDAQ53_RX640', 'USBPIX3_RX640', 'KC705_RX640'] + if name not in supported_firmwares: + logger.error('Can only compile firmwares: %s', ','.join(supported_firmwares)) + return + + logger.info('Compile firmware %s', name) + + vivado_tcl = os.path.join(bdaq53_path, '..', 'firmware/vivado') + + # Use mappings from run.tcl + fpga_types = {'BDAQ53': 'xc7k160tffg676-2', + 'USBPIX3': 'xc7k160tfbg676-1', + 'KC705': 'xc7k325tffg900-2'} + constrains_files = {'BDAQ53': '../src/bdaq53.xdc', + 'USBPIX3': '../src/usbpix3.xdc', + 'KC705': '../src/kc705_gmii.xdc'} + flash_sizes = {'BDAQ53': '64', + 'USBPIX3': '64', + 'KC705': '16'} + + for k, v in fpga_types.items(): + if k in name: + fpga_type = v + constrain_files = constrains_files[k] + flash_size = flash_sizes[k] + board_name = k + + if '_SMA' in name: + connector = '_SMA' + elif '_FMC_LPC' in name: + connector = '_FMC_LPC' + else: + connector = '""' + + if 'RX640' in name: + option = '_RX640' + else: + option = '""' + + command_args = fpga_type + ' ' + board_name + ' ' + connector + ' ' + constrain_files + ' ' + flash_size + ' ' + option + command = 'vivado -mode tcl -source run.tcl -tclargs %s' % command_args + logger.info('Compiling firmware. Takes about 10 minutes!') + try: + vivado = pexpect.spawn(command, cwd=vivado_tcl, timeout=10) + vivado.expect('Vivado', timeout=5) + except pexpect.exceptions.ExceptionPexpect: + logger.error('Cannot execute vivado command %d.\nMaybe paid version is missing, that is needed for compilation?', command) + return + + import time + timeout = 10 # 50 seconds with no new print to screen + t = 0 + while t < timeout: + r = get_return_string() + if r: + if 'write_cfgmem completed successfully' in r: + break + print('.', end='', flush=True) + t = 0 + else: + time.sleep(5) + t += 1 + else: + raise RuntimeError('Timeout during compilation, check vivado.log') + + # Move firmware to current folder + cwd = os.getcwd() + vivado_tcl = os.path.join(bdaq53_path, '..', 'firmware/vivado') + shutil.move(os.path.join(vivado_tcl, r'output/%s' % name + '.bit'), cwd) + logger.info('SUCCESS!') + + +def find_vivado(path): + ''' Search in std. installation paths for vivado(_lab) binary + ''' + + if platform == "linux" or platform == "linux2": + linux_install_path = '/opt/' if not path else path + # Try vivado full install + paths = where(name='vivado', path=linux_install_path) + for path in paths: + if 'bin' in path: + return os.path.dirname(os.path.realpath(path)) + # Try vivado lab install + paths = where(name='vivado_lab', path=linux_install_path) + for path in paths: + if 'bin' in path: + return os.path.dirname(os.path.realpath(path)) + else: + raise NotImplementedError('Only Linux supported') + + +def where(name, path, flags=os.F_OK): + result = [] + paths = [path] + for outerpath in paths: + for innerpath, _, _ in os.walk(outerpath): + path = os.path.join(innerpath, name) + if os.access(path, flags): + result.append(os.path.normpath(path)) + return result + + +def main(name, path=None, create=False): + ''' Steps to download/compile/flash matching firmware to FPGA + + name: str + Firmware name: + If name has .bit suffix try to flash from local file + If not available find suitable firmware online, download, extract, and flash + compile: boolean + Compile firmware + ''' + + vivado_path = find_vivado(path) + if vivado_path: + logger.debug('Found vivado binary at %s', vivado_path) + os.environ["PATH"] += os.pathsep + vivado_path + else: + if path: + logger.error('Cannot find vivado installation in %s', path) + else: + logger.error('Cannot find vivado installation!') + if not create: + logger.error('Install vivado lab from here:\nhttps://www.xilinx.com/support/download.html') + else: + logger.error('Install vivado paid version to be able to compile firmware') + return + + if not create: + if os.path.isfile(name): + logger.info('Found existing local bit file') + bit_file = name + else: + if not name.endswith('.tar.gz'): + name += '.tar.gz' + stable_firmware = True # std. setting: use stable (tag) firmware + version = pkg_resources.get_distribution("bdaq53").version + if not os.getenv('CI'): + try: + import git + try: + repo = git.Repo(search_parent_directories=True, path=bdaq53_path) + active_branch = repo.active_branch + if active_branch != 'master': + stable_firmware = False # use development firmware + except git.InvalidGitRepositoryError: # no github repo --> use stable firmware + pass + except ImportError: # git not available + logger.warning('Git not properly installed, assume software release %s', version) + pass + if stable_firmware: + tag_list = get_tag_list(firmware_url) + matches = [i for i in range(len(tag_list)) if version in tag_list[i]] + if not matches: + raise RuntimeError('Cannot find tag version %s at %s', version, firmware_url) + tag_url = firmware_url + '/' + tag_list[matches[0]] + logger.info('Download stable firmware version %s', version) + archiv_name = download_firmware(name, tag_url) + else: + logger.info('Download development firmware') + archiv_name = download_firmware(name, firmware_dev_url + '.md') + else: # always use development version for CI runner + archiv_name = download_firmware(name, firmware_dev_url + '.md') + if not archiv_name: + return + bit_file = unpack_bit_file(archiv_name) + flash_firmware(bit_file) + else: + get_si_tcp() # get missing SiTCP sources + compile_firmware(name) + + +def get_tag_list(url): + ''' Extracts all tag names from firmware_url + + This is needed since the naming scheme is inconsistent + ''' + + response = get_web_page(url) + return re.findall(r'href="/silab/bdaq53/tags/(.*?)"', response) + + +def get_si_tcp(): + ''' Download SiTCP sources from official github repo and apply patches + ''' + + def line_prepender(filename, line): + with open(filename, 'rb+') as f: + content = f.read() + f.seek(0, 0) + # Python 3, wtf? + add = bytearray() + add.extend(map(ord, line)) + add.extend(map(ord, '\n')) + f.write(add + content) + + sitcp_folder = os.path.join(bdaq53_path, '..', 'firmware/SiTCP/') + + # Only download if not already existing SiTCP git repository + if not os.path.isdir(os.path.join(sitcp_folder, '.git')): + logger.info('Downloading SiTCP') + + # Has to be moved to be allowed to use existing folder for git checkout + shutil.move(sitcp_folder + '.gitkeep', os.path.join(sitcp_folder, '..')) + git.Repo.clone_from(url=sitcp_repo, + to_path=sitcp_folder, branch='master') + shutil.move(os.path.join(sitcp_folder, '..', '.gitkeep'), sitcp_folder) + # Patch sources, see README of bdaq53 + line_prepender(filename=sitcp_folder + 'TIMER.v', line=r'`default_nettype wire') + line_prepender(filename=sitcp_folder + 'WRAP_SiTCP_GMII_XC7K_32K.V', line=r'`default_nettype wire') + for line in fileinput.input([sitcp_folder + 'WRAP_SiTCP_GMII_XC7K_32K.V'], inplace=True): + print(line.replace("assign\tMY_IP_ADDR[31:0]\t= (~FORCE_DEFAULTn | (EXT_IP_ADDR[31:0]==32'd0) \t? DEFAULT_IP_ADDR[31:0]\t\t: EXT_IP_ADDR[31:0]\t\t);", + 'assign\tMY_IP_ADDR[31:0]\t= EXT_IP_ADDR[31:0];'), end='') + else: # update if existing + g = git.cmd.Git(sitcp_folder) + g.pull() + + +if __name__ == '__main__': + logging.basicConfig(level=logging.DEBUG) + main('BDAQ53_RX640') diff --git a/bdaq53/periphery.py b/bdaq53/periphery.py index 4b1b8d1103fb3d52aa959ae023d86cedb6834d3c..6c847347f20cac78b697d8fd150439dfebb8f828 100644 --- a/bdaq53/periphery.py +++ b/bdaq53/periphery.py @@ -61,7 +61,7 @@ class BDAQ53Periphery(object): return try: self.devices.init() - self.logger.debug('Initialized SCC powersupply %s' % (self.devices['SCC_Powersupply'].get_info())) + self.logger.debug('Initialized SCC powersupply %s' % (self.devices['SCC_Powersupply'].get_name())) try: self.logger.debug('Initialized sensor bias powersupply %s' % (self.devices['SensorBias'].get_name())) except KeyError: diff --git a/bdaq53/periphery.yaml b/bdaq53/periphery.yaml index a75382c681325304e800295a248f782dc265216f..8001eec008d3ac6ce7bb756df43543e034cdc9db 100644 --- a/bdaq53/periphery.yaml +++ b/bdaq53/periphery.yaml @@ -8,7 +8,7 @@ transfer_layer: - name : Serial type : Serial init : - port : /dev/ttyACM0 + port : /dev/ttyUSB0 read_termination : "\r\n" write_termination : "\n" baudrate : 19200 diff --git a/bdaq53/rd53a.py b/bdaq53/rd53a.py index 6208641eeae1dae1c8c2d050a39717d4c43c699d..5f92282a306bd04e6c4ed9316d2d4f7c616252f0 100644 --- a/bdaq53/rd53a.py +++ b/bdaq53/rd53a.py @@ -310,8 +310,7 @@ class RD53A(object): self.reset_masks() def init(self, **kwargs): - self.set_aurora(**kwargs) - self.bdaq.wait_for_aurora_sync() + self.init_communication(**kwargs) self.write_ecr() def set_aurora(self, tx_lanes=1, CB_Wait=255, CB_Send=1, chip_id=8, only_cb=False, write=True, **_): @@ -379,6 +378,39 @@ class RD53A(object): self.write_command(indata) return indata + def init_communication(self, **kwargs): + logger.info('Initializing communication...') + + # Configure cmd encoder + self.bdaq['cmd'].reset() + time.sleep(0.1) + self.write_command(self.write_sync(write=False) * 32) + # Wait for PLL lock + self.bdaq.wait_for_pll_lock() + + aurora_data = self.set_aurora(**kwargs) + + # Workaround for problems locking + for _ in range(30): + self.write_command(self.write_sync(write=False) * 32) + self.write_ecr() + + self.write_command(aurora_data) + time.sleep(0.01) + try: + self.bdaq.wait_for_aurora_sync() + except RuntimeError: + pass + else: + break + + self.write_command([0x00] * 1000, repetitions=1) + time.sleep(0.01) + else: + self.bdaq.wait_for_aurora_sync() + + logger.success('Communication established') + def write_global_pulse(self, width, chip_id=8, write=True): # 0101_1100 ChipId<3:0>,0 Width<3:0>,0 indata = [self.CMD_GLOBAL_PULSE] * 2 # [0b01011100] diff --git a/bdaq53/tests/.gitignore b/bdaq53/tests/.gitignore index 92b911c569e9bb0b15ebc9f6d0ebf1576fff2356..0b8273d328299650095dfc433636261c5d5210af 100644 --- a/bdaq53/tests/.gitignore +++ b/bdaq53/tests/.gitignore @@ -6,7 +6,11 @@ unisims secureip /cds.lib -/sim_build +/test_rd53/sim_build +/test_rd53/output_data +/test_rd53/*.log +/test_rd53/Makefile + /results.xml /*.gtkw /simvision# diff --git a/bdaq53/tests/setup_eudaq.sh b/bdaq53/tests/setup_eudaq.sh index 5125d18113621bf4ad01e5d0b9c52e632fd1c141..14c9e318d98592d168c5828df84dae81919aab54 100644 --- a/bdaq53/tests/setup_eudaq.sh +++ b/bdaq53/tests/setup_eudaq.sh @@ -1,4 +1,4 @@ -git clone -b v1.7-dev https://github.com/eudaq/eudaq +git clone -b v1.x-dev https://github.com/eudaq/eudaq cd eudaq/build cmake -DBUILD_python=ON -DBUILD_gui=OFF -DBUILD_onlinemon=OFF -DBUILD_runsplitter=OFF .. make -j 4 diff --git a/bdaq53/tests/test_hardware/test_scan_scripts.py b/bdaq53/tests/test_hardware/test_scan_scripts.py index b8ba281366f0467e455f79aa251e9dcb707e424f..c0119b955d108b592756ca3cecfff8f7df7b2af6 100644 --- a/bdaq53/tests/test_hardware/test_scan_scripts.py +++ b/bdaq53/tests/test_hardware/test_scan_scripts.py @@ -5,39 +5,16 @@ # ------------------------------------------------------------ # -import os -import time import logging import unittest import tables as tb import numpy as np -from slackclient import SlackClient logger = logging.getLogger(__file__) class TestScanScripts(unittest.TestCase): - @classmethod - def setUpClass(cls): - if os.getenv('CI', False): - job_id = os.environ.get('CI_JOB_ID', 'unknown') - text = 'Use setup for hardware based test job #%s in 5 minutes! Visit https://gitlab.cern.ch/silab/bdaq53/-/jobs/%s to cancel.' % (job_id, job_id) - logger.info(text) - if os.getenv('SLACK_TOKEN', False): - cls.slack = SlackClient(os.environ.get('SLACK_TOKEN')) - if not cls.slack.api_call('chat.postMessage', channel='rd53a_module_setup', text=text, username='BDAQ53 Bot', icon_emoji=':robot_face:')['ok']: - raise unittest.SkipTest("Cannot use Slack to inform users about hardware usage. Skip hardware based test!") - else: - raise unittest.SkipTest("Cannot get Slack credentials to inform users about hardware usage. Skip hardware based test!") - time.sleep(60 * 5) - cls.slack.api_call('chat.postMessage', channel='rd53a_module_setup', text='Starting...', username='BDAQ53 Bot', icon_emoji=':robot_face:') - - @classmethod - def tearDownClass(cls): - if os.getenv('CI', False): - cls.slack.api_call('chat.postMessage', channel='rd53a_module_setup', text='Done!', username='BDAQ53 Bot', icon_emoji=':robot_face:') - def test_digital_scan(self): ''' Test digital scan ''' from bdaq53.scans import scan_digital @@ -64,15 +41,49 @@ class TestScanScripts(unittest.TestCase): scan.close() with tb.open_file(scan.output_filename + '_interpreted.h5') as in_file: - # 60 % of the pixels see all injections, since FE issues logger.error(np.count_nonzero((in_file.root.HistOcc[:].sum(axis=2) != 100))) - self.assertTrue(np.count_nonzero(in_file.root.HistOcc[:].sum(axis=2) == 100) > 0.6 * 400 * 192) + self.assertTrue(np.count_nonzero(in_file.root.HistOcc[:].sum(axis=2) == 100) > 0.99 * 400 * 192) self.assertTrue(np.any(in_file.root.HistRelBCID[:])) self.assertTrue(np.any(in_file.root.HistTot[:])) # We expect BCID errors from SYNC # self.assertTrue(np.all(in_file.root.HistBCIDError[:] == 0)) # self.assertTrue(np.all(in_file.root.HistEventStatus[:] == 0)) + def test_threshold_scan(self): + ''' Test threshold scan and results ''' + from bdaq53.scans import scan_threshold + scan = scan_threshold.ThresholdScan() + scan.start(**scan_threshold.local_configuration) + scan.close() + +# with tb.open_file(scan.output_filename + '_interpreted.h5') as in_file: +# logger.error(np.count_nonzero((in_file.root.HistOcc[:].sum(axis=2) != 100))) +# self.assertTrue(np.count_nonzero(in_file.root.HistOcc[:].sum(axis=2) == 100) > 0.99 * 400 * 192) +# self.assertTrue(np.any(in_file.root.HistRelBCID[:])) +# self.assertTrue(np.any(in_file.root.HistTot[:])) +# # We expect BCID errors from SYNC +# # self.assertTrue(np.all(in_file.root.HistBCIDError[:] == 0)) +# # self.assertTrue(np.all(in_file.root.HistEventStatus[:] == 0)) + +# def test_fast_threshold_scan(self): +# ''' Test fast threshold scan and results ''' +# from bdaq53.scans import scan_threshold_fast +# scan = scan_threshold_fast.FastThresholdScan() +# scan.start(**scan_threshold_fast.local_configuration) +# scan.close() +# +# def test_register_test(self): +# from bdaq53.scans import test_registers +# scan = test_registers.RegisterTest() +# scan.start(**test_registers.local_configuration) +# scan.close() +# +# def test_threshold_noise_tuning(self): +# from bdaq53.scans import tune_local_threshold_noise +# scan = tune_local_threshold_noise.NoiseTuning() +# scan.start(**tune_local_threshold_noise.local_configuration) +# scan.close() + if __name__ == '__main__': unittest.main() diff --git a/firmware/SiTCP/.gitkeep b/firmware/SiTCP/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/firmware/src/bdaq53_core.v b/firmware/src/bdaq53_core.v index c12af14f6c793520b3eff07b866f41e1a5fab89d..dd2d88ecfe3b15d4e4a6784a2bd61ebc1e9350c2 100755 --- a/firmware/src/bdaq53_core.v +++ b/firmware/src/bdaq53_core.v @@ -37,7 +37,6 @@ `include "utils/rgmii_io.v" `include "utils/rbcp_to_bus.v" `include "utils/fifo_32_to_8.v" -`include "utils/clock_divider.v" `include "utils/bus_to_ip.v" `include "utils/ddr_des.v" `include "rrp_arbiter/rrp_arbiter.v" @@ -169,7 +168,7 @@ localparam BDAQ53 = 16'd1; localparam USBPIX3 = 16'd2; localparam KC705 = 16'd3; -`ifdef COCOTB_SIM +`ifdef RTL_SIM localparam BOARD = SIM; localparam CONNECTOR = CON_SMA; `elsif BDAQ53 diff --git a/firmware/src/rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_exdes.v b/firmware/src/rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_exdes.v index 094dae930e6fe000bb2ed739851b48b003f7d340..ba9cf0e2651db62a2a630ecfa55b887e24deb635 100644 --- a/firmware/src/rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_exdes.v +++ b/firmware/src/rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_exdes.v @@ -68,47 +68,46 @@ // This is sample simplex exdes file `timescale 1 ns / 10 ps -`define SIM_ENCRYPTED - -`ifndef SYNTHESIS - `include "rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_cdc_sync_exdes.v" - `ifdef SIM_ENCRYPTED // use the encrypted ip core for the GitLab CI - `include "rx_aurora_64b66b_1lane/ip/sim/core.vp" - `else // otherwise we use the non-encrypted version - - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane_core.v" - - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_64b66b_descrambler.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_block_sync_sm.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_cbcc_gtx_6466.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_cdc_sync.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_common_logic_cbcc.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_common_reset_cbcc.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_ll_to_axi.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_reset_logic.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_aurora_lane_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_channel_err_detect_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_channel_init_sm_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_err_detect_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_global_logic_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_lane_init_sm_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_datapath_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_user_k_datapath_simplex.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_startup_fsm.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_sym_dec.v" - - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_clock_module.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_gt_common_wrapper.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_support.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_support_reset_logic.v" - - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_multi_wrapper.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_wrapper.v" - `include "rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_gtx.v" - - `endif +`ifdef RTL_SIM + `define SIM_ENCRYPTED +`endif + +`include "rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_cdc_sync_exdes.v" + +`ifdef SIM_ENCRYPTED // use the encrypted ip core for the GitLab CI + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/sim/core.vp" +`else // otherwise we use the non-encrypted version + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane_core.v" + + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_64b66b_descrambler.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_block_sync_sm.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_cbcc_gtx_6466.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_cdc_sync.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_common_logic_cbcc.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_common_reset_cbcc.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_ll_to_axi.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_reset_logic.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_aurora_lane_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_channel_err_detect_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_channel_init_sm_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_err_detect_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_global_logic_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_lane_init_sm_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_datapath_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_user_k_datapath_simplex.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_startup_fsm.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_sym_dec.v" + + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_clock_module.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_gt_common_wrapper.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_support.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_support_reset_logic.v" + + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_multi_wrapper.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_wrapper.v" + `include "rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_gtx.v" `endif diff --git a/firmware/src/rx_aurora/rx_aurora_64b66b_1lane/rx_aurora_64b66b_core.v b/firmware/src/rx_aurora/rx_aurora_64b66b_1lane/rx_aurora_64b66b_core.v index 81c26d90e66909f0f4e00d994174b02ccea170ef..b3521f9a0ee9c0620840076fee126f5b46b1a96f 100755 --- a/firmware/src/rx_aurora/rx_aurora_64b66b_1lane/rx_aurora_64b66b_core.v +++ b/firmware/src/rx_aurora/rx_aurora_64b66b_1lane/rx_aurora_64b66b_core.v @@ -8,10 +8,7 @@ `timescale 1ns/1ps `default_nettype none -`ifndef SYNTHESIS `include "rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_exdes.v" -`endif - module rx_aurora_64b66b_core #( diff --git a/firmware/vivado/ci_run.tcl b/firmware/vivado/ci_run.tcl new file mode 100644 index 0000000000000000000000000000000000000000..3bb99a08c60ecf59c3cfae1ea27a0b876b18d0f4 --- /dev/null +++ b/firmware/vivado/ci_run.tcl @@ -0,0 +1,91 @@ + +# --------------------------------------------------------------- +# Copyright (c) SILAB , Institute of Physics, University of Bonn +# --------------------------------------------------------------- +# +# This script creates Vivado projects and bitfiles for the supported hardware platforms +# +# Start vivado in tcl mode by typing: +# vivado -mode tcl -source run.tcl +# + + +set basil_dir [exec python -c "import basil, os; print(str(os.path.dirname(os.path.dirname(basil.__file__))))"] +set include_dirs [list $basil_dir/basil/firmware/modules $basil_dir/basil/firmware/modules/utils] + +file mkdir output reports + + +proc read_design_files {} { + read_verilog ../src/bdaq53.v + read_verilog ../src/bdaq53_core.v + + read_edif ../SiTCP/SiTCP_XC7K_32K_BBT_V110.ngc + read_verilog ../SiTCP/TIMER.v + read_verilog ../SiTCP/SiTCP_XC7K_32K_BBT_V110.V + read_verilog ../SiTCP/WRAP_SiTCP_GMII_XC7K_32K.V + + + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/rx_aurora_64b66b.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/rx_aurora_64b66b_core.v + + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_exdes.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_cdc_sync_exdes.v + + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane_core.v + + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_64b66b_descrambler.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_block_sync_sm.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_cbcc_gtx_6466.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_cdc_sync.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_common_logic_cbcc.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_common_reset_cbcc.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_ll_to_axi.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_reset_logic.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_aurora_lane_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_channel_err_detect_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_channel_init_sm_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_err_detect_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_global_logic_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_lane_init_sm_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_datapath_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_user_k_datapath_simplex.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_startup_fsm.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_sym_dec.v + + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_clock_module.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_gt_common_wrapper.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_support.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_support_reset_logic.v + + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_multi_wrapper.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_wrapper.v + read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_gtx.v +} + + +proc run_bit { part board connector xdc_file size option} { + create_project -force -part $part $board$option$connector designs + + read_design_files + read_xdc $xdc_file + + #read_ip ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane.xci + global include_dirs + + synth_design -top bdaq53 -include_dirs $include_dirs -verilog_define "$board=1" -verilog_define "$connector=1" -verilog_define "SYNTHESIS=1" -verilog_define "$option=1" + opt_design + place_design + phys_opt_design + route_design + report_utilization + report_timing -file "reports/report_timing.$board$option$connector.log" + write_bitstream -force -file output/$board$option$connector + write_cfgmem -format mcs -size $size -interface SPIx4 -loadbit "up 0x0 output/$board$option$connector.bit" -force -file output/$board$option$connector + close_project + + exec tar -C ./output -cvzf output/$board$option$connector.tar.gz $board$option$connector.bit $board$option$connector.mcs +} + diff --git a/firmware/vivado/run.tcl b/firmware/vivado/run.tcl index c83e771d2c257f8c93c0a574baf89052be72d46e..f201e6372be718e2a96b6adc70e4d6dfca8b41ee 100644 --- a/firmware/vivado/run.tcl +++ b/firmware/vivado/run.tcl @@ -3,15 +3,20 @@ # Copyright (c) SILAB , Institute of Physics, University of Bonn # --------------------------------------------------------------- # -# This script creates Vivado projects and bitfiles for the supported hardware platforms +# This script creates Vivado projects and bitfiles for the supported hardware platforms. # -# Start vivado in tcl mode by typing: +# Start vivado in tcl mode by executing: # vivado -mode tcl -source run.tcl # +# NOTE: This will build firmware versions for every supported hardware. See the section "Create projects and bitfiles" below. +# Alternatively, a list of 6 arguments can be used to build only the specified firmware. +# The arguments have to be in the correct order. Just copy&paste from the "Create projects and bitfiles" section and remove all but one space in between the args. +# vivado -mode tcl -source run.tcl -tclargs xc7k160tffg676-2 BDAQ53 "" ../src/bdaq53.xdc 64 _RX640 +# -set basil_dir [exec python -c "import basil, os; print(str(os.path.dirname(basil.__file__)))"] -set include_dirs [list $basil_dir/firmware/modules $basil_dir/firmware/modules/utils] +set basil_dir [exec python -c "import basil, os; print(str(os.path.dirname(os.path.dirname(basil.__file__))))"] +set include_dirs [list $basil_dir/basil/firmware/modules $basil_dir/basil/firmware/modules/utils] file mkdir output reports @@ -24,45 +29,6 @@ proc read_design_files {} { read_verilog ../SiTCP/TIMER.v read_verilog ../SiTCP/SiTCP_XC7K_32K_BBT_V110.V read_verilog ../SiTCP/WRAP_SiTCP_GMII_XC7K_32K.V - - - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/rx_aurora_64b66b.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/rx_aurora_64b66b_core.v - - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_exdes.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/exdes/aurora_64b66b_1lane_cdc_sync_exdes.v - - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane_core.v - - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_64b66b_descrambler.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_block_sync_sm.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_cbcc_gtx_6466.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_cdc_sync.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_common_logic_cbcc.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_common_reset_cbcc.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_ll_to_axi.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_reset_logic.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_aurora_lane_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_channel_err_detect_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_channel_init_sm_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_err_detect_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_global_logic_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_lane_init_sm_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_datapath_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_ll_user_k_datapath_simplex.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_rx_startup_fsm.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/src/aurora_64b66b_1lane_sym_dec.v - - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_clock_module.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_gt_common_wrapper.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_support.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/support/aurora_64b66b_1lane_support_reset_logic.v - - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_multi_wrapper.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_wrapper.v - read_verilog ../src/rx_aurora/rx_aurora_64b66b_1lane/ip/aurora_64b66b_1lane/aurora_64b66b_1lane/example_design/gt/aurora_64b66b_1lane_gtx.v } @@ -96,18 +62,29 @@ proc run_bit { part board connector xdc_file size option} { # Create projects and bitfiles # -# Bitfiles for the 1.28 Gb/s Aurora ip core configuration -# FPGA type board name connector constraints file flash size option -run_bit xc7k160tffg676-2 BDAQ53 "" ../src/bdaq53.xdc 64 "" -run_bit xc7k160tfbg676-1 USBPIX3 "" ../src/usbpix3.xdc 64 "" -run_bit xc7k325tffg900-2 KC705 _SMA ../src/kc705_gmii.xdc 16 "" -run_bit xc7k325tffg900-2 KC705 _FMC_LPC ../src/kc705_gmii.xdc 16 "" +if {$argc == 0} { +# By default, all firmware versions are generated. You can comment the ones you don't need. # Bitfiles for the 640 Mb/s Aurora ip core configuration -# FPGA type board name connector constraints file flash size option +# FPGA type board name connector constraints file flash size option run_bit xc7k160tffg676-2 BDAQ53 "" ../src/bdaq53.xdc 64 _RX640 run_bit xc7k160tfbg676-1 USBPIX3 "" ../src/usbpix3.xdc 64 _RX640 run_bit xc7k325tffg900-2 KC705 _SMA ../src/kc705_gmii.xdc 16 _RX640 run_bit xc7k325tffg900-2 KC705 _FMC_LPC ../src/kc705_gmii.xdc 16 _RX640 +# Bitfiles for the 1.28 Gb/s Aurora ip core configuration +# FPGA type board name connector constraints file flash size option +run_bit xc7k160tffg676-2 BDAQ53 "" ../src/bdaq53.xdc 64 "" +run_bit xc7k160tfbg676-1 USBPIX3 "" ../src/usbpix3.xdc 64 "" +run_bit xc7k325tffg900-2 KC705 _SMA ../src/kc705_gmii.xdc 16 "" +run_bit xc7k325tffg900-2 KC705 _FMC_LPC ../src/kc705_gmii.xdc 16 "" + +# In order to build only one specific firmware version, the tun.tcl can be executed with arguments +} else { + if {$argc == 6} { + run_bit {*}$argv + } else { + puts "ERROR: Invalid args" + } +} exit