diff --git a/.gitignore b/.gitignore index b25c15b..4ac4e47 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ *~ +.ninja* +**/build/* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5fac78b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_STANDARD 99) + +# SCHEREMO: Needed to skip compiler test, which doesn't support baremetal targets +set(CMAKE_C_COMPILER_WORKS 1) + +# SCHEREMO: This toolchain file is only used for test compilation! +set(CMAKE_TOOLCHAIN_FILE cmake/toolchain_gcc.cmake) + +project(chimera-sdk LANGUAGES C ASM) + +include(${CMAKE_CURRENT_LIST_DIR}/cmake/Utils.cmake) + +add_subdirectory(targets) +add_subdirectory(hal) + +add_library(chimera-sdk INTERFACE) +target_link_libraries(chimera-sdk INTERFACE hal) +target_link_libraries(chimera-sdk INTERFACE runtime) +target_sources(chimera-sdk INTERFACE $) + +enable_testing() + +add_subdirectory(tests) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0b4f59a --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 deeploy + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index c4dc7da..36fafff 100644 --- a/README.md +++ b/README.md @@ -1 +1,49 @@ # CHIMERA SDK + +Chimera-SDK is a bare-metal development platform for ASICs based on the [Chimera architecture](https://github.com/pulp-platform/chimera), a microcontroller SoC for multi-cluster, heterogeneous systems. + +Chimera and Chimera-SDK are developed as part of the PULP project, a joint effort between ETH Zurich and the University of Bologna. + +## License + +Unless specified otherwise in the respective file headers, all code checked into this repository is made available under a permissive license. All software sources are licensed under Apache 2.0 (see LICENSE) or compatible licenses, with the exception of `scripts/run_clang_format.py`, which is licensed under the MIT license. + +## Getting started + +If you are working on an IIS system, you can use the preinstalled SEPP packages to add the correct versions of the RISC-V toolchain and questasim into your path. If you use bash, you might run +``` +riscv bash +``` + +If you are not on an IIS system, please ensure a RISC-V toolchain and questa installation are available in your path by checking that the output of +``` +which riscv32-unknown-elf-gcc +``` +is not empty. + +To build the SDK and all tests contained in the SDK, run + +``` +mkdir build && cd build +cmake -DTARGET_PLATFORM=[YOURTARGETPLATFORM] ../ +cmake --build . +``` + +The resulting binaries will be stored in `build/bin`, and can be used within the `chimera` repo as tests. + +## CXX Formatting + +To format all source files, run +``` +python scripts/run_clang_format.py -ir sw/ +``` + +Our CI uses llvm-12 for clang-format, so on IIS machines you may run +``` +python scripts/run_clang_format.py -ir hal/ --clang-format-executable=/usr/pack/riscv-1.0-kgf/pulp-llvm-0.12.0/bin/clang-format + +python scripts/run_clang_format.py -ir targets/ --clang-format-executable=/usr/pack/riscv-1.0-kgf/pulp-llvm-0.12.0/bin/clang-format + +python scripts/run_clang_format.py -ir tests/ --clang-format-executable=/usr/pack/riscv-1.0-kgf/pulp-llvm-0.12.0/bin/clang-format + +``` diff --git a/cmake/Utils.cmake b/cmake/Utils.cmake new file mode 100644 index 0000000..45214d9 --- /dev/null +++ b/cmake/Utils.cmake @@ -0,0 +1,19 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +macro(add_chimera_executable name) + add_executable(${ARGV}) + add_custom_command( + TARGET ${name} + POST_BUILD + COMMAND ${CMAKE_OBJDUMP} -dhS $ > $.s) +endmacro() + +## TODO: Add vsim target or some such +macro(add_chimera_test name) + add_chimera_executable(${ARGV}) + add_test(NAME ${name} COMMAND ${name}) +endmacro() diff --git a/cmake/toolchain_gcc.cmake b/cmake/toolchain_gcc.cmake new file mode 100644 index 0000000..1e80730 --- /dev/null +++ b/cmake/toolchain_gcc.cmake @@ -0,0 +1,16 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +set(CMAKE_EXECUTABLE_SUFFIX ".elf") + +set(CMAKE_SYSTEM_NAME Generic) + +set(CMAKE_C_COMPILER riscv32-unknown-elf-gcc) +set(CMAKE_CXX_COMPILER riscv32-unknown-elf-g++) +set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +set(CMAKE_OBJCOPY riscv32-unknown-elf-objcopy) +set(CMAKE_OBJDUMP riscv32-unknown-elf-objdump) +set(CMAKE_AR riscv32-unknown-elf-ar) diff --git a/hal/CMakeLists.txt b/hal/CMakeLists.txt new file mode 100644 index 0000000..ed20361 --- /dev/null +++ b/hal/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +file(GLOB_RECURSE SOURCES + "src/*" +) + +add_library(hal STATIC ${SOURCES}) + +target_include_directories(hal + PUBLIC + "inc/" +) diff --git a/hal/inc/device_api.h b/hal/inc/device_api.h new file mode 100644 index 0000000..d0dba5b --- /dev/null +++ b/hal/inc/device_api.h @@ -0,0 +1,25 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Moritz Scherer + +#include +#include + +typedef bool (*chi_device_callback)(struct chi_device *device); + +typedef struct chi_device_api { + int (*open)(struct chi_device *device); + int (*close)(struct chi_device *device); + ssize_t (*read_async)(struct chi_device *device, void *buffer, uint32_t size, + chi_device_callback cb); + ssize_t (*write_async)(struct chi_device *device, const void *buffer, + uint32_t size, chi_device_callback cb); +} chi_device_api_t; + +typedef struct chi_device { + struct chi_device_api *api; // function pointers + uint32_t *device_addr; + void *cfg; +} chi_device_t; diff --git a/hal/src/device_api.c b/hal/src/device_api.c new file mode 100644 index 0000000..109ef2a --- /dev/null +++ b/hal/src/device_api.c @@ -0,0 +1,8 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Moritz Scherer + +#include +#include diff --git a/scripts/run_clang_format.py b/scripts/run_clang_format.py new file mode 100755 index 0000000..75dec86 --- /dev/null +++ b/scripts/run_clang_format.py @@ -0,0 +1,394 @@ +#!/usr/bin/env python + +# MIT License + +# Copyright (c) 2017 Guillaume Papin + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Taken from: https://github.com/Sarcasm/run-clang-format +# SPDX-License-Identifier: MIT +"""A wrapper script around clang-format, suitable for linting multiple files +and to use for continuous integration. + +This is an alternative API for the clang-format command line. +It runs over multiple files and directories in parallel. +A diff output is produced and a sensible exit code is returned. + +""" + +from __future__ import print_function, unicode_literals + +import argparse +import codecs +import difflib +import errno +import fnmatch +import io +import multiprocessing +import os +import signal +import subprocess +import sys +import traceback +from functools import partial + +try: + from subprocess import DEVNULL # py3k +except ImportError: + DEVNULL = open(os.devnull, "wb") + +DEFAULT_EXTENSIONS = 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx' +DEFAULT_CLANG_FORMAT_IGNORE = '.clang-format-ignore' + + +class ExitStatus: + SUCCESS = 0 + DIFF = 1 + TROUBLE = 2 + + +def excludes_from_file(ignore_file): + excludes = [] + try: + with io.open(ignore_file, 'r', encoding = 'utf-8') as f: + for line in f: + if line.startswith('#'): + # ignore comments + continue + pattern = line.rstrip() + if not pattern: + # allow empty lines + continue + excludes.append(pattern) + except EnvironmentError as e: + if e.errno != errno.ENOENT: + raise + return excludes + + +def list_files(files, recursive = False, extensions = None, exclude = None): + if extensions is None: + extensions = [] + if exclude is None: + exclude = [] + + out = [] + for file in files: + if recursive and os.path.isdir(file): + for dirpath, dnames, fnames in os.walk(file): + fpaths = [os.path.join(dirpath, fname) for fname in fnames] + for pattern in exclude: + # os.walk() supports trimming down the dnames list + # by modifying it in-place, + # to avoid unnecessary directory listings. + dnames[:] = [x for x in dnames if not fnmatch.fnmatch(os.path.join(dirpath, x), pattern)] + fpaths = [x for x in fpaths if not fnmatch.fnmatch(x, pattern)] + for f in fpaths: + ext = os.path.splitext(f)[1][1:] + if ext in extensions: + out.append(f) + else: + out.append(file) + return out + + +def make_diff(file, original, reformatted): + return list( + difflib.unified_diff(original, + reformatted, + fromfile = '{}\t(original)'.format(file), + tofile = '{}\t(reformatted)'.format(file), + n = 3)) + + +class DiffError(Exception): + + def __init__(self, message, errs = None): + super(DiffError, self).__init__(message) + self.errs = errs or [] + + +class UnexpectedError(Exception): + + def __init__(self, message, exc = None): + super(UnexpectedError, self).__init__(message) + self.formatted_traceback = traceback.format_exc() + self.exc = exc + + +def run_clang_format_diff_wrapper(args, file): + try: + ret = run_clang_format_diff(args, file) + return ret + except DiffError: + raise + except Exception as e: + raise UnexpectedError('{}: {}: {}'.format(file, e.__class__.__name__, e), e) + + +def run_clang_format_diff(args, file): + try: + with io.open(file, 'r', encoding = 'utf-8') as f: + original = f.readlines() + except IOError as exc: + raise DiffError(str(exc)) + + if args.in_place: + invocation = [args.clang_format_executable, '-i', file] + else: + invocation = [args.clang_format_executable, file] + + if args.style: + invocation.extend(['-style', args.style]) + + if args.dry_run: + print(" ".join(invocation)) + return [], [] + + # Use of utf-8 to decode the process output. + # + # Hopefully, this is the correct thing to do. + # + # It's done due to the following assumptions (which may be incorrect): + # - clang-format will returns the bytes read from the files as-is, + # without conversion, and it is already assumed that the files use utf-8. + # - if the diagnostics were internationalized, they would use utf-8: + # > Adding Translations to Clang + # > + # > Not possible yet! + # > Diagnostic strings should be written in UTF-8, + # > the client can translate to the relevant code page if needed. + # > Each translation completely replaces the format string + # > for the diagnostic. + # > -- http://clang.llvm.org/docs/InternalsManual.html#internals-diag-translation + # + # It's not pretty, due to Python 2 & 3 compatibility. + encoding_py3 = {} + if sys.version_info[0] >= 3: + encoding_py3['encoding'] = 'utf-8' + + try: + proc = subprocess.Popen(invocation, + stdout = subprocess.PIPE, + stderr = subprocess.PIPE, + universal_newlines = True, + **encoding_py3) + except OSError as exc: + raise DiffError("Command '{}' failed to start: {}".format(subprocess.list2cmdline(invocation), exc)) + proc_stdout = proc.stdout + proc_stderr = proc.stderr + if sys.version_info[0] < 3: + # make the pipes compatible with Python 3, + # reading lines should output unicode + encoding = 'utf-8' + proc_stdout = codecs.getreader(encoding)(proc_stdout) + proc_stderr = codecs.getreader(encoding)(proc_stderr) + # hopefully the stderr pipe won't get full and block the process + outs = list(proc_stdout.readlines()) + errs = list(proc_stderr.readlines()) + proc.wait() + if proc.returncode: + raise DiffError( + "Command '{}' returned non-zero exit status {}".format(subprocess.list2cmdline(invocation), + proc.returncode), + errs, + ) + if args.in_place: + return [], errs + return make_diff(file, original, outs), errs + + +def bold_red(s): + return '\x1b[1m\x1b[31m' + s + '\x1b[0m' + + +def colorize(diff_lines): + + def bold(s): + return '\x1b[1m' + s + '\x1b[0m' + + def cyan(s): + return '\x1b[36m' + s + '\x1b[0m' + + def green(s): + return '\x1b[32m' + s + '\x1b[0m' + + def red(s): + return '\x1b[31m' + s + '\x1b[0m' + + for line in diff_lines: + if line[:4] in ['--- ', '+++ ']: + yield bold(line) + elif line.startswith('@@ '): + yield cyan(line) + elif line.startswith('+'): + yield green(line) + elif line.startswith('-'): + yield red(line) + else: + yield line + + +def print_diff(diff_lines, use_color): + if use_color: + diff_lines = colorize(diff_lines) + if sys.version_info[0] < 3: + sys.stdout.writelines((l.encode('utf-8') for l in diff_lines)) + else: + sys.stdout.writelines(diff_lines) + + +def print_trouble(prog, message, use_colors): + error_text = 'error:' + if use_colors: + error_text = bold_red(error_text) + print("{}: {} {}".format(prog, error_text, message), file = sys.stderr) + + +def main(): + parser = argparse.ArgumentParser(description = __doc__) + parser.add_argument('--clang-format-executable', + metavar = 'EXECUTABLE', + help = 'path to the clang-format executable', + default = 'clang-format') + parser.add_argument('--extensions', + help = 'comma separated list of file extensions (default: {})'.format(DEFAULT_EXTENSIONS), + default = DEFAULT_EXTENSIONS) + parser.add_argument('-r', '--recursive', action = 'store_true', help = 'run recursively over directories') + parser.add_argument('-d', '--dry-run', action = 'store_true', help = 'just print the list of files') + parser.add_argument('-i', '--in-place', action = 'store_true', help = 'format file instead of printing differences') + parser.add_argument('files', metavar = 'file', nargs = '+') + parser.add_argument('-q', '--quiet', action = 'store_true', help = "disable output, useful for the exit code") + parser.add_argument('-j', + metavar = 'N', + type = int, + default = 0, + help = 'run N clang-format jobs in parallel' + ' (default number of cpus + 1)') + parser.add_argument('--color', + default = 'auto', + choices = ['auto', 'always', 'never'], + help = 'show colored diff (default: auto)') + parser.add_argument('-e', + '--exclude', + metavar = 'PATTERN', + action = 'append', + default = [], + help = 'exclude paths matching the given glob-like pattern(s)' + ' from recursive search') + parser.add_argument('--style', help = 'formatting style to apply (LLVM, Google, Chromium, Mozilla, WebKit)') + + args = parser.parse_args() + + # use default signal handling, like diff return SIGINT value on ^C + # https://bugs.python.org/issue14229#msg156446 + signal.signal(signal.SIGINT, signal.SIG_DFL) + try: + signal.SIGPIPE + except AttributeError: + # compatibility, SIGPIPE does not exist on Windows + pass + else: + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + colored_stdout = False + colored_stderr = False + if args.color == 'always': + colored_stdout = True + colored_stderr = True + elif args.color == 'auto': + colored_stdout = sys.stdout.isatty() + colored_stderr = sys.stderr.isatty() + + version_invocation = [args.clang_format_executable, str("--version")] + try: + subprocess.check_call(version_invocation, stdout = DEVNULL) + except subprocess.CalledProcessError as e: + print_trouble(parser.prog, str(e), use_colors = colored_stderr) + return ExitStatus.TROUBLE + except OSError as e: + print_trouble( + parser.prog, + "Command '{}' failed to start: {}".format(subprocess.list2cmdline(version_invocation), e), + use_colors = colored_stderr, + ) + return ExitStatus.TROUBLE + + retcode = ExitStatus.SUCCESS + + excludes = excludes_from_file(DEFAULT_CLANG_FORMAT_IGNORE) + excludes.extend(args.exclude) + + files = list_files(args.files, + recursive = args.recursive, + exclude = excludes, + extensions = args.extensions.split(',')) + + if not files: + return + + njobs = args.j + if njobs == 0: + njobs = multiprocessing.cpu_count() + 1 + njobs = min(len(files), njobs) + + if njobs == 1: + # execute directly instead of in a pool, + # less overhead, simpler stacktraces + it = (run_clang_format_diff_wrapper(args, file) for file in files) + pool = None + else: + pool = multiprocessing.Pool(njobs) + it = pool.imap_unordered(partial(run_clang_format_diff_wrapper, args), files) + pool.close() + while True: + try: + outs, errs = next(it) + except StopIteration: + break + except DiffError as e: + print_trouble(parser.prog, str(e), use_colors = colored_stderr) + retcode = ExitStatus.TROUBLE + sys.stderr.writelines(e.errs) + except UnexpectedError as e: + print_trouble(parser.prog, str(e), use_colors = colored_stderr) + sys.stderr.write(e.formatted_traceback) + retcode = ExitStatus.TROUBLE + # stop at the first unexpected error, + # something could be very wrong, + # don't process all files unnecessarily + if pool: + pool.terminate() + break + else: + sys.stderr.writelines(errs) + if outs == []: + continue + if not args.quiet: + print_diff(outs, use_color = colored_stdout) + if retcode == ExitStatus.SUCCESS: + retcode = ExitStatus.DIFF + if pool: + pool.join() + return retcode + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/targets/CMakeLists.txt b/targets/CMakeLists.txt new file mode 100644 index 0000000..f45f160 --- /dev/null +++ b/targets/CMakeLists.txt @@ -0,0 +1,20 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +set(AVAILABLE_TARGETS + "Cheshire" + CACHE STRING "Available Targets" +) + +get_property(OPT_STRINGS CACHE OPT PROPERTY STRINGS) + +if(NOT TARGET_PLATFORM IN_LIST AVAILABLE_TARGETS) + message(FATAL_ERROR "Wrong value for TARGET_PLATFORM: Got ${TARGET_PLATFORM}") +endif() + +if (TARGET_PLATFORM STREQUAL "Cheshire") + add_subdirectory(cheshire) +endif() diff --git a/targets/cheshire/CMakeLists.txt b/targets/cheshire/CMakeLists.txt new file mode 100644 index 0000000..1c1df4d --- /dev/null +++ b/targets/cheshire/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +file(GLOB_RECURSE ASM_SOURCES + "src/crt0.S" +) +set_property(SOURCE ${ASM_SOURCES} PROPERTY LANGUAGE ASM) +add_library(runtime OBJECT ${ASM_SOURCES}) + +set(ISA rv32imc) +set(ABI ilp32) + +target_compile_options(runtime + PUBLIC + -march=${ISA} + -mabi=${ABI} +) + +target_link_options(runtime + PUBLIC + -march=${ISA} + -mabi=${ABI} + -nostartfiles + -nostdlib + -L${CMAKE_CURRENT_LIST_DIR} + -Tlink.ld +) diff --git a/targets/cheshire/common.ldh b/targets/cheshire/common.ldh new file mode 100644 index 0000000..7c94fff --- /dev/null +++ b/targets/cheshire/common.ldh @@ -0,0 +1,51 @@ +/* Copyright 2022 ETH Zurich and University of Bologna. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Nicole Narr */ +/* Christopher Reinwardt */ +/* Paul Scheffler */ + +/* This header defines symbols and rules universal to bare-metal execution */ + +ENTRY(_start) + +MEMORY { + bootrom (rx) : ORIGIN = 0x02000000, LENGTH = 16K + /* We assume at least 64 KiB SPM, same minus stack for ROMs. */ + /* If more SPM is available, CRT0 repoints the stack. */ + extrom (rx) : ORIGIN = 0x00000000, LENGTH = 48K + spm (rwx) : ORIGIN = 0x10000000, LENGTH = 64K + memisl (rwx) : ORIGIN = 0x18000000, LENGTH = 64K + /* We assume at least 8 MiB of DRAM (minimum for Linux). */ + dram (rwx) : ORIGIN = 0x80000000, LENGTH = 8M +} + +SECTIONS { + /* Keep binaries lean */ + /DISCARD/ : { *(.riscv.attributes) *(.comment) } + + /* Global and stack pointer */ + /* By default, keep the calling context (boot ROM) stack pointer */ + __global_pointer$ = ADDR(.misc) + SIZEOF(.misc) / 2; + __stack_pointer$ = 0; + + /* Further addresses */ + __base_dma = 0x01000000; + __base_bootrom = 0x02000000; + __base_clint = 0x02040000; + __base_axirt = 0x020C0000; + __base_axirtgrd = 0x020C1ffc; + __base_regs = 0x03000000; + __base_llc = 0x03001000; + __base_uart = 0x03002000; + __base_i2c = 0x03003000; + __base_spih = 0x03004000; + __base_gpio = 0x03005000; + __base_slink = 0x03006000; + __base_vga = 0x03007000; + __base_plic = 0x04000000; + __base_memisl = ORIGIN(memisl); + __base_spm = ORIGIN(spm); + __base_dram = ORIGIN(dram); +} diff --git a/targets/cheshire/link.ld b/targets/cheshire/link.ld new file mode 100644 index 0000000..8a1efcd --- /dev/null +++ b/targets/cheshire/link.ld @@ -0,0 +1,44 @@ +/* Copyright 2022 ETH Zurich and University of Bologna. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* Nicole Narr */ +/* Christopher Reinwardt */ +/* Paul Scheffler */ + +INCLUDE common.ldh + +SECTIONS { + .text : { + *(.text._start) + *(.text) + *(.text.*) + } > memisl + + .misc : ALIGN(16) { + *(.rodata) + *(.rodata.*) + *(.data) + *(.data.*) + *(.srodata) + *(.srodata.*) + *(.sdata) + *(.sdata.*) + } > memisl + + . = ALIGN(32); + __bss_start = .; + .bss : { + *(.bss) + *(.bss.*) + *(.sbss) + *(.sbss.*) + } > memisl + . = ALIGN(32); + __bss_end = .; + + .bulk : ALIGN(16) { + *(.bulk) + *(.bulk.*) + } > memisl +} diff --git a/targets/cheshire/src/crt0.S b/targets/cheshire/src/crt0.S new file mode 100644 index 0000000..9790a64 --- /dev/null +++ b/targets/cheshire/src/crt0.S @@ -0,0 +1,133 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Moritz Scherer + +.section .text._start +// Minimal CRT0 +.global _start +_start: + // Globally disable Machine and Supervisor interrupts + csrrc x0, mstatus, 10 + + // Park SMP harts + csrr t0, mhartid + beqz t0, 2f +1: + wfi + j 1b +2: + // Init stack and global pointer iff linked as nonzero + mv t1, sp + la t0, __stack_pointer$ + beqz t0, 1f + mv sp, t0 +1: .option push + .option norelax + la t0, __global_pointer$ + beqz t0, 1f + mv gp, t0 +1: .option pop + + // Store existing stack, global, return pointers on new stack + addi sp, sp, -12 + sw t1, 0(sp) + sw gp, 4(sp) + sw ra, 8(sp) + + // Set trap vector + la t0, _trap_handler_wrap + csrrw x0, mtvec, t0 + + // Zero the .bss section + la t0, __bss_start // t0 = bss start address + la t1, __bss_end // t1 = bss end address + sub t2, t1, t0 // t2 = #bytes to zero + li a0, 0 + +_zero_bss_loop: + addi t4, t2, -16 + blez t2, _fp_init // t2 <= 0? => No bss to zero + blt t4, x0, _zero_bss_rem // t4 < 0? => Less than 4 words left + sw a0, 0(t0) + sw a0, 4(t0) + sw a0, 8(t0) + sw a0, 12(t0) + addi t2, t2, -16 + addi t0, t0, 16 + bgt t2, x0, _zero_bss_loop // Still more to go + j _fp_init + +_zero_bss_rem: + sb a0, 0(t0) + addi t2, t2, -1 + addi t0, t0, 1 + bgt t2, x0, _zero_bss_rem + +_fp_init: + // Full fence, then jump to main + call main + +// If main returns, we end up here +.global _exit +_exit: + // Restore the original context registers (sp last) + lw ra, 8(sp) + lw gp, 4(sp) + lw sp, 0(sp) + // Save the return value to scratch register 2 and wait forever. + slli t0, a0, 1 + ori t0, t0, 1 + la t1, __base_regs + sw t0, 8(t1) // regs.SCRATCH[2] + // Hand over to whatever called us, passing return + ret + +// This wraps the C trap handler to save the (integer-only) caller-save +// registers and perform a proper machine-mode exception return. +.align 4 +_trap_handler_wrap: + addi sp, sp, -64 + sw ra, 60(sp) + sw t0, 56(sp) + sw t1, 52(sp) + sw t2, 48(sp) + sw a0, 44(sp) + sw a1, 40(sp) + sw a2, 36(sp) + sw a3, 32(sp) + sw a4, 28(sp) + sw a5, 24(sp) + sw a6, 20(sp) + sw a7, 16(sp) + sw t3, 12(sp) + sw t4, 8(sp) + sw t5, 4(sp) + sw t6, 0(sp) + + jal trap_vector + + lw ra, 60(sp) + lw t0, 56(sp) + lw t1, 52(sp) + lw t2, 48(sp) + lw a0, 44(sp) + lw a1, 40(sp) + lw a2, 36(sp) + lw a3, 32(sp) + lw a4, 28(sp) + lw a5, 24(sp) + lw a6, 20(sp) + lw a7, 16(sp) + lw t3, 12(sp) + lw t4, 8(sp) + lw t5, 4(sp) + lw t6, 0(sp) + addi sp, sp, 128 + mret + +.global trap_vector +.weak trap_vector +trap_vector: + j trap_vector diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..a9bbb67 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +add_subdirectory(generic) + +# TODO: Add target-specific test directories diff --git a/tests/generic/CMakeLists.txt b/tests/generic/CMakeLists.txt new file mode 100644 index 0000000..bcc761a --- /dev/null +++ b/tests/generic/CMakeLists.txt @@ -0,0 +1,7 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +add_subdirectory(testReturnZero) diff --git a/tests/generic/testReturnZero/CMakeLists.txt b/tests/generic/testReturnZero/CMakeLists.txt new file mode 100644 index 0000000..849997a --- /dev/null +++ b/tests/generic/testReturnZero/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright 2024 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Moritz Scherer + +cmake_minimum_required(VERSION 3.13) + +set(CMAKE_C_COMPILER_WORKS 1) + +set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE) + +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_LIST_DIR}/toolchain_gcc.cmake) + +project(chimera-sdk-test-build LANGUAGES C ASM) + +file(GLOB_RECURSE TEST_SRCS + "src/testReturn0.c" +) + +add_chimera_test( + return0 + ${TEST_SRCS} +) + +target_link_libraries(return0 PUBLIC chimera-sdk) diff --git a/tests/generic/testReturnZero/src/testReturn0.c b/tests/generic/testReturnZero/src/testReturn0.c new file mode 100644 index 0000000..c000c1e --- /dev/null +++ b/tests/generic/testReturnZero/src/testReturn0.c @@ -0,0 +1,7 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Moritz Scherer + +int main() { return 0; }