Initial commit (Bazel version) * Add Bazel build environment setup * Kelvin startup asm and linker script * A hello_world example Change-Id: I7b3b246f1f22900d47475d0aa50204d2e174193a
diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..99fc0bd --- /dev/null +++ b/.bazelrc
@@ -0,0 +1,8 @@ +build --action_env=BAZEL_CXXOPTS="-std=gnu++14" +build --cxxopt='-std=gnu++14' +build --conlyopt='-std=gnu11' + +# Enable toolchain resolution with cc +build --incompatible_enable_cc_toolchain_resolution + +build:kelvin --platforms=//platforms/riscv32:kelvin
diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000..ac14c3d --- /dev/null +++ b/.bazelversion
@@ -0,0 +1 @@ +5.1.1
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac51a05 --- /dev/null +++ b/.gitignore
@@ -0,0 +1 @@ +bazel-*
diff --git a/README.md b/README.md new file mode 100644 index 0000000..3cc5013 --- /dev/null +++ b/README.md
@@ -0,0 +1,51 @@ +# Kelvin SW Repository + +This project contains the BSP to build the SW artifact that can run on the +Kelvin core, and integrated as part of the Shodan repository. + +The project supports two build systems -- Bazel and CMake -- for OSS integration +reasons. Bazel is used by [TFLM](https://github.com/tensorflow/tflite-micro) +flow, while CMake is the build system for [IREE](https://github.com/openxla/iree). + +## Prerequisite + +If you get this project from Project Shodan manifest, you are all set. If not, +you need to have following projects as well to build the project successfully. + +* Kelvin crosscompile toolchain: Under `<dir>/cache/toolchain_kelvin` + +This project needs to be at `<dir>/sw/kelvin`. + +## Code structure + +* build_tools: Build tool/rules for both Bazel and CMake +* crt: Kelvin BSP +* examples: Source code to build Kelvin SW artifacts. +* platforms: Crosscompile platform setup for Bazel. +* third_party: Third party repositories for Bazel. +* toolchains: Crosscomple toolchain setup for Bazel. + +## Build the project + +### Bazel + +The project uses Bazel 5.1.1, to align with +[OpenTitan](https://github.com/lowRISC/opentitan) build system requirements. + +```bash +bazel build //... +``` + +### CMake + +```note +TODO: Add CMake flow +``` + +## Run the executable + +```note +TODO: Add kelvin simulator +``` + +Load the generated `.bin` binaries to matcha FPGA emulator.
diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..60c42e0 --- /dev/null +++ b/WORKSPACE
@@ -0,0 +1,33 @@ +workspace(name = "kelvin") + +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +# Kelvin toolchain +new_local_repository( + name = "kelvin-gcc", + build_file = "third_party/kelvin-gcc/BUILD", + path = "../../cache/toolchain_kelvin", +) + +# CRT is the Compiler Repository Toolkit. It contains the configuration for +# the windows compiler. +maybe( + http_archive, + name = "crt", + url = "https://github.com/lowRISC/crt/archive/refs/tags/v0.3.4.tar.gz", + sha256 = "01a66778d1a0d5bbfb4ba30e72bd6876d0c20766d0b1921ab36ca3350cb48c60", + strip_prefix = "crt-0.3.4", +) + +load("@crt//:repos.bzl", "crt_repos") + +crt_repos() + +load("@crt//:deps.bzl", "crt_deps") + +crt_deps() + +load("//platforms:registration.bzl", "kelvin_register_toolchain") + +kelvin_register_toolchain()
diff --git a/build_tools/bazel/BUILD b/build_tools/bazel/BUILD new file mode 100644 index 0000000..ffd0fb0 --- /dev/null +++ b/build_tools/bazel/BUILD
@@ -0,0 +1 @@ +package(default_visibility = ["//visibility:public"])
diff --git a/build_tools/bazel/kelvin.bzl b/build_tools/bazel/kelvin.bzl new file mode 100644 index 0000000..84d037b --- /dev/null +++ b/build_tools/bazel/kelvin.bzl
@@ -0,0 +1,183 @@ +"""Rules to build Kelvin SW objects""" + +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") + + +KELVIN_PLATFORM = "//platforms/riscv32:kelvin" + +def _kelvin_transition_impl(_settings, _attr): + return {"//command_line_option:platforms": KELVIN_PLATFORM} + +kelvin_transition = transition( + implementation = _kelvin_transition_impl, + inputs = [], + outputs = ["//command_line_option:platforms"], +) + +def kelvin_rule(**kwargs): + """Kelvin-specific transition rule. + + A wrapper over rule() for creating rules that trigger + the transition to the kelvin platform config. + + Args: + **kwargs: params forwarded to the implementation. + Returns: + Kelvin transition rule. + """ + attrs = kwargs.pop("attrs", {}) + if "platform" not in attrs: + attrs["platform"] = attr.string(default = KELVIN_PLATFORM) + attrs["_allowlist_function_transition"] = attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ) + + return rule( + cfg = kelvin_transition, + attrs = attrs, + **kwargs + ) + +def _kelvin_binary_impl(ctx): + """Implements compilation for kelvin executables. + + This rule compiles and links provided input into an executable + suitable for use on the Kelvin core. Generates both an ELF + and a BIN. + + Args: + ctx: context for the rules. + srcs: Input source files. + deps: Target libraries that the binary depends upon. + hdrs: Header files that are local to the binary. + copts: Flags to pass along to the compiler. + defines: Preprocessor definitions. + linkopts: Flags to pass along to the linker. + + Output: + OutputGroupsInfo to allow definition of filegroups + containing the output ELF and BIN. + """ + cc_toolchain = find_cc_toolchain(ctx).cc + feature_configuration = cc_common.configure_features( + ctx = ctx, + cc_toolchain = cc_toolchain, + requested_features = ctx.features, + unsupported_features = ctx.disabled_features, + ) + compilation_contexts = [] + linking_contexts = [] + for dep in ctx.attr.deps: + if CcInfo in dep: + compilation_contexts.append(dep[CcInfo].compilation_context) + linking_contexts.append(dep[CcInfo].linking_context) + (_compilation_context, compilation_outputs) = cc_common.compile( + actions = ctx.actions, + cc_toolchain = cc_toolchain, + feature_configuration = feature_configuration, + name = ctx.label.name, + srcs = ctx.files.srcs, + compilation_contexts = compilation_contexts, + private_hdrs = ctx.files.hdrs, + user_compile_flags = ctx.attr.copts, + defines = ctx.attr.defines, + ) + linking_outputs = cc_common.link( + name = "{}.elf".format(ctx.label.name), + actions = ctx.actions, + feature_configuration = feature_configuration, + cc_toolchain = cc_toolchain, + compilation_outputs = compilation_outputs, + linking_contexts = linking_contexts, + user_link_flags = ctx.attr.linkopts + [ + "-Wl,-T,{}".format(ctx.file.linker_script.path), + ], + additional_inputs = depset([ctx.file.linker_script] + ctx.files.linker_script_includes), + output_type = "executable", + ) + + binary = ctx.actions.declare_file( + "{}.bin".format( + ctx.attr.name, + ), + ) + ctx.actions.run( + outputs = [binary], + inputs = [linking_outputs.executable] + cc_toolchain.all_files.to_list(), + arguments = [ + "-g", + "-O", + "binary", + linking_outputs.executable.path, + binary.path, + ], + executable = cc_toolchain.objcopy_executable, + ) + + return [ + DefaultInfo( + files = depset([linking_outputs.executable, binary]), + ), + OutputGroupInfo( + all_files = depset([linking_outputs.executable, binary]), + elf_file = depset([linking_outputs.executable]), + bin_file = depset([binary]), + ), + ] + +kelvin_binary_impl = kelvin_rule( + implementation = _kelvin_binary_impl, + attrs = { + "srcs": attr.label_list(allow_files = True), + "deps": attr.label_list(allow_empty = True, providers = [CcInfo]), + "hdrs": attr.label_list(allow_files = [".h"], allow_empty = True), + "copts": attr.string_list(), + "defines": attr.string_list(), + "linkopts": attr.string_list(), + "linker_script": attr.label(allow_single_file = True), + "linker_script_includes": attr.label_list(default = [], allow_files = True), + "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + }, + fragments = ["cpp"], + toolchains = ["@rules_cc//cc:toolchain_type"], +) + +def kelvin_binary(name, srcs, **kwargs): + """A helper macro for generating binary artifacts for the kelvin core. + + This macro uses the kelvin toolchain, kelvin-specific starting asm, + and kelvin linker script to build kelvin binaries. + + Args: + name: The name of this rule. + srcs: The c source files. + **kwargs: Additional arguments forward to cc_binary. + Emits rules: + filegroup named: <name>.bin + Containing the binary output for the target. + filegroup named: <name>.elf + Containing all elf output for the target. + """ + srcs = srcs + [ + "//crt:kelvin_gloss.cc", + "//crt:kelvin_start.S", + "//crt:crt.S", + ] + kelvin_binary_impl( + name = name, + srcs = srcs, + linker_script = "//crt:kelvin.ld", + **kwargs + ) + + # Need to create the following filegroups to make the output discoverable. + native.filegroup( + name = "{}.bin".format(name), + srcs = [name], + output_group = "bin_file", + ) + native.filegroup( + name = "{}.elf".format(name), + srcs = [name], + output_group = "elf_file", + )
diff --git a/crt/BUILD b/crt/BUILD new file mode 100644 index 0000000..72a00c5 --- /dev/null +++ b/crt/BUILD
@@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +# Exports the kelvin files to be used by the kelvin_binary() +exports_files([ + "crt.S", + "kelvin.ld", + "kelvin_gloss.cc", + "kelvin_start.S", +])
diff --git a/crt/crt.S b/crt/crt.S new file mode 100644 index 0000000..e5c34f5 --- /dev/null +++ b/crt/crt.S
@@ -0,0 +1,141 @@ +// Copyright 2023 Google LLC. +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +/** + * CRT library + * + * Utility functions written in assembly that can be used before the C + * runtime has been initialized. These functions should not be used once + * the C runtime has been initialized. + * + * The name of this library is historical. In many toolchains, a file called + * "crt0.o" is linked into each executable, which does something similar to + * what these functions + */ + + // NOTE: The "ax" flag below is necessary to ensure that this section + // is allocated space in ROM by the linker. + .section .crt, "ax", @progbits + + /** + * Write zeros into the section bounded by the start and end pointers. + * The section must be word (4 byte) aligned. It is valid for the section + * to have a length of 0 (i.e. the start and end pointers may be equal). + * + * This function follows the standard ILP32 calling convention for arguments + * but does not require a valid stack pointer, thread pointer or global + * pointer. + * + * Clobbers a0 and t0. + * + * @param a0 pointer to start of section to clear (inclusive). + * @param a1 pointer to end of section to clear (exclusive). + */ + .balign 4 + .global crt_section_clear + .type crt_section_clear, @function +crt_section_clear: + + // Check that start is before end. + bgeu a0, a1, .L_clear_nothing + + // Check that start and end are word aligned. + or t0, a0, a1 + andi t0, t0, 0x3 + bnez t0, .L_clear_error + +.L_clear_loop: + // Write zero into section memory word-by-word. + // TODO: unroll + sw zero, 0(a0) + addi a0, a0, 4 + bltu a0, a1, .L_clear_loop + ret + +.L_clear_nothing: + // If section length is 0 just return. Otherwise end is before start + // which is invalid so trigger an error. + bne a0, a1, .L_clear_error + ret + +.L_clear_error: + ebreak + + // Set function size to allow disassembly. + .size crt_section_clear, .-crt_section_clear + +// ----------------------------------------------------------------------------- + + /** + * Copy data from the given source into the section bounded by the start and + * end pointers. Both the section and the source must be word (4 byte) aligned. + * It is valid for the section to have a length of 0 (i.e. the start and end + * pointers may be equal). The source is assumed to have the same length as the + * target section. + * + * The destination section and the source must not overlap. + * + * This function follows the standard ILP32 calling convention for arguments + * but does not require a valid stack pointer, thread pointer or global + * pointer. + * + * Clobbers a0, a2, t0 and t1. + * + * @param a0 pointer to start of destination section (inclusive). + * @param a1 pointer to end of destination section (exclusive). + * @param a2 pointer to source data (inclusive). + */ + .balign 4 + .global crt_section_copy + .type crt_section_copy, @function +crt_section_copy: + + // Check that start is before end. + bgeu a0, a1, .L_copy_nothing + + // Check that start, end and src are word aligned. + or t0, a0, a1 + or t0, t0, a2 + andi t0, t0, 0x3 + bnez t0, .L_copy_error + + // Check that source does not destructively overlap destination + // (assuming a forwards copy). + // + // src start end + // | | | + // +-------------+ | + // | source | | + // +-------------+ | + // +-------------+ + // | destination | + // +-------------+ + // | | + // start end + // + // TODO: disallow all overlap since it indicates API misuse? + sub t0, a0, a2 // (start - src) mod 2**32 + sub t1, a1, a0 // end - start + bltu t0, t1, .L_copy_error + +.L_copy_loop: + // Copy data from src into section word-by-word. + // TODO: unroll + lw t0, 0(a2) + addi a2, a2, 4 + sw t0, 0(a0) + addi a0, a0, 4 + bltu a0, a1, .L_copy_loop + ret + +.L_copy_nothing: + // If section length is 0 just return. Otherwise end is before start + // which is invalid so trigger an error. + bne a0, a1, .L_copy_error + ret + +.L_copy_error: + ebreak + .size crt_section_copy, .-crt_section_copy
diff --git a/crt/kelvin.ld b/crt/kelvin.ld new file mode 100644 index 0000000..08f3542 --- /dev/null +++ b/crt/kelvin.ld
@@ -0,0 +1,135 @@ +/* Copyright 2023 Google LLC. */ +/* Licensed under the Apache License, Version 2.0, see LICENSE for details. */ +/* SPDX-License-Identifier: Apache-2.0 */ + +/** + * A simple linker script for kelvin core. + * + * Memory layout: + * + * TCM_ORIGIN ---> +=====================+ + * | | + * | .text | + * +---------------------| + * | .crt | + * +---------------------+ + * | .rodata | + * +---------------------+ + * | .init_array | + * +---------------------+ + * | .data | + * +---------------------+ + * | .bss | + * +---------------------+ + * | .heap | + * | (All unclamied | + * | memory) | + * | | + * (TCM_END - stack ---> +---------------------+ + * - model_output | .stack | + * - output_header) +---------------------+ + * | .model_output | + * output_header (64B) ---> +---------------------+ + * | .output_header | + * TCM_END ---> +=====================+ + **/ + +MEMORY { + TCM(rwx): ORIGIN = 0x00000000, LENGTH = 0x400000 +} + +STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x4000; +OUTPUT_SIZE = DEFINED(OUTPUT_SIZE) ? OUTPUT_SIZE : DEFINED(__output_size__) ? __output_size__ : 0x40; +__output_header_size__ = 0x40; + +ENTRY(_start) + +SECTIONS { + . = ORIGIN(TCM); + .text : ALIGN(4) { + *(._init) + *(.text) + *(.text.*) + . = ALIGN(4); + __etext = .; + } > TCM + + .init.array : ALIGN(4) { + __init_array_start = .; + *(.init_array) + *(.init_array.*) + . = ALIGN(4); + __init_array_end = .; + } > TCM + + .rodata : ALIGN(4) { + *(.srodata) + *(.srodata.*) + *(.rodata) + *(.rodata.*) + . = ALIGN(4); + } > TCM + + .data : ALIGN(4) { + __data_start__ = .; + /** + * This will get loaded into `gp`, and the linker will use that register for + * accessing data within [-2048,2047] of `__global_pointer$`. + * + * This is much cheaper (for small data) than materializing the + * address and loading from that (which will take one extra instruction). + */ + _global_pointer = . + 0x800; + *(.sdata) + *(.sdata.*) + *(.data) + *(.data.*) + /* Align on 256 width. */ + . = ALIGN(256); + __data_end__ = .; + } > TCM + + .bss : ALIGN(4) { + __bss_start__ = .; + *(.sbss) + *(.sbss.*) + *(.bss) + *(.bss.*) + __bss_end__ = .; + } > TCM + + /* All the unclaimed memory is used in heap */ + .heap (NOLOAD) : { + . = ALIGN(64); + __heap_start__ = .; + . = ORIGIN(TCM) + LENGTH(TCM) - STACK_SIZE - OUTPUT_SIZE - __output_header_size__ - 63; + . = ALIGN(64); + __heap_end__ = .; + } > TCM + + .stack ORIGIN(TCM) + LENGTH(TCM) - STACK_SIZE - OUTPUT_SIZE - __output_header_size__ (NOLOAD) : { + __stack_start__ = .; + . += STACK_SIZE; + . = ALIGN(64); + __stack_end__ = .; + _stack_end = .; + } > TCM + + .model_output ORIGIN(TCM) + LENGTH(TCM) - OUTPUT_SIZE - __output_header_size__ (NOLOAD) : { + . = ALIGN(64); + __model_output_start__ = .; + *(.model_output) + __model_output_end__ = .; + } > TCM + + .output_header ORIGIN(TCM) + LENGTH(TCM) - __output_header_size__ (NOLOAD) : { + /* + * Model output information (return code and output location/length) is + * always at the end of TCM. + */ + __output_header_start__ = .; + _ret = .; + *(.model_output_header*) + __output_header_end__ = .; + } > TCM +}
diff --git a/crt/kelvin_gloss.cc b/crt/kelvin_gloss.cc new file mode 100644 index 0000000..c5859f1 --- /dev/null +++ b/crt/kelvin_gloss.cc
@@ -0,0 +1,104 @@ +// Copyright 2023 Google LLC +// +// 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. +// +// Syscall stubs for newlib on Kelvin +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> + +void* __dso_handle = reinterpret_cast<void*>(&__dso_handle); + +extern "C" int _close(int file) { return -1; } + +extern "C" int _fstat(int file, struct stat* st) { + if (file != STDOUT_FILENO && file != STDERR_FILENO) { + errno = EBADF; + return -1; + } + + if (st == NULL) { + errno = EFAULT; + return -1; + } + + st->st_mode = S_IFCHR; + return 0; +} + +extern "C" int _isatty(int file) { + errno = ENOTTY; + return 1; +} + +extern "C" int _lseek(int file, int ptr, int dir) { + if (file != STDOUT_FILENO && file != STDERR_FILENO) { + errno = EBADF; + return -1; + } + + return 0; +} + +extern "C" int _read(int file, char* ptr, int len) { + errno = EBADF; + return -1; +} + +// TODO(hcindyl/lundong): implement printf properly. +extern "C" int _write(int file, char* ptr, int len) { + errno = EBADF; + return -1; +} + +extern "C" int _open(const char* path, int flags, ...) { return -1; } + +extern "C" void _exit(int status) { + asm volatile("ebreak"); + while (1) { + } +} + +extern "C" int _kill(int pid, int sig) { + asm volatile("ebreak"); + return -1; +} + +extern "C" int _getpid(void) { + asm volatile("ebreak"); + return -1; +} + +char* _heap_ptr; // Set to __heap_start__ in kelvin_start.S + +extern "C" void* _sbrk(int bytes) { + extern char __heap_end__; + char* prev_heap_end; + if ((bytes < 0) || (_heap_ptr + bytes > &__heap_end__)) { + errno = ENOMEM; + return reinterpret_cast<void*>(-1); + } + + prev_heap_end = _heap_ptr; + _heap_ptr += bytes; + + return reinterpret_cast<void*>(prev_heap_end); +} + +void operator delete(void* p) noexcept { free(p); } + +extern "C" void operator delete(void* p, uint32_t c) noexcept { + operator delete(p); +}
diff --git a/crt/kelvin_start.S b/crt/kelvin_start.S new file mode 100644 index 0000000..b162fdc --- /dev/null +++ b/crt/kelvin_start.S
@@ -0,0 +1,78 @@ +// Copyright 2023 Google LLC. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// A starting functions for simple kelvin programs. + +/** + * Entry point. + */ + .section ._init + .balign 4 + .global _start + .type _start, @function +_start: + ############################################### + # Put all scalar registers into a known state # + ############################################### + la sp, _stack_end + la gp, _global_pointer + la s0, __heap_start__ + sw s0, _heap_ptr, s1 + mv tp, zero + mv t1, zero + mv t2, zero + mv s0, zero + mv s1, zero + mv a1, zero + mv a2, zero + mv a3, zero + mv a4, zero + mv a5, zero + mv a6, zero + mv a7, zero + mv s2, zero + mv s3, zero + mv s4, zero + mv s5, zero + mv s6, zero + mv s7, zero + mv s8, zero + mv s9, zero + mv s10, zero + mv s11, zero + mv t3, zero + mv t4, zero + mv t5, zero + mv t6, zero + + # Zero out the bss section + la a0, __bss_start__ + la a1, __bss_end__ + call crt_section_clear + + # Initialize arrays + la s0, __init_array_start + la s1, __init_array_end + bgeu s0, s1, init_array_loop_end +init_array_loop: + lw t0, 0(s0) + jalr t0 + addi s0, s0, 0x4 + bltu s0, s1, init_array_loop +init_array_loop_end: + + + ############# + # Call main # + ############# + li a0, 0 # argv + li a1, 0 # argc + la ra, main + jalr ra, ra + # Store the application's return value at _ret + la t0, _ret + sw a0, 0(t0) + mpause # Kelvin end of program op +1: + j 1b
diff --git a/examples/hello_world/BUILD b/examples/hello_world/BUILD new file mode 100644 index 0000000..6f91382 --- /dev/null +++ b/examples/hello_world/BUILD
@@ -0,0 +1,8 @@ +load("//build_tools/bazel:kelvin.bzl", "kelvin_binary") + +kelvin_binary( + name = "hello_world", + srcs = [ + "hello_world.c", + ], +)
diff --git a/examples/hello_world/hello_world.c b/examples/hello_world/hello_world.c new file mode 100644 index 0000000..e47bd5e --- /dev/null +++ b/examples/hello_world/hello_world.c
@@ -0,0 +1,52 @@ +// Copyright 2023 Google LLC +// +// 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. +// A Simple kelvin program. + +#include <stddef.h> +#include <stdint.h> + +typedef struct { + uint32_t return_code; // Populated in kelvin_start.S. + uint32_t output_ptr; + uint32_t length; +} OutputHeader; + +__attribute__((section(".model_output_header"))) OutputHeader output_header = { + .output_ptr = 0, + .length = 0, +}; + +__attribute__((section(".model_output"))) uint32_t output; + +int main(int argc, char *argv[]) { + const uint32_t kDataSize = 0x1000 / sizeof(uint32_t); + uint32_t data[kDataSize]; + + for (int i = 0; i < sizeof(data) / sizeof(uint32_t); ++i) { + data[i] = i; + } + + for (int i = 0; i < sizeof(data) / sizeof(uint32_t); ++i) { + data[i] += 1; + } + + // Setup output. + output_header.length = sizeof(output); + output = data[kDataSize - 1]; + output_header.output_ptr = (uint32_t)&output; + + // invalidate all cache. + asm volatile("flushall"); + return 0; +}
diff --git a/platforms/BUILD b/platforms/BUILD new file mode 100644 index 0000000..bb7a41a --- /dev/null +++ b/platforms/BUILD
@@ -0,0 +1,5 @@ +licenses(["notice"]) + +package( + default_visibility = ["//visibility:public"], +)
diff --git a/platforms/cpu/BUILD b/platforms/cpu/BUILD new file mode 100644 index 0000000..4a03609 --- /dev/null +++ b/platforms/cpu/BUILD
@@ -0,0 +1,12 @@ +licenses(["notice"]) + +package( + default_visibility = ["//visibility:public"], +) + +constraint_setting(name = "cpu") + +constraint_value( + name = "kelvin", + constraint_setting = ":cpu", +)
diff --git a/platforms/registration.bzl b/platforms/registration.bzl new file mode 100644 index 0000000..43e75c5 --- /dev/null +++ b/platforms/registration.bzl
@@ -0,0 +1,5 @@ +"""Kelvin toolchain registration.""" + +def kelvin_register_toolchain(name = "kelvin"): + native.register_execution_platforms("//platforms/riscv32:kelvin") + native.register_toolchains("//toolchains/kelvin:all")
diff --git a/platforms/riscv32/BUILD b/platforms/riscv32/BUILD new file mode 100644 index 0000000..39cfec3 --- /dev/null +++ b/platforms/riscv32/BUILD
@@ -0,0 +1,9 @@ +package(default_visibility = ["//visibility:public"]) + +platform( + name = "kelvin", + constraint_values = [ + "//platforms/cpu:kelvin", + "@platforms//os:none", + ], +)
diff --git a/platforms/riscv32/devices.bzl b/platforms/riscv32/devices.bzl new file mode 100644 index 0000000..3e0878b --- /dev/null +++ b/platforms/riscv32/devices.bzl
@@ -0,0 +1,19 @@ +load("@crt//config:device.bzl", "device_config") + +DEVICES = [ + device_config( + name = "kelvin", + architecture = "rv32im", + feature_set = "//platforms/riscv32/features:rv32im", + constraints = [ + "//platforms/cpu:kelvin", + "@platforms//os:none", + ], + substitutions = { + "ARCHITECTURE": "rv32im", + "ABI": "ilp32", + "CMODEL": "medany", + "[STACK_PROTECTOR]": "-fstack-protector-strong", + }, + ), +]
diff --git a/platforms/riscv32/features/BUILD b/platforms/riscv32/features/BUILD new file mode 100644 index 0000000..98de11f --- /dev/null +++ b/platforms/riscv32/features/BUILD
@@ -0,0 +1,86 @@ +load( + "@crt//config:features.bzl", + "CPP_ALL_COMPILE_ACTIONS", + "C_ALL_COMPILE_ACTIONS", + "LD_ALL_ACTIONS", + "feature", + "feature_set", + "flag_group", + "flag_set", +) + +package(default_visibility = ["//visibility:public"]) + +feature( + name = "architecture", + enabled = True, + flag_sets = [ + flag_set( + actions = CPP_ALL_COMPILE_ACTIONS + C_ALL_COMPILE_ACTIONS + LD_ALL_ACTIONS, + flag_groups = [ + flag_group( + flags = [ + "-march=ARCHITECTURE", + "-mabi=ABI", + "-mcmodel=CMODEL", + ], + ), + ], + ), + ], +) + +feature( + name = "sys_spec", + enabled = True, + flag_sets = [ + flag_set( + actions = CPP_ALL_COMPILE_ACTIONS, + flag_groups = [ + flag_group( + flags = [ + "-march=ARCHITECTURE", + "-mabi=ABI", + "-mcmodel=CMODEL", + "-nostdlib", + ], + ), + ], + ), + flag_set( + actions = LD_ALL_ACTIONS, + flag_groups = [ + flag_group( + flags = [ + "--specs=nano.specs", + "-lm_nano", + "-lc_nano", + "-lg_nano", + "-lgcc", + "-nostartfiles", + ], + ), + ], + ), + ], +) + +feature_set( + name = "rv32im", + feature = [ + ":architecture", + ":sys_spec", + "@crt//features/embedded:cc_constructor_destructor", + "@crt//features/embedded:exceptions", + "@crt//features/embedded:runtime_type_information", + "@crt//platforms/riscv32/features:all_warnings_as_errors", + "@crt//platforms/riscv32/features:fastbuild", + "@crt//features/common:includes", + "@crt//features/common:all_warnings", + "@crt//features/common:all_warnings_as_errors", + "@crt//features/common:reproducible", + # TODO(atv): It would be nice to have the feature, but for now enabling + # this creates the wrong program. + # "@crt//features/common:symbol_garbage_collection", + ], +)
diff --git a/third_party/kelvin-gcc/BUILD b/third_party/kelvin-gcc/BUILD new file mode 100644 index 0000000..3148231 --- /dev/null +++ b/third_party/kelvin-gcc/BUILD
@@ -0,0 +1,9 @@ +# Automatically generated by @crt//:compiler.bzl. Do not edit. +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "all", + srcs = glob(["**"], exclude=["**/*.html","**/*.pdf"]), +) + +exports_files(["bin/**"])
diff --git a/toolchains/kelvin/BUILD b/toolchains/kelvin/BUILD new file mode 100644 index 0000000..ef7a6b7 --- /dev/null +++ b/toolchains/kelvin/BUILD
@@ -0,0 +1,52 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Forked from @crt//toolchains/lowrisc_rv32imcb/BUILD.bazel + +load("@crt//config:compiler.bzl", "setup") +load("//platforms/riscv32:devices.bzl", "DEVICES") + +package(default_visibility = ["//visibility:public"]) + +SYSTEM_INCLUDE_PATHS = [ + "external/kelvin-gcc/riscv32-unknown-elf/include/c++/10.2.0", + "external/kelvin-gcc/riscv32-unknown-elf/include/c++/10.2.0/backward", + "external/kelvin-gcc/riscv32-unknown-elf/include/c++/10.2.0/riscv32-unknown-elf", + "external/kelvin-gcc/lib/gcc/riscv32-unknown-elf/10.2.0/include", + "external/kelvin-gcc/riscv32-unknown-elf/include", + "external/kelvin-gcc/lib/gcc/riscv32-unknown-elf/10.2.0/include-fixed", +] + +filegroup( + name = "compiler_components", + srcs = [ + "//toolchains/kelvin/wrappers:all", + "@kelvin-gcc//:all", + ], +) + +[setup( + name = device.name, + architecture = device.architecture, + artifact_naming = device.artifact_naming, + compiler_components = ":compiler_components", + constraints = device.constraints, + feature_set = device.feature_set, + include_directories = SYSTEM_INCLUDE_PATHS, + params = { + "compiler": "gcc", + }, + substitutions = device.substitutions, + tools = { + "ar": "wrappers/ar", + "cpp": "wrappers/cpp", + "gcc": "wrappers/gcc", + "gcov": "wrappers/gcov", + "ld": "wrappers/ld", + "nm": "wrappers/nm", + "objcopy": "wrappers/objcopy", + "objdump": "wrappers/objdump", + "strip": "wrappers/strip", + }, +) for device in DEVICES]
diff --git a/toolchains/kelvin/wrappers/BUILD b/toolchains/kelvin/wrappers/BUILD new file mode 100644 index 0000000..7121e88 --- /dev/null +++ b/toolchains/kelvin/wrappers/BUILD
@@ -0,0 +1,19 @@ +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*"])) + +filegroup( + name = "all", + srcs = [ + "ar", + "clang", + "cpp", + "gcc", + "gcov", + "ld", + "nm", + "objcopy", + "objdump", + "strip", + ], +)
diff --git a/toolchains/kelvin/wrappers/ar b/toolchains/kelvin/wrappers/ar new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/ar
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/clang b/toolchains/kelvin/wrappers/clang new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/clang
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/cpp b/toolchains/kelvin/wrappers/cpp new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/cpp
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/driver.sh b/toolchains/kelvin/wrappers/driver.sh new file mode 100755 index 0000000..eb2994e --- /dev/null +++ b/toolchains/kelvin/wrappers/driver.sh
@@ -0,0 +1,21 @@ +#!/bin/bash --norc +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +PROG=$(basename "$0") +DRIVER_DIR=$(dirname "$0") +TOOLCHAIN="kelvin-gcc" +PREFIX="riscv32-unknown-elf" + +ARGS=() +POSTARGS=() +case "${PROG}" in + gcc) + ;; +esac + +exec "external/${TOOLCHAIN}/bin/${PREFIX}-${PROG}" \ + "${ARGS[@]}" \ + "$@"\ + "${POSTARGS[@]}"
diff --git a/toolchains/kelvin/wrappers/gcc b/toolchains/kelvin/wrappers/gcc new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/gcc
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/gcov b/toolchains/kelvin/wrappers/gcov new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/gcov
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/ld b/toolchains/kelvin/wrappers/ld new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/ld
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/nm b/toolchains/kelvin/wrappers/nm new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/nm
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/objcopy b/toolchains/kelvin/wrappers/objcopy new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/objcopy
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/objdump b/toolchains/kelvin/wrappers/objdump new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/objdump
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file
diff --git a/toolchains/kelvin/wrappers/strip b/toolchains/kelvin/wrappers/strip new file mode 120000 index 0000000..da2bdd9 --- /dev/null +++ b/toolchains/kelvin/wrappers/strip
@@ -0,0 +1 @@ +driver.sh \ No newline at end of file