From fb75e47554e43f54992333e83fc722cbf93ba1b7 Mon Sep 17 00:00:00 2001 From: Andreas Kurth Date: Tue, 25 Oct 2022 11:58:19 +0000 Subject: [PATCH 1/5] apt-requirements: Import from OpenTitan Signed-off-by: Andreas Kurth --- apt-requirements.txt | 53 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 apt-requirements.txt diff --git a/apt-requirements.txt b/apt-requirements.txt new file mode 100644 index 0000000000..e28bf69ec2 --- /dev/null +++ b/apt-requirements.txt @@ -0,0 +1,53 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# List of packages installed with apt on our reference Ubuntu platform. +# +# When updating this list, please keep the yum package requirements for +# RHEL/CentOS 7 in sync. These were derived from the Ubuntu requirements +# and are maintained in yum-requirements.txt. +# +# This list of packages is also included in the documentation at +# doc/ug/install_instructions/index.md. When updating this file also check if +# doc/ug/install_instructions/index.md needs to be updated as well. +# +# Keep it sorted. +autoconf +bison +build-essential +clang-format +cmake +curl +doxygen +flex +g++ +git +golang +lcov +libelf1 +libelf-dev +libftdi1-2 +libftdi1-dev +# A requirement of the prebuilt clang toolchain. +libncursesw5 +libssl-dev +libudev-dev +libusb-1.0-0 +lld +lsb-release +make +ninja-build +perl +pkgconf +python3 +python3-pip +python3-setuptools +python3-urllib3 +python3-wheel +shellcheck +srecord +tree +xsltproc +zlib1g-dev +xz-utils From f280f69ca5e15c8d07f0650ef4449b14da567516 Mon Sep 17 00:00:00 2001 From: Andreas Kurth Date: Tue, 25 Oct 2022 11:58:42 +0000 Subject: [PATCH 2/5] util/get-toolchain.py: Import from OpenTitan Signed-off-by: Andreas Kurth --- util/get-toolchain.py | 257 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100755 util/get-toolchain.py diff --git a/util/get-toolchain.py b/util/get-toolchain.py new file mode 100755 index 0000000000..18297c2804 --- /dev/null +++ b/util/get-toolchain.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python3 +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +import argparse +import json +import logging as log +import re +import shutil +import subprocess +import sys +import tempfile +from pathlib import Path +from urllib.request import urlopen, urlretrieve + +log.basicConfig(level=log.INFO, format="%(levelname)s: %(message)s") + +# the keys in this dictionary specify valid toolchain kinds +ASSET_PREFIXES = { + # kind : prefix, + "combined": "lowrisc-toolchain-rv32imcb-", + "gcc-only": "lowrisc-toolchain-gcc-rv32imcb-", +} +ASSET_SUFFIX = ".tar.xz" +RELEASES_URL_BASE = 'https://api.github.com/repos/lowRISC/lowrisc-toolchains/releases' + +INSTALL_DIR = '/tools/riscv' +TOOLCHAIN_VERSION = 'latest' +TOOLCHAIN_KIND = 'combined' + +FILE_PATTERNS_TO_REWRITE = [ + "riscv32-unknown-elf-*.cmake", + "meson-riscv32-unknown-elf-*.txt", +] + + +def get_available_toolchain_info(version, kind): + assert kind in ASSET_PREFIXES + + if version == 'latest': + releases_url = '%s/%s' % (RELEASES_URL_BASE, version) + else: + releases_url = '%s/tags/%s' % (RELEASES_URL_BASE, version) + + with urlopen(releases_url) as f: + release_info = json.loads(f.read().decode('utf-8')) + + for asset in release_info["assets"]: + if (asset["name"].startswith(ASSET_PREFIXES[kind]) and + asset["name"].endswith(ASSET_SUFFIX)): + return { + 'download_url': asset['browser_download_url'], + 'name': asset['name'], + 'version': release_info['tag_name'], + 'kind': kind + } + + # No matching asset found for the toolchain kind requested + log.error("No available downloads found for %s toolchain version: %s", + kind, release_info['tag_name']) + raise SystemExit(1) + + +def get_installed_toolchain_info(unpack_dir): + + # Try new-style buildinfo.json first + try: + buildinfo = {} + with open(str(unpack_dir / 'buildinfo.json'), 'r') as f: + buildinfo = json.loads(f.read()) + + # Toolchains before 20200602-4 contained a `buildinfo.json` without a + # 'kind' field. Setting it to 'unknown' will ensure we never skip + # updating because we think it's the same as the existing toolchain. + if 'kind' not in buildinfo: + buildinfo['kind'] = 'unknown' + + return buildinfo + except Exception as e: + # buildinfo.json might not exist in older builds + log.info("Unable to parse buildinfo.json: %s", str(e)) + pass + + # If that wasn't successful, try old-style plaintext buildinfo + version_re = r"(lowRISC toolchain version|Version):\s*\n?(?P[^\n\s]+)" + buildinfo_txt_path = unpack_dir / 'buildinfo' + try: + with open(str(buildinfo_txt_path), 'r') as f: + match = re.match(version_re, f.read(), re.M) + if not match: + log.warning("Unable extract version from %s", + str(buildinfo_txt_path)) + return None + return {'version': match.group("version"), 'kind': 'unknown'} + except Exception as e: + log.error("Unable to read %s: %s", str(buildinfo_txt_path), str(e)) + return None + + +def download(url): + log.info("Downloading toolchain from %s", url) + tmpfile = tempfile.mkstemp()[1] + urlretrieve(url, tmpfile) + log.info("Download complete") + return Path(tmpfile) + + +def install(archive_file, unpack_dir): + unpack_dir.mkdir(parents=True, exist_ok=True) + + cmd = [ + 'tar', + '-x', + '-f', + str(archive_file), + '--strip-components=1', + '-C', + str(unpack_dir), + ] + subprocess.run(cmd, check=True) + + +def postinstall_rewrite_configs(unpack_dir, install_dir): + """Rewrites the toolchain configuration files to point to install_dir. + + 'unpack_dir' is where the toolchain is unpacked by this script. + 'install_dir' is where the toolchain is eventually invoked from. Typically, + these are the same, unless a staged installation is being performed by + supplying both, --install-dir and --dest-dir switches. Regardless, if the + 'install_dir' is different from the default, the config files need to be + updated to reflect the correct paths. + """ + if str(install_dir) == INSTALL_DIR: + return + + for file_pattern in FILE_PATTERNS_TO_REWRITE: + for config_file_path in unpack_dir.glob(file_pattern): + # Rewrite INSTALL_DIR to the requested target dir. + log.info("Updating toolchain paths in %s", str(config_file_path)) + with open(str(config_file_path)) as f: + original = f.read() + with open(str(config_file_path), "w") as f: + f.write(original.replace(INSTALL_DIR, str(install_dir))) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--install-dir', + '-i', + required=False, + default=INSTALL_DIR, + help="Installation directory (default: %(default)s)") + parser.add_argument('--dest-dir', + '-d', + required=False, + help="""Destination directory if performing a staged + installation. This is the staging directory where the + toolchain is unpacked.""") + parser.add_argument('--release-version', + '-r', + required=False, + default=TOOLCHAIN_VERSION, + help="Toolchain version (default: %(default)s)") + parser.add_argument('--latest-available-version', + '-l', + required=False, + default=False, + action='store_true', + help="Return the latest available toolchain version.") + parser.add_argument('--kind', + required=False, + default=TOOLCHAIN_KIND, + choices=ASSET_PREFIXES.keys(), + help="Toolchain kind (default: %(default)s)") + parser.add_argument( + '--update', + '-u', + required=False, + default=False, + action='store_true', + help="Update to target version if needed (default: %(default)s)") + args = parser.parse_args() + + available_toolchain = get_available_toolchain_info(args.release_version, + args.kind) + + if args.latest_available_version: + print(available_toolchain['version']) + sys.exit(0) + + log.info("Found available %s toolchain version %s, %s", + available_toolchain['kind'], available_toolchain['version'], + available_toolchain['name']) + + install_dir = Path(args.install_dir) + if args.dest_dir is None: + unpack_dir = install_dir + else: + unpack_dir = Path(args.dest_dir) + + if args.update and unpack_dir.is_dir(): + installed_toolchain = get_installed_toolchain_info(unpack_dir) + if installed_toolchain is None: + sys.exit('Unable to extract current toolchain version. ' + 'Delete target directory %s and try again.' % + str(unpack_dir)) + + version_matches = available_toolchain[ + 'version'] == installed_toolchain['version'] + kind_matches = available_toolchain['kind'] == installed_toolchain[ + 'kind'] + + if installed_toolchain[ + 'kind'] != 'unknown' and version_matches and kind_matches: + log.info( + 'Downloaded %s toolchain is version %s, ' + 'same as the %s toolchain installed at %s (version %s).', + available_toolchain['kind'], available_toolchain['version'], + installed_toolchain['kind'], installed_toolchain['version'], + str(unpack_dir)) + log.warning("Skipping install.") + sys.exit(0) + + log.info( + "Found installed %s toolchain version %s, updating to %s toolchain " + "version %s.", + installed_toolchain['kind'], installed_toolchain['version'], + available_toolchain['kind'], available_toolchain['version']) + else: + if unpack_dir.exists(): + sys.exit('Target directory %s already exists. ' + 'Delete it first, or use --update.' % str(unpack_dir)) + + archive_file = None + try: + archive_file = download(available_toolchain['download_url']) + + if args.update and unpack_dir.exists(): + # We only reach this point if |unpack_dir| contained a toolchain + # before, so removing it is reasonably safe. + shutil.rmtree(str(unpack_dir)) + + install(archive_file, unpack_dir) + postinstall_rewrite_configs(unpack_dir.resolve(), + install_dir.resolve()) + finally: + if archive_file: + archive_file.unlink() + + log.info('Installed %s toolchain version %s to %s.', + available_toolchain['kind'], available_toolchain['version'], + str(unpack_dir)) + + +if __name__ == "__main__": + main() From dc0ef0aa0001e47e6c3a08026295f2f6f549755f Mon Sep 17 00:00:00 2001 From: Andreas Kurth Date: Tue, 25 Oct 2022 11:59:51 +0000 Subject: [PATCH 3/5] apt-requirements: Add `device-tree-compiler` Signed-off-by: Andreas Kurth --- apt-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apt-requirements.txt b/apt-requirements.txt index e28bf69ec2..93fa7f3033 100644 --- a/apt-requirements.txt +++ b/apt-requirements.txt @@ -19,6 +19,7 @@ build-essential clang-format cmake curl +device-tree-compiler doxygen flex g++ From 34b695357304af7ae2e2b603e6fdaf3e7e0682cf Mon Sep 17 00:00:00 2001 From: Andreas Kurth Date: Mon, 31 Oct 2022 09:20:51 +0000 Subject: [PATCH 4/5] [util] Add container files Signed-off-by: Andreas Kurth --- util/container/Dockerfile | 153 ++++++++++++++++++++++++++++++++++++++ util/container/start.sh | 17 +++++ util/container/sudoconf | 2 + 3 files changed, 172 insertions(+) create mode 100644 util/container/Dockerfile create mode 100755 util/container/start.sh create mode 100644 util/container/sudoconf diff --git a/util/container/Dockerfile b/util/container/Dockerfile new file mode 100644 index 0000000000..270694a3d9 --- /dev/null +++ b/util/container/Dockerfile @@ -0,0 +1,153 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Docker container containing various hardware and software development tools +# for Ibex. + +# Global configuration options. +ARG VERILATOR_VERSION=4.210 +# The RISCV toolchain version should match the release tag used in GitHub. +ARG RISCV_TOOLCHAIN_TAR_VERSION=20220210-1 +# This should match the version in ci/install-package-dependencies.sh +ARG GCC_VERSION=9 + +# Main container image. +FROM ubuntu:20.04 AS ibex +ARG VERILATOR_VERSION +ARG RISCV_TOOLCHAIN_TAR_VERSION +ARG GCC_VERSION + +LABEL version="0.1" +LABEL description="Ibex development container." +LABEL maintainer="ibex@lowrisc.org" + +# Use bash as default shell. +RUN ln -sf /bin/bash /bin/sh + +# Add OBS repository to apt sources. +RUN OBS_URL="https://download.opensuse.org/repositories"; \ + OBS_PATH="/home:/phiwag:/edatools/xUbuntu_20.04"; \ + REPO_URL="${OBS_URL}${OBS_PATH}"; \ + \ + EDATOOLS_REPO_KEY="${REPO_URL}/Release.key"; \ + EDATOOLS_REPO="deb ${REPO_URL}/ /"; \ + \ + apt-get update && \ + apt-get install -y curl && \ + \ + curl -f -sL -o "$TMPDIR/obs.asc" "$EDATOOLS_REPO_KEY" || { \ + error "Failed to download repository key from ${REPO_URL}"; \ + } && \ + echo "$EDATOOLS_REPO" > "$TMPDIR/obs.list" && \ + mv "$TMPDIR/obs.asc" /etc/apt/trusted.gpg.d/obs.asc && \ + mv "$TMPDIR/obs.list" /etc/apt/sources.list.d/edatools.list + +# Install system packages +# +# Install (and cleanup) required packages (from apt-requirements.txt). +# Also add some additional packages for the use within this container and for +# developer convenience: +# - gosu and sudo are used by the scripting to make the image more convenient +# to use. +# - locales and locales-all are required to set the locale. +# - minicom and screen are useful to see UART communication. +# - dc and time are requirements of Synopsys VCS. +# - csh and ksh are requirements of Cadence Xcelium. +# - software-properties-common is required to be able to install newer gcc versions. + +# Necessary to avoid user interaction with tzdata during install +ARG DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC + +COPY apt-requirements.txt /tmp/apt-requirements.txt +RUN echo "verilator-${VERILATOR_VERSION}" >>/tmp/apt-requirements.txt \ + && sed -i -e '/^$/d' -e '/^#/d' -e 's/#.*//' /tmp/apt-requirements.txt \ + && apt-get update \ + && xargs apt-get install -y /dev/null 2>&1 +usermod -o -u "$DEV_UID" dev >/dev/null 2>&1 + +# Load user configuration. +test -f "${USER_CONFIG}" && export BASH_ENV=${USER_CONFIG} + +cd /home/dev || exit +exec gosu dev:dev /bin/bash -c "$@" diff --git a/util/container/sudoconf b/util/container/sudoconf new file mode 100644 index 0000000000..0f89e625af --- /dev/null +++ b/util/container/sudoconf @@ -0,0 +1,2 @@ +# Give dev user account root permissions in container +dev ALL=(ALL) NOPASSWD:ALL From 91cc057f5e493986d3299f4c4a0a3b9ba64643b7 Mon Sep 17 00:00:00 2001 From: Andreas Kurth Date: Mon, 7 Nov 2022 14:51:06 +0000 Subject: [PATCH 5/5] [util/container] Update spike to latest commit of `ibex_cosim` branch Signed-off-by: Andreas Kurth --- util/container/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/container/Dockerfile b/util/container/Dockerfile index 270694a3d9..eace7373cb 100644 --- a/util/container/Dockerfile +++ b/util/container/Dockerfile @@ -140,7 +140,7 @@ ENV RISCV_OBJCOPY "${RISCV}/bin/riscv32-unknown-elf-objcopy" # Build and install Spike. RUN mkdir /tmp/spike && cd /tmp/spike \ && git clone https://github.com/lowRISC/riscv-isa-sim && cd riscv-isa-sim \ - && git checkout 0e306ce7b96b79ed67f9c9987ba30135e3f5aeff \ + && git checkout 15fbd5680e44da699f828c67db15345822a47ef6 \ && mkdir build && cd build \ && ../configure --prefix=$RISCV --enable-commitlog --enable-misaligned \ && make -j16 \