├── .gitignore ├── python-requirements.txt ├── .gitmodules ├── samples ├── float_model │ ├── mnist_emitc_static_test.txt │ ├── mnist_bytecode_static_test.txt │ ├── mobilenet_v1_emitc_static_test.txt │ ├── mobilenet_v1_bytecode_static_test.txt │ ├── mnist.h │ ├── mobilenet_v1.h │ ├── mnist.c │ ├── mobilenet_v1.c │ └── CMakeLists.txt ├── quant_model │ ├── mobilenet_v1_emitc_static_test.txt │ ├── mobilenet_v1_bytecode_static_test.txt │ ├── mobilenet_v1.h │ ├── CMakeLists.txt │ └── mobilenet_v1.c ├── simple_vec_mul │ ├── simple_float_mul.mlir │ ├── simple_int_mul.mlir │ ├── simple_test.txt │ ├── int_vec.c │ ├── float_vec.c │ └── CMakeLists.txt ├── CMakeLists.txt ├── util │ ├── util.h │ ├── alloc.h │ ├── alloc.c │ ├── CMakeLists.txt │ ├── model_api.h │ └── util.c ├── device │ ├── CMakeLists.txt │ ├── device.h │ ├── device_vmvx_loader.c │ └── device_static_loader.c └── lit.cfg.py ├── .github └── workflows │ └── springbok.yml ├── CONTRIBUTING.md ├── springbok_config.h ├── sim └── config │ ├── springbok.resc │ ├── platforms │ └── springbok.repl │ └── infrastructure │ └── SpringbokRiscV32.cs ├── springbok ├── CMakeLists.txt ├── include │ ├── springbok.h │ └── springbok_intrinsics.h ├── springbok.ld ├── springbok_gloss.cpp ├── crt0.S └── springbok.cpp ├── cmake ├── riscv_springbok.cmake ├── springbok_ops.cmake ├── riscv_iree.cmake ├── iree_model_input.cmake ├── springbok_vmvx_module.cmake ├── springbok_modules.cmake └── springbok_static_module.cmake ├── README.md ├── CMakeLists.txt └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /python-requirements.txt: -------------------------------------------------------------------------------- 1 | PILLOW 2 | numpy 3 | lit 4 | requests 5 | wget 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third_party/iree"] 2 | path = third_party/iree 3 | url = https://github.com/google/iree.git 4 | -------------------------------------------------------------------------------- /samples/float_model/mnist_emitc_static_test.txt: -------------------------------------------------------------------------------- 1 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/float_model/mnist_emitc_static 2>&1 | tee %t 2 | // RUN: cat %t | FileCheck %s 3 | // CHECK: {{digit: 4}} 4 | -------------------------------------------------------------------------------- /samples/float_model/mnist_bytecode_static_test.txt: -------------------------------------------------------------------------------- 1 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/float_model/mnist_bytecode_static 2>&1 | tee %t 2 | // RUN: cat %t | FileCheck %s 3 | // CHECK: {{digit: 4}} 4 | -------------------------------------------------------------------------------- /samples/float_model/mobilenet_v1_emitc_static_test.txt: -------------------------------------------------------------------------------- 1 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/float_model/mobilenet_v1_emitc_static 2>&1 | tee %t 2 | // RUN: cat %t | FileCheck %s 3 | // CHECK: {{Image prediction result is: id: 178}} 4 | -------------------------------------------------------------------------------- /samples/quant_model/mobilenet_v1_emitc_static_test.txt: -------------------------------------------------------------------------------- 1 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/quant_model/mobilenet_v1_emitc_static 2>&1 | tee %t 2 | // RUN: cat %t | FileCheck %s 3 | // CHECK: {{Image prediction result is: id: 178}} 4 | -------------------------------------------------------------------------------- /samples/float_model/mobilenet_v1_bytecode_static_test.txt: -------------------------------------------------------------------------------- 1 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/float_model/mobilenet_v1_bytecode_static 2>&1 | tee %t 2 | // RUN: cat %t | FileCheck %s 3 | // CHECK: {{Image prediction result is: id: 178}} 4 | -------------------------------------------------------------------------------- /samples/quant_model/mobilenet_v1_bytecode_static_test.txt: -------------------------------------------------------------------------------- 1 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/quant_model/mobilenet_v1_bytecode_static 2>&1 | tee %t 2 | // RUN: cat %t | FileCheck %s 3 | // CHECK: {{Image prediction result is: id: 178}} 4 | -------------------------------------------------------------------------------- /samples/simple_vec_mul/simple_float_mul.mlir: -------------------------------------------------------------------------------- 1 | func.func @simple_mul(%arg0: tensor<1024xf32>, %arg1: tensor<1024xf32>) -> tensor<1024xf32> 2 | { 3 | %0 = "mhlo.multiply"(%arg0, %arg1) : (tensor<1024xf32>, tensor<1024xf32>) -> tensor<1024xf32> 4 | return %0 : tensor<1024xf32> 5 | } 6 | -------------------------------------------------------------------------------- /samples/simple_vec_mul/simple_int_mul.mlir: -------------------------------------------------------------------------------- 1 | func.func @simple_mul(%arg0: tensor<1024xi32>, %arg1: tensor<1024xi32>) -> tensor<1024xi32> 2 | { 3 | %0 = "mhlo.multiply"(%arg0, %arg1) : (tensor<1024xi32>, tensor<1024xi32>) -> tensor<1024xi32> 4 | return %0 : tensor<1024xi32> 5 | } 6 | -------------------------------------------------------------------------------- /.github/workflows/springbok.yml: -------------------------------------------------------------------------------- 1 | name: Springbok README tests 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | test: 10 | runs-on: ubuntu-22.04 11 | steps: 12 | - name: Clone repository 13 | uses: actions/checkout@v2 14 | 15 | - name: Install tuttest 16 | run: pip install git+https://github.com/antmicro/tuttest 17 | 18 | - name: Run tuttest 19 | run: tuttest README.md | grep -v sim_springbok | bash -e - 20 | -------------------------------------------------------------------------------- /samples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | iree_add_all_subdirs() 16 | -------------------------------------------------------------------------------- /samples/simple_vec_mul/simple_test.txt: -------------------------------------------------------------------------------- 1 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/simple_vec_mul/simple_int_vec_mul_bytecode_static 2 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/simple_vec_mul/simple_int_vec_mul_emitc_static 3 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/simple_vec_mul/simple_int_vec_mul_bytecode_vmvx 4 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/simple_vec_mul/simple_int_vec_mul_emitc_vmvx 5 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/simple_vec_mul/simple_float_vec_mul_bytecode_static 6 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/simple_vec_mul/simple_float_vec_mul_emitc_static 7 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/simple_vec_mul/simple_float_vec_mul_bytecode_vmvx 8 | // RUN: ${TEST_RUNNER_CMD} ${BUILD}/samples/simple_vec_mul/simple_float_vec_mul_emitc_vmvx 9 | -------------------------------------------------------------------------------- /samples/util/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef SAMPLES_UTIL_UTIL_H_ 18 | #define SAMPLES_UTIL_UTIL_H_ 19 | 20 | // A top-level header collection for ML executable utility library. 21 | 22 | #include "samples/util/alloc.h" 23 | #include "samples/util/model_api.h" 24 | 25 | #endif // SAMPLES_UTIL_UTIL_H_ 26 | -------------------------------------------------------------------------------- /samples/util/alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef SAMPLES_UTIL_ALLOC_H_ 18 | #define SAMPLES_UTIL_ALLOC_H_ 19 | 20 | #include "samples/util/model_api.h" 21 | 22 | // Allocate the input buffer w.r.t the model config. 23 | // The buffer must be released by the external caller. 24 | iree_status_t alloc_input_buffer(const MlModel *model, void **buffer); 25 | 26 | #endif // SAMPLES_UTIL_ALLOC_H_ 27 | -------------------------------------------------------------------------------- /samples/device/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | iree_cc_library( 16 | NAME 17 | device_static_loader 18 | HDRS 19 | "device.h" 20 | SRCS 21 | "device_static_loader.c" 22 | DEPS 23 | iree::hal::drivers::local_sync::sync_driver 24 | iree::hal::local::loaders::static_library_loader 25 | ) 26 | 27 | iree_cc_library( 28 | NAME 29 | device_vmvx_loader 30 | HDRS 31 | "device.h" 32 | SRCS 33 | "device_vmvx_loader.c" 34 | DEPS 35 | iree::hal::drivers::local_sync::sync_driver 36 | iree::hal::local::loaders::vmvx_module_loader 37 | ) 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement (CLA). You (or your employer) retain the copyright to your 10 | contribution; this simply gives us permission to use and redistribute your 11 | contributions as part of the project. Head over to 12 | to see your current agreements on file or 13 | to sign a new one. 14 | 15 | You generally only need to submit a CLA once, so if you've already submitted one 16 | (even if it was for a different project), you probably don't need to do it 17 | again. 18 | 19 | ## Code Reviews 20 | 21 | All submissions, including submissions by project members, require review. We 22 | use GitHub pull requests for this purpose. Consult 23 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 24 | information on using pull requests. 25 | 26 | ## Community Guidelines 27 | 28 | This project follows 29 | [Google's Open Source Community Guidelines](https://opensource.google/conduct/). 30 | -------------------------------------------------------------------------------- /springbok_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Springbok-specific implementation for some IREE functions. 18 | 19 | #ifndef SPRINGBOK_CONFIG_H 20 | #define SPRINGBOK_CONFIG_H 21 | 22 | // IREE_TIME_NOW_FN is required and used to fetch the current RTC time and to be 23 | // used for wait handling. A thread-less system can just return 0. 24 | #define IREE_TIME_NOW_FN \ 25 | { \ 26 | return 0; \ 27 | } 28 | 29 | // IREE_DEVICE_SIZE_T for status print out. 30 | #define IREE_DEVICE_SIZE_T uint32_t 31 | #define PRIdsz PRIu32 32 | 33 | #endif // SPRINGBOK_CONFIG_H 34 | -------------------------------------------------------------------------------- /samples/util/alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "samples/util/alloc.h" 18 | 19 | iree_status_t alloc_input_buffer(const MlModel *model, void **buffer) { 20 | iree_status_t result = iree_ok_status(); 21 | for (int i = 0; i < model->num_input; ++i) { 22 | if (iree_status_is_ok(result)) { 23 | buffer[i] = aligned_alloc(sizeof(uint32_t), model->input_size_bytes[i] * 24 | model->input_length[i]); 25 | if (buffer[i] == NULL) { 26 | result = iree_make_status(IREE_STATUS_RESOURCE_EXHAUSTED); 27 | } 28 | } 29 | } 30 | return result; 31 | } 32 | -------------------------------------------------------------------------------- /samples/device/device.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef SAMPLES_DEVICE_DEVICE_H_ 18 | #define SAMPLES_DEVICE_DEVICE_H_ 19 | 20 | #include "iree/hal/local/executable_loader.h" 21 | 22 | // Create the HAL device from the different backend targets. 23 | // The HAL device and loader are returned based on the implementation, and they 24 | // must be released by the caller. 25 | iree_status_t create_sample_device(iree_allocator_t host_allocator, 26 | iree_hal_device_t** out_device, 27 | iree_hal_executable_loader_t** loader); 28 | 29 | #endif // SAMPLES_DEVICE_DEVICE_H_ 30 | -------------------------------------------------------------------------------- /sim/config/springbok.resc: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http:#www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # Renode script for testing the Springbok Vector Core 16 | 17 | mach create "springbok" 18 | 19 | EnsureTypeIsLoaded "Antmicro.Renode.Peripherals.CPU.RiscV32" 20 | include @sim/config/infrastructure/SpringbokRiscV32.cs 21 | 22 | $platformfile?=@sim/config/platforms/springbok.repl 23 | 24 | machine LoadPlatformDescription $platformfile 25 | 26 | $bin?=@build/build-riscv/samples/simple_vec_mul/simple_int_vec_mul_emitc_static 27 | 28 | sysbus.cpu2 EnableRiscvOpcodesCounting 29 | 30 | macro reset 31 | """ 32 | sysbus LoadELF $bin 33 | # Start the vector core at address 0 of its instruction TCM. 34 | sysbus.cpu2 IsHalted true 35 | sysbus.cpu2 PC 0x32000000 36 | """ 37 | runMacro $reset 38 | -------------------------------------------------------------------------------- /samples/float_model/mnist.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef SAMPLES_FLOAT_MODEL_MNIST_H 18 | #define SAMPLES_FLOAT_MODEL_MNIST_H 19 | 20 | #include "samples/util/util.h" 21 | 22 | typedef struct { 23 | int best_idx; 24 | float best_out; 25 | } MnistOutput; 26 | 27 | const MlModel kModel = { 28 | .num_input = 1, 29 | .num_input_dim = {4}, 30 | .input_shape = {{1, 28, 28, 1}}, 31 | .input_length = {28 * 28 * 1}, 32 | .input_size_bytes = {sizeof(float)}, 33 | .num_output = 1, 34 | .output_length = {10}, 35 | .output_size_bytes = sizeof(float), 36 | .hal_element_type = IREE_HAL_ELEMENT_TYPE_FLOAT_32, 37 | .entry_func = "module.predict", 38 | .model_name = "mnist", 39 | }; 40 | 41 | #endif // SAMPLES_FLOAT_MODEL_MNIST_H_ 42 | -------------------------------------------------------------------------------- /springbok/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | enable_language(ASM) 16 | 17 | add_library(springbok INTERFACE) 18 | add_library(springbok_intrinsic STATIC) 19 | target_sources(springbok_intrinsic 20 | PRIVATE 21 | crt0.S 22 | springbok_gloss.cpp 23 | springbok.cpp 24 | ) 25 | 26 | target_include_directories(springbok_intrinsic PUBLIC include) 27 | 28 | target_link_libraries(springbok 29 | INTERFACE 30 | springbok_intrinsic 31 | ) 32 | 33 | target_include_directories(springbok INTERFACE include) 34 | 35 | target_compile_options(springbok_intrinsic 36 | PUBLIC 37 | ${VEC_DEFAULT_COPTS} 38 | ) 39 | 40 | target_link_options(springbok 41 | INTERFACE 42 | -Wl,--whole-archive ${CMAKE_CURRENT_BINARY_DIR}/libspringbok_intrinsic.a -Wl,--no-whole-archive 43 | ) 44 | -------------------------------------------------------------------------------- /samples/float_model/mobilenet_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef SAMPLES_FLOAT_MODEL_MOBILENETV1_H 18 | #define SAMPLES_FLOAT_MODEL_MOBILENETV1_H 19 | 20 | #include "samples/util/util.h" 21 | 22 | typedef struct { 23 | int best_idx; 24 | float best_out; 25 | } MobilenetV1Output; 26 | 27 | const MlModel kModel = { 28 | .num_input = 1, 29 | .num_input_dim = {4}, 30 | .input_shape = {{1, 224, 224, 3}}, 31 | .input_length = {224 * 224 * 3}, 32 | .input_size_bytes = {sizeof(float)}, 33 | .num_output = 1, 34 | .output_length = {1001}, 35 | .output_size_bytes = sizeof(float), 36 | .hal_element_type = IREE_HAL_ELEMENT_TYPE_FLOAT_32, 37 | .entry_func = "module.main", 38 | .model_name = "mobilenet_v1_0.25_224_float", 39 | }; 40 | 41 | #endif // SAMPLES_FLOAT_MODEL_MOBILENET_V1_H_ 42 | -------------------------------------------------------------------------------- /samples/quant_model/mobilenet_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef SAMPLES_QUANT_MODEL_MOBILENETV1_H 18 | #define SAMPLES_QUANT_MODEL_MOBILENETV1_H 19 | 20 | #include "samples/util/util.h" 21 | 22 | typedef struct { 23 | int best_idx; 24 | int best_out; 25 | } MobilenetV1Output; 26 | 27 | const MlModel kModel = { 28 | .num_input = 1, 29 | .num_input_dim = {4}, 30 | .input_shape = {{1, 224, 224, 3}}, 31 | .input_length = {224 * 224 * 3}, 32 | .input_size_bytes = {sizeof(uint8_t)}, 33 | .num_output = 1, 34 | .output_length = {1001}, 35 | .output_size_bytes = sizeof(uint8_t), 36 | .hal_element_type = IREE_HAL_ELEMENT_TYPE_UINT_8, 37 | .entry_func = "module.main", 38 | .model_name = "mobilenet_v1_0.25_224_quant", 39 | }; 40 | 41 | #endif // SAMPLES_QUANT_MODELS_MOBILENET_V1_H_ 42 | -------------------------------------------------------------------------------- /cmake/riscv_springbok.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # A cmake cache to connect springbok BSP with the executables 16 | 17 | if(NOT TARGET springbok) 18 | message(FATAL_ERROR "Please include springbok target first") 19 | endif() 20 | 21 | if(NOT DEFINED SPRINGBOK_LINKER_SCRIPT) 22 | message(FATAL_ERROR "Please specifiy SPRINGBOK_LINKER_SCRIPT path first") 23 | endif() 24 | 25 | function(add_executable executable) 26 | cmake_parse_arguments(AE "ALIAS;IMPORTED" "" "" ${ARGN}) 27 | if(AE_ALIAS OR AE_IMPORTED) 28 | _add_executable(${executable} ${ARGN}) 29 | else() 30 | _add_executable(${executable} ${ARGN}) 31 | target_link_libraries(${executable} PRIVATE springbok) 32 | target_link_options(${executable} PRIVATE "-T${SPRINGBOK_LINKER_SCRIPT}") 33 | target_link_options(${executable} PRIVATE "-nostartfiles") 34 | endif() 35 | endfunction() 36 | -------------------------------------------------------------------------------- /sim/config/platforms/springbok.repl: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // *************************************************** 16 | // Springbok 17 | // *************************************************** 18 | 19 | cpu2: CPU.SpringbokRiscV32 @ sysbus 20 | hartId: 2 21 | 22 | //RAM_VEC_IMEM [‘h3200_0000 - ‘h320F_FFFF) 1MB RAM for Vector core Instruction 23 | // Remember to update hart_is_vc in rom_crt.S if this changes. 24 | ram_vec_imem: Memory.MappedMemory @ sysbus 0x32000000 25 | size: 0x00100000 26 | 27 | //RAM_VEC_DMEM [‘h3400_0000 - ‘h34FF_FFFF) 16MB RAM for Vector core Data 28 | ram_vec_dmem: Memory.MappedMemory @ sysbus 0x34000000 29 | size: 0x01000000 30 | 31 | //RAM_VEC_CSR [‘h3800_0000 - ‘h3800_0FFF) 4KB RAM for Vector Core CSRs 32 | ram_vec_csr: Memory.MappedMemory @ sysbus 0x38000000 33 | size: 0x00001000 34 | 35 | vec_controlblock : CPU.SpringbokRiscV32_ControlBlock @ sysbus 0x47000000 36 | core: cpu2 37 | imem: ram_vec_imem 38 | dmem: ram_vec_dmem 39 | -------------------------------------------------------------------------------- /samples/lit.cfg.py: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import sys 17 | 18 | import lit.formats 19 | import lit.llvm 20 | 21 | # Configuration file for the 'lit' test runner. 22 | lit.llvm.initialize(lit_config, config) 23 | 24 | config.name = "Model tests" 25 | config.test_format = lit.formats.ShTest(True) 26 | 27 | config.suffixes = [".txt"] 28 | config.excludes = [ 29 | "CMakeLists.txt" 30 | ] 31 | dir_path = os.path.dirname(os.path.realpath(__file__)) 32 | config.environment["ROOTDIR"] = dir_path + "/.." 33 | config.environment["BUILD"] = config.environment["ROOTDIR"] + "/build/build-riscv" 34 | 35 | renode_cmd = ( 36 | "%s/build_tools/test_runner.py" 37 | " --renode-path %s/build/renode/renode" 38 | % (config.environment["ROOTDIR"], config.environment["ROOTDIR"])) 39 | 40 | config.test_exec_root = config.environment["ROOTDIR"] + "/build/springbok_iree/tests" 41 | 42 | # Enable features based on -D FEATURES=internal syntax. FEATURE is used in the 43 | # REQUIRES field in the lit test. Can add multiple features with comma delimiter. 44 | features_param = lit_config.params.get("FEATURES") 45 | if features_param: 46 | config.available_features.update(features_param.split(',')) 47 | 48 | config.environment["TEST_RUNNER_CMD"] = renode_cmd 49 | -------------------------------------------------------------------------------- /samples/util/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | iree_cc_library( 16 | NAME 17 | util_base 18 | HDRS 19 | "util.h" 20 | SRCS 21 | "util.c" 22 | DEPS 23 | ::alloc 24 | iree::modules::hal 25 | ) 26 | 27 | # static library using regular HAL 28 | iree_cc_library( 29 | NAME 30 | util_static 31 | DEPS 32 | ::util_base 33 | samples::device::device_static_loader 34 | ) 35 | 36 | # vmvx using regular HAL 37 | iree_cc_library( 38 | NAME 39 | util_vmvx 40 | DEPS 41 | ::util_base 42 | samples::device::device_vmvx_loader 43 | ) 44 | 45 | # static library using inline HAL 46 | iree_cc_library( 47 | NAME 48 | util_static_inline 49 | HDRS 50 | "util.h" 51 | SRCS 52 | "util.c" 53 | DEPS 54 | ::alloc 55 | iree::modules::hal::inline 56 | iree::modules::hal::loader 57 | samples::device::device_static_loader 58 | COPTS 59 | "-DBUILD_LOADER_HAL" 60 | ) 61 | 62 | # vmvx using inline HAL 63 | iree_cc_library( 64 | NAME 65 | util_vmvx_inline 66 | HDRS 67 | "util.h" 68 | SRCS 69 | "util.c" 70 | DEPS 71 | ::alloc 72 | iree::modules::hal::inline 73 | samples::device::device_vmvx_loader 74 | COPTS 75 | "-DBUILD_INLINE_HAL" 76 | ) 77 | 78 | iree_cc_library( 79 | NAME 80 | alloc 81 | HDRS 82 | "alloc.h" 83 | SRCS 84 | "alloc.c" 85 | DEPS 86 | iree::base 87 | ) 88 | -------------------------------------------------------------------------------- /springbok/include/springbok.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef SPRINGBOK_H 18 | #define SPRINGBOK_H 19 | #include 20 | #include 21 | 22 | #define ERROR_TAG "ERROR" 23 | #define WARN_TAG "WARN" 24 | #define INFO_TAG "INFO" 25 | #define DEBUG_TAG "DEBUG" 26 | #define NOISY_TAG "NOISY" 27 | 28 | #define LOG_FMT "%s |" 29 | #define LOG_ARGS(LOG_TAG) LOG_TAG 30 | 31 | #define LOG_MAX_SZ 256 32 | 33 | #define SIMLOG(sim_log_level, fmt, ...) \ 34 | do { \ 35 | char tmp_log_msg[LOG_MAX_SZ]; \ 36 | snprintf(tmp_log_msg, LOG_MAX_SZ, fmt, __VA_ARGS__); \ 37 | springbok_simprint_##sim_log_level(tmp_log_msg, 0); \ 38 | } while (0) 39 | 40 | #define LOG_ERROR(msg, args...) \ 41 | SIMLOG(error, LOG_FMT msg, LOG_ARGS(ERROR_TAG), ##args) 42 | #define LOG_WARN(msg, args...) \ 43 | SIMLOG(warning, LOG_FMT msg, LOG_ARGS(WARN_TAG), ##args) 44 | #define LOG_INFO(msg, args...) \ 45 | SIMLOG(info, LOG_FMT msg, LOG_ARGS(INFO_TAG), ##args) 46 | #define LOG_DEBUG(msg, args...) \ 47 | SIMLOG(debug, LOG_FMT msg, LOG_ARGS(DEBUG_TAG), ##args) 48 | #define LOG_NOISY(msg, args...) \ 49 | SIMLOG(noisy, LOG_FMT msg, LOG_ARGS(NOISY_TAG), ##args) 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | int float_to_str(const int len, char *buffer, const float value); 55 | #ifdef __cplusplus 56 | } 57 | #endif 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /samples/device/device_vmvx_loader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // VMVX module loading in IREE. 18 | 19 | #include "iree/hal/drivers/local_sync/sync_device.h" 20 | #include "iree/hal/local/loaders/vmvx_module_loader.h" 21 | #include "samples/device/device.h" 22 | 23 | // A function to create the HAL device from the different backend targets. 24 | // The HAL device and loader are returned based on the implementation, and they 25 | // must be released by the caller. 26 | iree_status_t create_sample_device(iree_allocator_t host_allocator, 27 | iree_hal_device_t** out_device, 28 | iree_hal_executable_loader_t** loader) { 29 | // Set parameters for the device created in the next step. 30 | iree_hal_sync_device_params_t params; 31 | iree_hal_sync_device_params_initialize(¶ms); 32 | 33 | iree_vm_instance_t* instance = NULL; 34 | iree_status_t status = iree_vm_instance_create(host_allocator, &instance); 35 | 36 | if (iree_status_is_ok(status)) { 37 | status = iree_hal_vmvx_module_loader_create( 38 | instance, /*user_module_count=*/0, /*user_modules=*/NULL, 39 | host_allocator, loader); 40 | } 41 | iree_vm_instance_release(instance); 42 | 43 | // Use the default host allocator for buffer allocations. 44 | iree_string_view_t identifier = iree_make_cstring_view("vmvx"); 45 | iree_hal_allocator_t* device_allocator = NULL; 46 | if (iree_status_is_ok(status)) { 47 | status = iree_hal_allocator_create_heap(identifier, host_allocator, 48 | host_allocator, &device_allocator); 49 | } 50 | 51 | if (iree_status_is_ok(status)) { 52 | // Create the synchronous device. 53 | status = iree_hal_sync_device_create( 54 | identifier, ¶ms, /*loader_count=*/1, loader, device_allocator, 55 | host_allocator, out_device); 56 | } 57 | 58 | iree_hal_allocator_release(device_allocator); 59 | return status; 60 | } 61 | -------------------------------------------------------------------------------- /samples/util/model_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef SAMPLES_UTIL_MODEL_API_H_ 18 | #define SAMPLES_UTIL_MODEL_API_H_ 19 | 20 | // Define ML model configuration and model-specific utility APIs. 21 | 22 | #include "iree/hal/local/executable_library.h" 23 | #include "iree/modules/hal/module.h" 24 | #include "iree/vm/bytecode_module.h" 25 | 26 | #define MAX_MODEL_INPUT_NUM 2 27 | #define MAX_MODEL_INPUT_DIM 4 28 | #define MAX_MODEL_OUTPUTS 12 29 | #define MAX_ENTRY_FUNC_NAME 20 30 | 31 | typedef struct { 32 | int num_input; 33 | int num_input_dim[MAX_MODEL_INPUT_NUM]; 34 | iree_hal_dim_t input_shape[MAX_MODEL_INPUT_NUM][MAX_MODEL_INPUT_DIM]; 35 | int input_length[MAX_MODEL_INPUT_NUM]; 36 | int input_size_bytes[MAX_MODEL_INPUT_NUM]; 37 | int num_output; 38 | int output_length[MAX_MODEL_OUTPUTS]; 39 | int output_size_bytes; 40 | enum iree_hal_element_types_t hal_element_type; 41 | char entry_func[MAX_ENTRY_FUNC_NAME]; 42 | char model_name[]; 43 | } MlModel; 44 | 45 | // Load the statically embedded library 46 | iree_hal_executable_library_query_fn_t library_query(void); 47 | 48 | // Function to create the bytecode or C module. 49 | iree_status_t create_module(iree_vm_instance_t *instance, 50 | iree_vm_module_t **module); 51 | 52 | // For each ML workload, based on the model configuration, allocate the buffer 53 | // and prepare the data. It can be loaded from a embedded image binary, a 54 | // randomly generated stream, or a pointer from the sensor/ISP output. 55 | iree_status_t load_input_data(const MlModel *model, void **buffer, 56 | iree_const_byte_span_t **byte_span); 57 | 58 | // Process the ML execution output into the final data to be sent to the 59 | // host. `output_length` is set to the total byte size of the model's output. 60 | iree_status_t process_output(const MlModel *model, 61 | iree_hal_buffer_mapping_t *buffers, 62 | uint32_t *output_length); 63 | 64 | #endif // SAMPLES_UTIL_MODEL_API_H_ 65 | -------------------------------------------------------------------------------- /samples/device/device_static_loader.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Static library loading in IREE. 18 | 19 | #include "iree/hal/drivers/local_sync/sync_device.h" 20 | #include "iree/hal/local/loaders/static_library_loader.h" 21 | #include "samples/util/model_api.h" 22 | 23 | // A function to create the HAL device from the different backend targets. 24 | // The HAL device and loader are returned based on the implementation, and they 25 | // must be released by the caller. 26 | iree_status_t create_sample_device(iree_allocator_t host_allocator, 27 | iree_hal_device_t** out_device, 28 | iree_hal_executable_loader_t** loader) { 29 | iree_status_t status = iree_ok_status(); 30 | 31 | // Set paramters for the device created in the next step. 32 | iree_hal_sync_device_params_t params; 33 | iree_hal_sync_device_params_initialize(¶ms); 34 | 35 | // Load the statically embedded library 36 | const iree_hal_executable_library_query_fn_t libraries[] = {library_query()}; 37 | 38 | if (iree_status_is_ok(status)) { 39 | status = iree_hal_static_library_loader_create( 40 | IREE_ARRAYSIZE(libraries), libraries, 41 | iree_hal_executable_import_provider_null(), host_allocator, loader); 42 | } 43 | 44 | // Use the default host allocator for buffer allocations. 45 | iree_string_view_t identifier = iree_make_cstring_view("sync"); 46 | iree_hal_allocator_t* device_allocator = NULL; 47 | if (iree_status_is_ok(status)) { 48 | status = iree_hal_allocator_create_heap(identifier, host_allocator, 49 | host_allocator, &device_allocator); 50 | } 51 | 52 | // Create the device and release the executor and loader afterwards. 53 | if (iree_status_is_ok(status)) { 54 | status = iree_hal_sync_device_create( 55 | identifier, ¶ms, /*loader_count=*/1, loader, device_allocator, 56 | host_allocator, out_device); 57 | } 58 | 59 | iree_hal_allocator_release(device_allocator); 60 | return status; 61 | } 62 | -------------------------------------------------------------------------------- /cmake/springbok_ops.cmake: -------------------------------------------------------------------------------- 1 | # Add Compilation and Linker options based on iree/build_tools/cmake/iree_cops.cmake 2 | 3 | # Key compilation options 4 | iree_select_compiler_opts(IREE_DEFAULT_COPTS 5 | CLANG_OR_GCC 6 | "-fvisibility=hidden" 7 | 8 | # NOTE: The RTTI setting must match what LLVM was compiled with (defaults 9 | # to RTTI disabled). 10 | "$<$:-fno-rtti>" 11 | "$<$:-fno-exceptions>" 12 | ) 13 | 14 | # Compiler diagnostics. 15 | # Please keep these in sync with build_tools/bazel/iree.bazelrc 16 | iree_select_compiler_opts(IREE_DEFAULT_COPTS 17 | 18 | # Clang diagnostics. These largely match the set of warnings used within 19 | # Google. They have not been audited super carefully by the IREE team but are 20 | # generally thought to be a good set and consistency with those used 21 | # internally is very useful when importing. If you feel that some of these 22 | # should be different (especially more strict), please raise an issue! 23 | CLANG 24 | "-Werror" 25 | "-Wall" 26 | 27 | # Disable warnings we don't care about or that generally have a low 28 | # signal/noise ratio. 29 | "-Wno-ambiguous-member-template" 30 | "-Wno-char-subscripts" 31 | "-Wno-deprecated-declarations" 32 | "-Wno-extern-c-compat" # Matches upstream. Cannot impact due to extern C inclusion method. 33 | "-Wno-gnu-alignof-expression" 34 | "-Wno-gnu-variable-sized-type-not-at-end" 35 | "-Wno-ignored-optimization-argument" 36 | "-Wno-invalid-offsetof" # Technically UB but needed for intrusive ptrs 37 | "-Wno-invalid-source-encoding" 38 | "-Wno-mismatched-tags" 39 | "-Wno-pointer-sign" 40 | "-Wno-reserved-user-defined-literal" 41 | "-Wno-return-type-c-linkage" 42 | "-Wno-self-assign-overloaded" 43 | "-Wno-sign-compare" 44 | "-Wno-signed-unsigned-wchar" 45 | "-Wno-strict-overflow" 46 | "-Wno-trigraphs" 47 | "-Wno-unknown-pragmas" 48 | "-Wno-unknown-warning-option" 49 | "-Wno-unused-command-line-argument" 50 | "-Wno-unused-const-variable" 51 | "-Wno-unused-function" 52 | "-Wno-unused-local-typedef" 53 | "-Wno-unused-private-field" 54 | "-Wno-user-defined-warnings" 55 | 56 | # Explicitly enable some additional warnings. 57 | # Some of these aren't on by default, or under -Wall, or are subsets of 58 | # warnings turned off above. 59 | "-Wctad-maybe-unsupported" 60 | "-Wfloat-overflow-conversion" 61 | "-Wfloat-zero-conversion" 62 | "-Wfor-loop-analysis" 63 | "-Wformat-security" 64 | "-Wgnu-redeclared-enum" 65 | "-Wimplicit-fallthrough" 66 | "-Winfinite-recursion" 67 | "-Wliteral-conversion" 68 | "-Wnon-virtual-dtor" 69 | "-Woverloaded-virtual" 70 | "-Wself-assign" 71 | "-Wstring-conversion" 72 | "-Wtautological-overlap-compare" 73 | "-Wthread-safety" 74 | "-Wthread-safety-beta" 75 | "-Wunused-comparison" 76 | "-Wvla" 77 | ) 78 | 79 | 80 | iree_select_compiler_opts(IREE_DEFAULT_LINKOPTS 81 | CLANG_OR_GCC 82 | # Required by all modern software, effectively: 83 | "-lm" 84 | ) 85 | -------------------------------------------------------------------------------- /samples/quant_model/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #------------------------------------------------------------------------------- 16 | # Build the mlir bytecode modules with iree-compile. Note the last two flags 17 | # are for RVV support. 18 | #------------------------------------------------------------------------------- 19 | 20 | springbok_modules( 21 | NAME 22 | mobilenet_v1 23 | SRC 24 | "https://storage.googleapis.com/tfhub-lite-models/tensorflow/lite-model/mobilenet_v1_0.25_224_quantized/1/default/1.tflite" 25 | C_IDENTIFIER 26 | "samples_quant_model_mobilenet_v1" 27 | FLAGS 28 | "-iree-input-type=tosa" 29 | "-riscv-v-vector-bits-min=512" 30 | "-riscv-v-fixed-length-vector-lmul-max=8" 31 | ) 32 | 33 | #------------------------------------------------------------------------------- 34 | # Binaries to execute the IREE model input 35 | #------------------------------------------------------------------------------- 36 | 37 | iree_model_input( 38 | NAME 39 | mobilenet_quant_input 40 | SHAPE 41 | "1, 224, 224, 3" 42 | SRC 43 | "https://storage.googleapis.com/download.tensorflow.org/ \ 44 | example_images/YellowLabradorLooking_new.jpg" 45 | QUANT 46 | ) 47 | 48 | #------------------------------------------------------------------------------- 49 | # Binaries to execute the MLIR bytecode modules 50 | #------------------------------------------------------------------------------- 51 | 52 | 53 | # If the program requires a larger stack size, add 54 | # 55 | # LINKOPTS 56 | # "LINKER:--defsym=__stack_size__=" 57 | # 58 | # to increase it. 59 | 60 | iree_cc_binary( 61 | NAME 62 | mobilenet_v1_bytecode_static 63 | SRCS 64 | "mobilenet_v1.c" 65 | DEPS 66 | ::mobilenet_quant_input_c 67 | ::mobilenet_v1_bytecode_module_static_c 68 | ::mobilenet_v1_bytecode_module_static_lib 69 | iree::vm::bytecode_module 70 | samples::util::util_static 71 | LINKOPTS 72 | "LINKER:--defsym=__itcm_length__=1M" 73 | "LINKER:--defsym=__stack_size__=300k" 74 | ) 75 | 76 | iree_cc_binary( 77 | NAME 78 | mobilenet_v1_emitc_static 79 | SRCS 80 | "mobilenet_v1.c" 81 | DEPS 82 | ::mobilenet_quant_input_c 83 | ::mobilenet_v1_c_module_static_emitc 84 | ::mobilenet_v1_c_module_static_lib 85 | samples::util::util_static 86 | LINKOPTS 87 | "LINKER:--defsym=__itcm_length__=1M" 88 | "LINKER:--defsym=__stack_size__=300k" 89 | COPTS 90 | "-DBUILD_EMITC" 91 | ) 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RISC-V 32-Bit Bare-Metal ML Deployment on Springbok via IREE 2 | 3 | This project demonstrates how to compile RISC-V 32-bit ML workloads via 4 | [IREE](https://github.com/google/iree), and deploy the workloads with IREE's c 5 | API to generate the bare-matal executables. The built artifacts are targeted for 6 | Springbok, a RISC-V 32-bit bare-metal platform, and can be simulated with 7 | [Renode](https://github.com/renode/renode). 8 | 9 | ## Prerequisites 10 | 11 | First install the system packages: 12 | 13 | ```bash 14 | sudo apt install xxd cmake ninja-build wget 15 | pip install -r python-requirements.txt 16 | ``` 17 | 18 | **NOTE**: IREE requires CMake >= 3.17. If your system's default cmake is in an 19 | older version, please update it manually. 20 | 21 | To get you going we have pre-compiled an RV32 LLVM toolchain. This can be installed using: 22 | 23 | ```bash 24 | ./build_tools/install_toolchain.sh 25 | ``` 26 | 27 | The IREE compiler can be downloaded using: 28 | 29 | ```bash 30 | ./build_tools/download_iree_compiler.py 31 | ``` 32 | 33 | Finally Renode can be downloaded using: 34 | 35 | ```bash 36 | ./build_tools/download_renode.py 37 | ``` 38 | 39 | Make sure your `${HOME}/.local/bin` is in your PATH: 40 | 41 | ```bash 42 | export PATH=${HOME}/.local/bin:${PATH} 43 | ``` 44 | 45 | **NOTE**: If your python packages are installed with the virtual environment, 46 | please set PATH accordingly. 47 | 48 | ## Code structure 49 | 50 | * build_tools: Utility scripts for the project 51 | * cmake: CMake Macros for the project 52 | * samples: Codegen and execution of ML models based on IREE 53 | * device: Device HAL driver library 54 | * float_model: float model examples 55 | * quant_model: quantized model examples 56 | * simple_vec_mul: Point-wise vector multiplication examples 57 | * util: Runtime utility library for model execution 58 | * sim/config: Renode configuration and infrastructure 59 | * springbok: Low-level code and linker scripts for the Springbok machine 60 | * third_party/iree: IREE codebase 61 | 62 | ## Build the project 63 | 64 | All sample models we've included can be built at once using this command: 65 | 66 | ```bash 67 | ./build_tools/build_riscv.sh 68 | ``` 69 | 70 | Elfs will land in `build/build-riscv/samples//` and come in two flavors: `_bytecode_static` and `_emitc_static`. The bytecode executable uses the IREE VM, while the emitc executable compiles the VM commands into C. 71 | 72 | ## Run the executables 73 | 74 | To run a simulation, run `./build_tools/sim_springbok.sh` with a path to a compiled executable. For example, to run MobileNet v1: 75 | 76 | ```bash 77 | ./build_tools/sim_springbok.sh build/build-riscv/samples/quant_model/mobilenet_v1_emitc_static 78 | ``` 79 | 80 | ## Test the executables 81 | 82 | This project utilizes LLVM `lit` and `FileCheck` to test the ML 83 | executable performance. The tests are defined in the *_test.txt files under 84 | `samples`. To run the tests: 85 | 86 | ```bash 87 | lit --path $(realpath build/iree_compiler/tests/bin) -a samples 88 | ``` 89 | 90 | Test times can be found at `build/springbok_iree/tests/.lit_test_times.txt`. 91 | -------------------------------------------------------------------------------- /samples/float_model/mnist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // mnist float model 18 | // MlModel struct initialization to include model I/O info. 19 | // Bytecode loading, input/output processes. 20 | 21 | #include "mnist.h" 22 | 23 | #include 24 | 25 | // Compiled module embedded here to avoid file IO: 26 | #if !defined(BUILD_EMITC) 27 | #include "samples/float_model/mnist_bytecode_module_static.h" 28 | #include "samples/float_model/mnist_bytecode_module_static_c.h" 29 | #else 30 | #include "samples/float_model/mnist_c_module_static_c.h" 31 | #include "samples/float_model/mnist_c_module_static_emitc.h" 32 | #endif 33 | #include "samples/float_model/mnist_input_c.h" 34 | 35 | MnistOutput score; 36 | 37 | iree_status_t create_module(iree_vm_instance_t *instance, 38 | iree_vm_module_t **module) { 39 | #if !defined(BUILD_EMITC) 40 | const struct iree_file_toc_t *module_file_toc = 41 | samples_float_model_mnist_bytecode_module_static_create(); 42 | return iree_vm_bytecode_module_create( 43 | instance, 44 | iree_make_const_byte_span(module_file_toc->data, module_file_toc->size), 45 | iree_allocator_null(), iree_allocator_system(), module); 46 | #else 47 | return module_create(instance, iree_allocator_system(), module); 48 | #endif 49 | } 50 | 51 | iree_hal_executable_library_query_fn_t library_query(void) { 52 | return &mnist_linked_llvm_cpu_library_query; 53 | } 54 | 55 | iree_status_t load_input_data(const MlModel *model, void **buffer, 56 | iree_const_byte_span_t **byte_span) { 57 | byte_span[0] = malloc(sizeof(iree_const_byte_span_t)); 58 | *byte_span[0] = iree_make_const_byte_span( 59 | mnist_input, model->input_size_bytes[0] * model->input_length[0]); 60 | return iree_ok_status(); 61 | } 62 | 63 | iree_status_t process_output(const MlModel *model, 64 | iree_hal_buffer_mapping_t *buffers, 65 | uint32_t *output_length) { 66 | iree_status_t result = iree_ok_status(); 67 | // find the label index with best prediction 68 | float best_out = 0.0; 69 | int best_idx = -1; 70 | for (int i = 0; i < model->output_length[0]; ++i) { 71 | float out = ((float *)buffers[0].contents.data)[i]; 72 | if (out > best_out) { 73 | best_out = out; 74 | best_idx = i; 75 | } 76 | } 77 | 78 | score.best_out = best_out; 79 | score.best_idx = best_idx; 80 | 81 | LOG_INFO("Digit recognition result is: digit: %d", best_idx); 82 | 83 | *output_length = sizeof(score); 84 | return result; 85 | } 86 | -------------------------------------------------------------------------------- /samples/float_model/mobilenet_v1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Mobilenet_v1_0.25_224 float model 18 | // MlModel struct initialization to include model I/O info. 19 | // Bytecode loading, input/output processes. 20 | 21 | #include "mobilenet_v1.h" 22 | 23 | #include 24 | 25 | // Compiled module embedded here to avoid file IO: 26 | #include "samples/float_model/mobilenet_input_c.h" 27 | #if !defined(BUILD_EMITC) 28 | #include "samples/float_model/mobilenet_v1_bytecode_module_static.h" 29 | #include "samples/float_model/mobilenet_v1_bytecode_module_static_c.h" 30 | #else 31 | #include "samples/float_model/mobilenet_v1_c_module_static_c.h" 32 | #include "samples/float_model/mobilenet_v1_c_module_static_emitc.h" 33 | #endif 34 | 35 | MobilenetV1Output score; 36 | 37 | iree_status_t create_module(iree_vm_instance_t *instance, 38 | iree_vm_module_t **module) { 39 | #if !defined(BUILD_EMITC) 40 | const struct iree_file_toc_t *module_file_toc = 41 | samples_float_model_mobilenet_v1_bytecode_module_static_create(); 42 | return iree_vm_bytecode_module_create( 43 | instance, 44 | iree_make_const_byte_span(module_file_toc->data, module_file_toc->size), 45 | iree_allocator_null(), iree_allocator_system(), module); 46 | #else 47 | return module_create(instance, iree_allocator_system(), module); 48 | #endif 49 | } 50 | 51 | iree_hal_executable_library_query_fn_t library_query(void) { 52 | return &mobilenet_v1_linked_llvm_cpu_library_query; 53 | } 54 | 55 | iree_status_t load_input_data(const MlModel *model, void **buffer, 56 | iree_const_byte_span_t **byte_span) { 57 | byte_span[0] = malloc(sizeof(iree_const_byte_span_t)); 58 | *byte_span[0] = iree_make_const_byte_span( 59 | mobilenet_input, model->input_size_bytes[0] * model->input_length[0]); 60 | return iree_ok_status(); 61 | } 62 | 63 | iree_status_t process_output(const MlModel *model, 64 | iree_hal_buffer_mapping_t *buffers, 65 | uint32_t *output_length) { 66 | iree_status_t result = iree_ok_status(); 67 | // find the label index with best prediction 68 | float best_out = 0.0; 69 | int best_idx = -1; 70 | for (int i = 0; i < model->output_length[0]; ++i) { 71 | float out = ((float *)buffers[0].contents.data)[i]; 72 | if (out > best_out) { 73 | best_out = out; 74 | best_idx = i; 75 | } 76 | } 77 | score.best_out = best_out; 78 | score.best_idx = best_idx; 79 | 80 | LOG_INFO("Image prediction result is: id: %d", best_idx + 1); 81 | 82 | *output_length = sizeof(score); 83 | return result; 84 | } 85 | -------------------------------------------------------------------------------- /samples/quant_model/mobilenet_v1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Mobilenet_v1_0.25_224 quant model 18 | // MlModel struct initialization to include model I/O info. 19 | // Bytecode loading, input/output processes. 20 | 21 | #include "mobilenet_v1.h" 22 | 23 | #include 24 | 25 | // Compiled module embedded here to avoid file IO: 26 | #include "samples/quant_model/mobilenet_quant_input_c.h" 27 | #if !defined(BUILD_EMITC) 28 | #include "samples/quant_model/mobilenet_v1_bytecode_module_static.h" 29 | #include "samples/quant_model/mobilenet_v1_bytecode_module_static_c.h" 30 | #else 31 | #include "samples/quant_model/mobilenet_v1_c_module_static_c.h" 32 | #include "samples/quant_model/mobilenet_v1_c_module_static_emitc.h" 33 | #endif 34 | 35 | MobilenetV1Output score; 36 | 37 | iree_status_t create_module(iree_vm_instance_t *instance, 38 | iree_vm_module_t **module) { 39 | #if !defined(BUILD_EMITC) 40 | const struct iree_file_toc_t *module_file_toc = 41 | samples_quant_model_mobilenet_v1_bytecode_module_static_create(); 42 | return iree_vm_bytecode_module_create( 43 | instance, 44 | iree_make_const_byte_span(module_file_toc->data, module_file_toc->size), 45 | iree_allocator_null(), iree_allocator_system(), module); 46 | #else 47 | return module_create(instance, iree_allocator_system(), module); 48 | #endif 49 | } 50 | 51 | iree_hal_executable_library_query_fn_t library_query(void) { 52 | return &mobilenet_v1_linked_llvm_cpu_library_query; 53 | } 54 | 55 | iree_status_t load_input_data(const MlModel *model, void **buffer, 56 | iree_const_byte_span_t **byte_span) { 57 | byte_span[0] = malloc(sizeof(iree_const_byte_span_t)); 58 | *byte_span[0] = iree_make_const_byte_span( 59 | mobilenet_quant_input, 60 | model->input_size_bytes[0] * model->input_length[0]); 61 | return iree_ok_status(); 62 | } 63 | 64 | iree_status_t process_output(const MlModel *model, 65 | iree_hal_buffer_mapping_t *buffers, 66 | uint32_t *output_length) { 67 | iree_status_t result = iree_ok_status(); 68 | // find the label index with best prediction 69 | int best_out = 0; 70 | int best_idx = -1; 71 | for (int i = 0; i < model->output_length[0]; ++i) { 72 | uint8_t out = ((uint8_t *)buffers[0].contents.data)[i]; 73 | if (out > best_out) { 74 | best_out = out; 75 | best_idx = i; 76 | } 77 | } 78 | score.best_out = best_out; 79 | score.best_idx = best_idx; 80 | 81 | LOG_INFO("Image prediction result is: id: %d", best_idx + 1); 82 | 83 | *output_length = sizeof(score); 84 | return result; 85 | } 86 | -------------------------------------------------------------------------------- /springbok/springbok.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | ITCM_LENGTH = DEFINED(__itcm_length__) ? __itcm_length__ : 64K; 18 | DTCM_LENGTH = DEFINED(__dtcm_length__) ? __dtcm_length__ : 4M; 19 | 20 | 21 | MEMORY 22 | { 23 | ITCM (rx) : ORIGIN = 0x32000000, LENGTH = ITCM_LENGTH 24 | DTCM (rw) : ORIGIN = 0x34000000, LENGTH = DTCM_LENGTH 25 | } 26 | 27 | STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0x2000; 28 | PROVIDE( _stack_ptr = ORIGIN(DTCM) + LENGTH(DTCM) - 64 ); 29 | PROVIDE( _stack_start_sentinel = ORIGIN(DTCM) + LENGTH(DTCM) - STACK_SIZE ); 30 | PROVIDE( _stack_end_sentinel = ORIGIN(DTCM) + LENGTH(DTCM) - 64 ); 31 | 32 | ENTRY(_start) 33 | 34 | SECTIONS 35 | { 36 | .text : 37 | { 38 | _stext = .; 39 | KEEP(*(.text._start)) 40 | *(.text*) 41 | _etext = .; 42 | } > ITCM 43 | 44 | .rodata : 45 | { 46 | . = ALIGN(64); 47 | _srodata = .; 48 | *(.rodata*) 49 | _erodata = .; 50 | } > DTCM 51 | 52 | .preinit_array : 53 | { 54 | PROVIDE(__preinit_array_start = .); 55 | KEEP(*(.preinit_array)) 56 | PROVIDE(__preinit_array_end = .); 57 | } > DTCM 58 | 59 | .init_array : 60 | { 61 | PROVIDE(__init_array_start = .); 62 | KEEP(*(SORT(.init_array.*))) 63 | KEEP(*(.init_array)) 64 | PROVIDE(__init_array_end = .); 65 | } > DTCM 66 | 67 | .fini_array : 68 | { 69 | PROVIDE(__fini_array_start = .); 70 | KEEP(*(SORT(.fini_array.*))) 71 | KEEP(*(.fini_array)) 72 | PROVIDE(__fini_array_end = .); 73 | } > DTCM 74 | 75 | .data : 76 | { 77 | . = ALIGN(64); 78 | _global_pointer = . + 0x800; 79 | _sdata = .; 80 | *(.data*) 81 | _edata = .; 82 | } > DTCM 83 | 84 | .bss (NOLOAD) : 85 | { 86 | . = ALIGN(64); 87 | _sbss = .; 88 | *(.bss*) 89 | *(COMMON) 90 | _ebss = .; 91 | } > DTCM 92 | 93 | .heap (NOLOAD) : 94 | { 95 | . = ALIGN(64); 96 | _sheap = .; 97 | . = ORIGIN(DTCM) + LENGTH(DTCM) - STACK_SIZE - 63; 98 | . = ALIGN(64); 99 | _eheap = .; 100 | } > DTCM 101 | 102 | .stack ORIGIN(DTCM) + LENGTH(DTCM) - STACK_SIZE (NOLOAD) : 103 | { 104 | _sstack = .; 105 | . = . + STACK_SIZE; 106 | . = ALIGN(64); 107 | _estack = .; 108 | } > DTCM 109 | 110 | _end = .; 111 | } 112 | -------------------------------------------------------------------------------- /cmake/riscv_iree.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required (VERSION 3.13) 16 | 17 | # CMake invokes the toolchain file twice during the first build, but only once 18 | # during subsequent rebuilds. This was causing the various flags to be added 19 | # twice on the first build, and on a rebuild ninja would see only one set of the 20 | # flags and rebuild the world. 21 | # https://github.com/android-ndk/ndk/issues/323 22 | if(RISCV_TOOLCHAIN_INCLUDED) 23 | return() 24 | endif(RISCV_TOOLCHAIN_INCLUDED) 25 | set(RISCV_TOOLCHAIN_INCLUDED true) 26 | 27 | set(CMAKE_SYSTEM_PROCESSOR riscv) 28 | set(CMAKE_CROSSCOMPILING ON CACHE BOOL "") 29 | 30 | if(CMAKE_HOST_SYSTEM_NAME STREQUAL Linux) 31 | set(RISCV_HOST_TAG linux) 32 | elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL Darwin) 33 | set(RISCV_HOST_TAG darwin) 34 | endif() 35 | 36 | set(RISCV_TOOLCHAIN_NAME clang) 37 | 38 | set(RISCV_TOOLCHAIN_ROOT "build/toolchain/toolchain_iree_rv32imf" CACHE PATH "RISC-V compiler path") 39 | set(CMAKE_FIND_ROOT_PATH ${RISCV_TOOLCHAIN_ROOT}) 40 | list(APPEND CMAKE_PREFIX_PATH "${RISCV_TOOLCHAIN_ROOT}") 41 | 42 | set(CMAKE_C_COMPILER "${RISCV_TOOLCHAIN_ROOT}/bin/clang") 43 | set(CMAKE_CXX_COMPILER "${RISCV_TOOLCHAIN_ROOT}/bin/clang++") 44 | set(CMAKE_AR "${RISCV_TOOLCHAIN_ROOT}/bin/llvm-ar") 45 | set(CMAKE_RANLIB "${RISCV_TOOLCHAIN_ROOT}/bin/llvm-ranlib") 46 | set(CMAKE_STRIP "${RISCV_TOOLCHAIN_ROOT}/bin/llvm-strip") 47 | 48 | set(RISCV_COMPILER_FLAGS "" CACHE STRING "RISC-V compiler flags for C, CXX, and ASM") 49 | set(RISCV_COMPILER_FLAGS_CXX) 50 | set(RISCV_COMPILER_FLAGS_DEBUG) 51 | set(RISCV_COMPILER_FLAGS_RELEASE) 52 | set(RISCV_LINKER_FLAGS) 53 | set(RISCV_LINKER_FLAGS_EXE) 54 | 55 | set(CMAKE_SYSTEM_NAME Generic) 56 | set(CMAKE_C_STANDARD 11) 57 | set(CMAKE_C_EXTENSIONS OFF) # Force the usage of _ISOC11_SOURCE 58 | set(CMAKE_SYSTEM_LIBRARY_PATH "${RISCV_TOOLCHAIN_ROOT}/riscv32-unknown-elf/lib") 59 | set(RISCV_COMPILER_FLAGS "${RISCV_COMPILER_FLAGS} -menable-experimental-extensions -march=rv32imf_zvl512b_zve32x -mabi=ilp32") 60 | 61 | set(CMAKE_C_FLAGS "${RISCV_COMPILER_FLAGS} ${CMAKE_C_FLAGS}") 62 | set(CMAKE_CXX_FLAGS "${RISCV_COMPILER_FLAGS} ${RISCV_COMPILER_FLAGS_CXX} ${CMAKE_CXX_FLAGS}") 63 | set(CMAKE_ASM_FLAGS "${RISCV_COMPILER_FLAGS} ${CMAKE_ASM_FLAGS}") 64 | set(CMAKE_C_FLAGS_DEBUG "${RISCV_COMPILER_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}") 65 | set(CMAKE_CXX_FLAGS_DEBUG "${RISCV_COMPILER_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}") 66 | set(CMAKE_ASM_FLAGS_DEBUG "${RISCV_COMPILER_FLAGS_DEBUG} ${CMAKE_ASM_FLAGS_DEBUG}") 67 | set(CMAKE_C_FLAGS_RELEASE "${RISCV_COMPILER_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}") 68 | set(CMAKE_CXX_FLAGS_RELEASE "${RISCV_COMPILER_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}") 69 | set(CMAKE_ASM_FLAGS_RELEASE "${RISCV_COMPILER_FLAGS_RELEASE} ${CMAKE_ASM_FLAGS_RELEASE}") 70 | set(CMAKE_SHARED_LINKER_FLAGS "${RISCV_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}") 71 | set(CMAKE_MODULE_LINKER_FLAGS "${RISCV_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}") 72 | set(CMAKE_EXE_LINKER_FLAGS "${RISCV_LINKER_FLAGS} ${RISCV_LINKER_FLAGS_EXE} ${CMAKE_EXE_LINKER_FLAGS}") 73 | -------------------------------------------------------------------------------- /springbok/springbok_gloss.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | void* __dso_handle = (void*) &__dso_handle; 24 | 25 | extern "C" void *_sbrk(int nbytes) { 26 | extern char _sheap, _eheap; 27 | static char *_heap_ptr = &_sheap; 28 | 29 | if ((nbytes < 0) || 30 | (_heap_ptr + nbytes > &_eheap)) { 31 | springbok_simprint(SPRINGBOK_SIMPRINT_ERROR, "_sbrk failed to allocate memory. Number of bytes requested:", nbytes); 32 | springbok_simprint(SPRINGBOK_SIMPRINT_ERROR, "Number of unallocated bytes remaining:", static_cast(&_eheap - _heap_ptr)); 33 | errno = ENOMEM; 34 | return (void *)-1; 35 | } 36 | 37 | void *base = _heap_ptr; 38 | _heap_ptr += nbytes; 39 | return base; 40 | } 41 | 42 | extern "C" int _read(int file, char *ptr, int len) { 43 | if (file != STDIN_FILENO) { 44 | errno = EBADF; 45 | return -1; 46 | } 47 | 48 | return 0; 49 | } 50 | 51 | extern "C" int _write(int file, char *buf, int nbytes) { 52 | static int _write_line_buffer_len[2] = {0, 0}; 53 | static char _write_line_buffer[2][256]; 54 | 55 | if (file != STDOUT_FILENO && file != STDERR_FILENO) { 56 | errno = EBADF; 57 | return -1; 58 | } 59 | 60 | if (nbytes <= 0) { 61 | return 0; 62 | } 63 | 64 | if (buf == NULL) { 65 | errno = EFAULT; 66 | return -1; 67 | } 68 | 69 | const int buffer_num = (file == STDOUT_FILENO)? 0 : 1; 70 | const int buffer_level = (file == STDOUT_FILENO)? SPRINGBOK_SIMPRINT_INFO : SPRINGBOK_SIMPRINT_ERROR; 71 | 72 | int bytes_read = 0; 73 | char c; 74 | do { 75 | int len = _write_line_buffer_len[buffer_num]; 76 | c = *(buf++); 77 | bytes_read++; 78 | 79 | if ((c == '\n') || (c == '\0')) { 80 | _write_line_buffer[buffer_num][len] = '\0'; 81 | springbok_simprint(buffer_level, _write_line_buffer[buffer_num], buffer_num); 82 | len = 0; 83 | } else { 84 | _write_line_buffer[buffer_num][len] = c; 85 | len++; 86 | 87 | if (len == 255) { 88 | _write_line_buffer[buffer_num][len] = '\0'; 89 | springbok_simprint(buffer_level, _write_line_buffer[buffer_num], buffer_num); 90 | len = 0; 91 | } 92 | } 93 | 94 | _write_line_buffer_len[buffer_num] = len; 95 | } while (bytes_read < nbytes); 96 | 97 | return bytes_read; 98 | } 99 | 100 | extern "C" int _close(int file) { 101 | errno = EBADF; 102 | return -1; 103 | } 104 | 105 | extern "C" int _lseek(int file, int offset, int whence) { 106 | if (file != STDOUT_FILENO && file != STDERR_FILENO) { 107 | errno = EBADF; 108 | return -1; 109 | } 110 | 111 | return 0; 112 | } 113 | 114 | extern "C" int _fstat(int file, struct stat *st) { 115 | if (file != STDOUT_FILENO && file != STDERR_FILENO) { 116 | errno = EBADF; 117 | return -1; 118 | } 119 | 120 | if (st == NULL) { 121 | errno = EFAULT; 122 | return -1; 123 | } 124 | 125 | st->st_mode = S_IFCHR; 126 | return 0; 127 | } 128 | 129 | extern "C" int _isatty(int file) { 130 | if (file != STDOUT_FILENO && file != STDERR_FILENO) { 131 | errno = EBADF; 132 | return -1; 133 | } 134 | 135 | return 1; 136 | } 137 | 138 | void operator delete(void *p) noexcept { 139 | free(p); 140 | } 141 | 142 | extern "C" void operator delete(void *p, unsigned long c) noexcept { 143 | operator delete(p); 144 | } 145 | -------------------------------------------------------------------------------- /cmake/iree_model_input.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | include(CMakeParseArguments) 16 | 17 | # iree_model_input() 18 | # 19 | # CMake function to load an external model input (an image) 20 | # and convert to the iree_c_embed_data. 21 | # 22 | # Parameters: 23 | # NAME: Name of model input image. 24 | # SHAPE: Input shape. 25 | # SRC: Input image URL. 26 | # QUANT: When added, indicate it's a quant model. 27 | # 28 | # Examples: 29 | # iree_model_input( 30 | # NAME 31 | # mobilenet_quant_input 32 | # SHAPE 33 | # "1, 224, 224, 3" 34 | # SRC 35 | # "https://storage.googleapis.com/download.tensorflow.org/ \ 36 | # example_images/YellowLabradorLooking_new.jpg" 37 | # QUANT 38 | # ) 39 | # 40 | function(iree_model_input) 41 | cmake_parse_arguments( 42 | _RULE 43 | "QUANT" 44 | "NAME;SHAPE;SRC;RANGE" 45 | "" 46 | ${ARGN} 47 | ) 48 | 49 | string(REGEX REPLACE "[ \t\r\n]" "" _RULE_SRC_TRIM ${_RULE_SRC}) 50 | string(REGEX MATCH "^https:" _RULE_SRC_URL ${_RULE_SRC_TRIM}) 51 | if (_RULE_SRC_URL) 52 | get_filename_component(_INPUT_FILENAME "${_RULE_SRC}" NAME) 53 | find_program(_WGET wget HINT "$ENV{PATH}" REQUIRED) 54 | add_custom_command( 55 | OUTPUT 56 | ${_INPUT_FILENAME} 57 | COMMAND 58 | ${_WGET} -q -P "${CMAKE_CURRENT_BINARY_DIR}" -O "${_INPUT_FILENAME}" 59 | "${_RULE_SRC_TRIM}" 60 | COMMENT 61 | "Download ${_INPUT_FILENAME} from ${_RULE_SRC_TRIM}" 62 | ) 63 | else() 64 | set(_INPUT_FILENAME ${_RULE_SRC_TRIM}) 65 | endif() 66 | 67 | set(_GEN_INPUT_SCRIPT "${CMAKE_SOURCE_DIR}/build_tools/gen_mlmodel_input.py") 68 | set(_OUTPUT_BINARY ${_RULE_NAME}) 69 | set(_ARGS) 70 | list(APPEND _ARGS "--i=${_INPUT_FILENAME}") 71 | list(APPEND _ARGS "--o=${_OUTPUT_BINARY}") 72 | list(APPEND _ARGS "--s=${_RULE_SHAPE}") 73 | if(_RULE_RANGE) 74 | list(APPEND _ARGS "--r=${_RULE_RANGE}") 75 | endif() 76 | if(_RULE_QUANT) 77 | list(APPEND _ARGS "--q") 78 | endif() 79 | 80 | # Replace dependencies passed by ::name with iree::package::name 81 | iree_package_ns(_PACKAGE_NS) 82 | list(TRANSFORM _RULE_DEPS REPLACE "^::" "${_PACKAGE_NS}::") 83 | 84 | # Prefix the library with the package name, so we get: iree_package_name. 85 | iree_package_name(_PACKAGE_NAME) 86 | 87 | set(_RULE_C_NAME "${_RULE_NAME}_c") 88 | set(_LIB_NAME "${_PACKAGE_NAME}_${_RULE_C_NAME}") 89 | set(_GEN_TARGET "${_LIB_NAME}_gen") 90 | set(_H_FILE_NAME ${_RULE_C_NAME}.h) 91 | 92 | add_custom_command( 93 | OUTPUT 94 | ${_OUTPUT_BINARY} 95 | ${_H_FILE_NAME} 96 | COMMAND 97 | ${_GEN_INPUT_SCRIPT} ${_ARGS} 98 | COMMAND 99 | xxd -i ${_OUTPUT_BINARY} > ${_H_FILE_NAME} 100 | DEPENDS 101 | ${_GEN_INPUT_SCRIPT} 102 | ${_INPUT_FILENAME} 103 | ) 104 | 105 | add_custom_target( 106 | ${_GEN_TARGET} 107 | DEPENDS 108 | "${_H_FILE_NAME}" 109 | ) 110 | 111 | add_library(${_LIB_NAME} 112 | ${_H_FILE_NAME} 113 | ) 114 | add_dependencies(${_LIB_NAME} ${_GEN_TARGET}) 115 | 116 | SET_TARGET_PROPERTIES( 117 | ${_LIB_NAME} 118 | PROPERTIES 119 | LINKER_LANGUAGE C 120 | ) 121 | 122 | # Alias the iree_package_name library to iree::package::name. 123 | # This lets us more clearly map to Bazel and makes it possible to 124 | # disambiguate the underscores in paths vs. the separators. 125 | add_library(${_PACKAGE_NS}::${_RULE_C_NAME} ALIAS ${_LIB_NAME}) 126 | iree_package_dir(_PACKAGE_DIR) 127 | if(${_RULE_C_NAME} STREQUAL ${_PACKAGE_DIR}) 128 | add_library(${_PACKAGE_NS} ALIAS ${_LIB_NAME}) 129 | endif() 130 | endfunction() 131 | -------------------------------------------------------------------------------- /samples/float_model/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #------------------------------------------------------------------------------- 16 | # Build the mlir bytecode modules with iree-compile. 17 | #------------------------------------------------------------------------------- 18 | 19 | springbok_modules( 20 | NAME 21 | mobilenet_v1 22 | SRC 23 | "https://storage.googleapis.com/tfhub-lite-models/tensorflow/lite-model/mobilenet_v1_0.25_224/1/default/1.tflite" 24 | C_IDENTIFIER 25 | "samples_float_model_mobilenet_v1" 26 | FLAGS 27 | "-iree-input-type=tosa" 28 | ) 29 | 30 | springbok_modules( 31 | NAME 32 | mnist 33 | SRC 34 | "${CMAKE_SOURCE_DIR}/third_party/iree/samples/models/mnist.mlir" 35 | C_IDENTIFIER 36 | "samples_float_model_mnist" 37 | FLAGS 38 | "-iree-input-type=mhlo" 39 | ) 40 | 41 | #------------------------------------------------------------------------------- 42 | # Binaries to execute the IREE model input 43 | #------------------------------------------------------------------------------- 44 | 45 | iree_model_input( 46 | NAME 47 | mobilenet_input 48 | SHAPE 49 | "1, 224, 224, 3" 50 | SRC 51 | "https://storage.googleapis.com/download.tensorflow.org/ \ 52 | example_images/YellowLabradorLooking_new.jpg" 53 | ) 54 | 55 | iree_model_input( 56 | NAME 57 | mnist_input 58 | SHAPE 59 | "1, 28, 28, 1" 60 | SRC 61 | "https://github.com/google/iree/raw/ \ 62 | 1e8d1fa96057c47d1fda918f3a2f71f14b073937/samples/iree_vision_inference/mnist_test.png" 63 | RANGE 64 | "0, 1" 65 | ) 66 | 67 | #------------------------------------------------------------------------------- 68 | # Binaries to execute the MLIR bytecode modules 69 | #------------------------------------------------------------------------------- 70 | 71 | 72 | # If the program requires a larger stack size, add 73 | # 74 | # LINKOPTS 75 | # "LINKER:--defsym=__stack_size__=" 76 | # 77 | # to increase it. 78 | 79 | iree_cc_binary( 80 | NAME 81 | mobilenet_v1_bytecode_static 82 | SRCS 83 | "mobilenet_v1.c" 84 | DEPS 85 | ::mobilenet_input_c 86 | ::mobilenet_v1_bytecode_module_static_c 87 | ::mobilenet_v1_bytecode_module_static_lib 88 | iree::vm::bytecode_module 89 | samples::util::util_static 90 | LINKOPTS 91 | "LINKER:--defsym=__itcm_length__=1M" 92 | "LINKER:--defsym=__stack_size__=200k" 93 | ) 94 | 95 | iree_cc_binary( 96 | NAME 97 | mobilenet_v1_emitc_static 98 | SRCS 99 | "mobilenet_v1.c" 100 | DEPS 101 | ::mobilenet_input_c 102 | ::mobilenet_v1_c_module_static_emitc 103 | ::mobilenet_v1_c_module_static_lib 104 | samples::util::util_static 105 | LINKOPTS 106 | "LINKER:--defsym=__itcm_length__=1M" 107 | "LINKER:--defsym=__stack_size__=200k" 108 | COPTS 109 | "-DBUILD_EMITC" 110 | ) 111 | 112 | iree_cc_binary( 113 | NAME 114 | mnist_bytecode_static 115 | SRCS 116 | "mnist.c" 117 | DEPS 118 | ::mnist_bytecode_module_static_c 119 | ::mnist_bytecode_module_static_lib 120 | ::mnist_input_c 121 | iree::vm::bytecode_module 122 | samples::util::util_static 123 | LINKOPTS 124 | "LINKER:--defsym=__stack_size__=100k" 125 | ) 126 | 127 | iree_cc_binary( 128 | NAME 129 | mnist_emitc_static 130 | SRCS 131 | "mnist.c" 132 | DEPS 133 | ::mnist_c_module_static_emitc 134 | ::mnist_c_module_static_lib 135 | ::mnist_input_c 136 | samples::util::util_static 137 | "m" 138 | LINKOPTS 139 | "LINKER:--defsym=__stack_size__=100k" 140 | COPTS 141 | "-DBUILD_EMITC" 142 | ) 143 | -------------------------------------------------------------------------------- /samples/simple_vec_mul/int_vec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Integer simple_mul bytecode loading and input/output processes 18 | 19 | #include "samples/util/util.h" 20 | 21 | // Compiled module embedded here to avoid file IO: 22 | #if defined(BUILD_VMVX) 23 | #if !defined(BUILD_EMITC) 24 | #include "samples/simple_vec_mul/simple_int_mul_bytecode_module_vmvx_c.h" 25 | #else 26 | #include "samples/simple_vec_mul/simple_int_mul_c_module_vmvx_emitc.h" 27 | #endif // !defined(BUILD_EMITC) 28 | #else 29 | #if !defined(BUILD_EMITC) 30 | #include "samples/simple_vec_mul/simple_int_mul_bytecode_module_static.h" 31 | #include "samples/simple_vec_mul/simple_int_mul_bytecode_module_static_c.h" 32 | #else 33 | #include "samples/simple_vec_mul/simple_int_mul_c_module_static_c.h" 34 | #include "samples/simple_vec_mul/simple_int_mul_c_module_static_emitc.h" 35 | #endif // !defined(BUILD_EMITC) 36 | #endif // defined(BUILD_VMVX) 37 | 38 | const MlModel kModel = { 39 | .num_input = 2, 40 | .num_input_dim = {1, 1}, 41 | .input_shape = {{1024}, {1024}}, 42 | .input_length = {1024, 1024}, 43 | .input_size_bytes = {sizeof(int32_t), sizeof(int32_t)}, 44 | .num_output = 1, 45 | .output_length = {1024}, 46 | .output_size_bytes = sizeof(int32_t), 47 | .hal_element_type = IREE_HAL_ELEMENT_TYPE_SINT_32, 48 | .entry_func = "module.simple_mul", 49 | .model_name = "simple_int_vec_mul", 50 | }; 51 | 52 | iree_status_t create_module(iree_vm_instance_t *instance, 53 | iree_vm_module_t **module) { 54 | #if !defined(BUILD_EMITC) 55 | #if defined(BUILD_VMVX) 56 | const struct iree_file_toc_t *module_file_toc = 57 | samples_simple_vec_mul_simple_int_mul_bytecode_module_vmvx_create(); 58 | #else 59 | const struct iree_file_toc_t *module_file_toc = 60 | samples_simple_vec_mul_simple_int_mul_bytecode_module_static_create(); 61 | #endif // #if defined(BUILD_VMVX) 62 | return iree_vm_bytecode_module_create( 63 | instance, 64 | iree_make_const_byte_span(module_file_toc->data, module_file_toc->size), 65 | iree_allocator_null(), iree_allocator_system(), module); 66 | #else 67 | return module_create(instance, iree_allocator_system(), module); 68 | #endif // #if !defined(BUILD_EMITC) 69 | } 70 | 71 | #if !defined(BUILD_VMVX) 72 | iree_hal_executable_library_query_fn_t library_query(void) { 73 | return &simple_mul_dispatch_0_library_query; 74 | } 75 | #endif // #if !defined(BUILD_VMVX) 76 | 77 | iree_status_t load_input_data(const MlModel *model, void **buffer, 78 | iree_const_byte_span_t **byte_span) { 79 | iree_status_t result = alloc_input_buffer(model, buffer); 80 | // Populate initial values 81 | // arg0 = 0, 0, 1, 1,..., 511 82 | // arg1 = 0, 1, 2, 3,..., 1023 83 | if (iree_status_is_ok(result)) { 84 | for (int i = 0; i < model->input_length[0]; ++i) { 85 | ((int32_t *)buffer[0])[i] = i >> 1; 86 | ((int32_t *)buffer[1])[i] = i; 87 | } 88 | } 89 | for (int i = 0; i < model->num_input; ++i) { 90 | byte_span[i] = malloc(sizeof(iree_const_byte_span_t)); 91 | *byte_span[i] = iree_make_const_byte_span( 92 | buffer[i], model->input_size_bytes[i] * model->input_length[i]); 93 | } 94 | return result; 95 | } 96 | 97 | iree_status_t process_output(const MlModel *model, 98 | iree_hal_buffer_mapping_t *buffers, 99 | uint32_t *output_length) { 100 | iree_status_t result = iree_ok_status(); 101 | for (int i = 0; i < buffers[0].contents.data_length / sizeof(int32_t); ++i) { 102 | if (((const int32_t *)buffers[0].contents.data)[i] != (i >> 1) * i) { 103 | result = iree_make_status(IREE_STATUS_UNKNOWN, "result mismatches"); 104 | break; 105 | } 106 | } 107 | return result; 108 | } 109 | -------------------------------------------------------------------------------- /samples/simple_vec_mul/float_vec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Float simple_mul bytecode loading and input/output processes 18 | 19 | #include "samples/util/util.h" 20 | 21 | // Compiled module embedded here to avoid file IO: 22 | #if defined(BUILD_VMVX) 23 | #if !defined(BUILD_EMITC) 24 | #include "samples/simple_vec_mul/simple_float_mul_bytecode_module_vmvx_c.h" 25 | #else 26 | #include "samples/simple_vec_mul/simple_float_mul_c_module_vmvx_emitc.h" 27 | #endif // !defined(BUILD_EMITC) 28 | #else 29 | #if !defined(BUILD_EMITC) 30 | #include "samples/simple_vec_mul/simple_float_mul_bytecode_module_static.h" 31 | #include "samples/simple_vec_mul/simple_float_mul_bytecode_module_static_c.h" 32 | #else 33 | #include "samples/simple_vec_mul/simple_float_mul_c_module_static_c.h" 34 | #include "samples/simple_vec_mul/simple_float_mul_c_module_static_emitc.h" 35 | #endif // #if !defined(BUILD_EMITC) 36 | #endif // #if defined(BUILD_VMVX) 37 | 38 | const MlModel kModel = { 39 | .num_input = 2, 40 | .num_input_dim = {1, 1}, 41 | .input_shape = {{1024}, {1024}}, 42 | .input_length = {1024, 1024}, 43 | .input_size_bytes = {sizeof(float), sizeof(float)}, 44 | .num_output = 1, 45 | .output_length = {1024}, 46 | .output_size_bytes = sizeof(float), 47 | .hal_element_type = IREE_HAL_ELEMENT_TYPE_FLOAT_32, 48 | .entry_func = "module.simple_mul", 49 | .model_name = "simple_float_vec_mul", 50 | }; 51 | 52 | iree_status_t create_module(iree_vm_instance_t *instance, 53 | iree_vm_module_t **module) { 54 | #if !defined(BUILD_EMITC) 55 | #if defined(BUILD_VMVX) 56 | const struct iree_file_toc_t *module_file_toc = 57 | samples_simple_vec_mul_simple_float_mul_bytecode_module_vmvx_create(); 58 | #else 59 | const struct iree_file_toc_t *module_file_toc = 60 | samples_simple_vec_mul_simple_float_mul_bytecode_module_static_create(); 61 | #endif // #if defined(BUILD_VMVX) 62 | return iree_vm_bytecode_module_create( 63 | instance, 64 | iree_make_const_byte_span(module_file_toc->data, module_file_toc->size), 65 | iree_allocator_null(), iree_allocator_system(), module); 66 | #else 67 | return module_create(instance, iree_allocator_system(), module); 68 | #endif // #if !defined(BUILD_EMITC) 69 | } 70 | 71 | #if !defined(BUILD_VMVX) 72 | iree_hal_executable_library_query_fn_t library_query(void) { 73 | return &simple_mul_dispatch_0_library_query; 74 | } 75 | #endif 76 | 77 | iree_status_t load_input_data(const MlModel *model, void **buffer, 78 | iree_const_byte_span_t **byte_span) { 79 | iree_status_t result = alloc_input_buffer(model, buffer); 80 | // Populate initial values 81 | // arg0 = 0, 1/4, 1/2, 3/4... 1023/4 82 | // arg1 = 0, 1/2, 1, 3/2... 1023/2 83 | if (iree_status_is_ok(result)) { 84 | for (int i = 0; i < model->input_length[0]; ++i) { 85 | ((float *)buffer[0])[i] = i / 4.0f; 86 | ((float *)buffer[1])[i] = i / 2.0f; 87 | } 88 | } 89 | for (int i = 0; i < model->num_input; ++i) { 90 | byte_span[i] = malloc(sizeof(iree_const_byte_span_t)); 91 | *byte_span[i] = iree_make_const_byte_span( 92 | buffer[i], model->input_size_bytes[i] * model->input_length[i]); 93 | } 94 | return result; 95 | } 96 | 97 | iree_status_t process_output(const MlModel *model, 98 | iree_hal_buffer_mapping_t *buffers, 99 | uint32_t *output_length) { 100 | iree_status_t result = iree_ok_status(); 101 | for (int i = 0; i < buffers[0].contents.data_length / sizeof(float); ++i) { 102 | if (((const float *)buffers[0].contents.data)[i] != i * i / 8.0f) { 103 | result = iree_make_status(IREE_STATUS_UNKNOWN, "result mismatches"); 104 | break; 105 | } 106 | } 107 | return result; 108 | } 109 | -------------------------------------------------------------------------------- /springbok/include/springbok_intrinsics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #define SPRINGBOK_SIMPRINT_ERROR (0) 20 | #define SPRINGBOK_SIMPRINT_WARNING (1) 21 | #define SPRINGBOK_SIMPRINT_INFO (2) 22 | #define SPRINGBOK_SIMPRINT_DEBUG (3) 23 | #define SPRINGBOK_SIMPRINT_NOISY (4) 24 | 25 | #define springbok_simprint_error(s, n) springbok_simprint(SPRINGBOK_SIMPRINT_ERROR, s, n) 26 | #define springbok_simprint_warning(s, n) springbok_simprint(SPRINGBOK_SIMPRINT_WARNING, s, n) 27 | #define springbok_simprint_info(s, n) springbok_simprint(SPRINGBOK_SIMPRINT_INFO, s, n) 28 | #define springbok_simprint_debug(s, n) springbok_simprint(SPRINGBOK_SIMPRINT_DEBUG, s, n) 29 | #define springbok_simprint_noisy(s, n) springbok_simprint(SPRINGBOK_SIMPRINT_NOISY, s, n) 30 | 31 | // simprint 32 | // Description: 33 | // This intrinsic prints a string and a number to the simulator console. 34 | // Inputs: 35 | // _loglevel: 36 | // The logging level in decreasing priority (0 is highest priority, 4 is lowest) 37 | // _string: 38 | // A pointer to the null-terminated string to print 39 | // _number: 40 | // The number to print 41 | // Outputs: 42 | // none 43 | static inline void springbok_simprint(int _loglevel, const char *_string, int _number) { 44 | // simprint a0, a1, a2 # "-------[rs2][rs1]000[rd ]1111011" 45 | register int loglevel __asm__ ("a0") = _loglevel; 46 | register const char *string __asm__ ("a1") = _string; 47 | register int number __asm__ ("a2") = _number; 48 | __asm__ volatile ("\t.word 0x00C5857B\n" : 49 | /* no outputs */ : 50 | "r"(loglevel), "r"(string), "r"(number) : 51 | /* no clobbers */); 52 | } 53 | 54 | // icount 55 | // Description: 56 | // This intrinsic returns a 32-bit value representing the number of instructions executed since reset. 57 | // Inputs: 58 | // none 59 | // Outputs: 60 | // the number of instructions executed since reset 61 | static inline unsigned int springbok_icount(void) { 62 | int retval; 63 | __asm__ volatile("csrr %0, 0x7c0;" : "=r"(retval)); 64 | return retval; 65 | } 66 | 67 | // ccount 68 | // Description: 69 | // This intrinsic returns a 32-bit value representing the number of unhalted cycles since reset. 70 | // Inputs: 71 | // none 72 | // Outputs: 73 | // the number of unhalted cycles since reset 74 | static inline unsigned int springbok_ccount(void) { 75 | // ccount a0 # "------------00001001[rd ]1111011" 76 | int retval; 77 | __asm__ volatile("csrr %0, 0x7c1;" : "=r"(retval)); 78 | return retval; 79 | } 80 | 81 | // hostreq 82 | // Description: 83 | // This intrinsic halts Springbok and triggers a host request interrupt in an attached management core. 84 | // Inputs: 85 | // none 86 | // Outputs: 87 | // none 88 | static inline void springbok_hostreq(void) { 89 | // hostreq # "-----------------010-----1111011" 90 | __asm__ volatile ("\t.word 0x0000207B\n" : 91 | /* no outputs */ : 92 | /* no inputs */ : 93 | /* no clobbers */); 94 | } 95 | 96 | // finish 97 | // Description: 98 | // This intrinsic halts and resets Springbok while triggerring a completion interrupt in an attached management core. 99 | // It's included here for completeness, but it should not actually be called by C/C++ applications as it bypasses 100 | // C/C++ destructors and crt stack sentinel verification. 101 | // Inputs: 102 | // none 103 | // Outputs: 104 | // none 105 | __attribute__((noreturn)) static inline void springbok_finish(void) { 106 | // finish # "-----------------011-----1111011" 107 | __asm__ volatile ("\t.word 0x0000307B\n" : 108 | /* no outputs */ : 109 | /* no inputs */ : 110 | /* no clobbers */); 111 | while(1); 112 | } 113 | -------------------------------------------------------------------------------- /cmake/springbok_vmvx_module.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # springbok_static_module() 15 | # 16 | # A modified version of iree_vmvx_linker_test to apply common iree-compile flags 17 | # Parameters: 18 | # NAME: Name of target. 19 | # SRC: Source file to compile into a bytecode module. Support relative path. 20 | # FLAGS: Flags to pass to the translation tool (list of strings). 21 | # DEPENDS: List of other targets and files required for this binary. 22 | # EMITC: Uses EmitC to output C code instead of VM bytecode. 23 | # INLINE_HAL: Use inline HAL. 24 | # 25 | # Examples: 26 | # springbok_vmvx_module( 27 | # NAME 28 | # simple_float_mul_c_module_vmvx 29 | # SRC 30 | # "simple_float_mul.mlir" 31 | # C_IDENTIFIER 32 | # "simple_float_mul" 33 | # FLAGS 34 | # "-iree-input-type=mhlo" 35 | # EMITC 36 | # ) 37 | # 38 | function(springbok_vmvx_module) 39 | cmake_parse_arguments( 40 | _RULE 41 | "EMITC;INLINE_HAL" 42 | "NAME;SRC;C_IDENTIFIER" 43 | "FLAGS;DEPENDS" 44 | ${ARGN} 45 | ) 46 | 47 | set(_MLIR_SRC "${_RULE_SRC}") 48 | string(FIND "${_RULE_SRC}" ".tflite" _IS_TFLITE REVERSE) 49 | if(${_IS_TFLITE} GREATER 0) 50 | find_program(IREE_IMPORT_TFLITE_TOOL "iree-import-tflite" REQUIRED) 51 | set(_MLIR_SRC "${CMAKE_CURRENT_BINARY_DIR}/${_RULE_NAME}.mlir") 52 | get_filename_component(_SRC_PATH "${_RULE_SRC}" REALPATH) 53 | set(_ARGS "${_SRC_PATH}") 54 | list(APPEND _ARGS "-o") 55 | list(APPEND _ARGS "${_RULE_NAME}.mlir") 56 | # Only add the custom_command here. The output is passed to 57 | # iree_bytecode_module as the source. 58 | add_custom_command( 59 | OUTPUT 60 | "${_RULE_NAME}.mlir" 61 | COMMAND 62 | ${IREE_IMPORT_TFLITE_TOOL} 63 | ${_ARGS} 64 | DEPENDS 65 | ${IREE_IMPORT_TFLITE_TOOL} 66 | ${_RULE_DEPENDS} 67 | ) 68 | endif() 69 | 70 | iree_package_name(_PACKAGE_NAME) 71 | iree_package_ns(_PACKAGE_NS) 72 | 73 | # Set common iree-compile flags 74 | set(_COMPILER_ARGS ${_RULE_FLAGS}) 75 | if (${_RULE_INLINE_HAL}) 76 | list(APPEND _COMPILER_ARGS "--iree-execution-model=inline-static") 77 | list(APPEND _COMPILER_ARGS "--iree-hal-target-backends=vmvx-inline") 78 | else() 79 | list(APPEND _COMPILER_ARGS "--iree-hal-target-backends=vmvx") 80 | endif() 81 | 82 | if(_RULE_EMITC) 83 | set(_MODULE_NAME "${_RULE_NAME}_emitc") 84 | set(_H_FILE_NAME "${_RULE_NAME}_emitc.h") 85 | 86 | get_filename_component(_MLIR_SRC "${_MLIR_SRC}" REALPATH) 87 | list(APPEND _COMPILER_ARGS "--iree-vm-target-index-bits=32") 88 | list(APPEND _COMPILER_ARGS "--output-format=vm-c") 89 | list(APPEND _COMPILER_ARGS "${_MLIR_SRC}") 90 | list(APPEND _COMPILER_ARGS "-o") 91 | list(APPEND _COMPILER_ARGS "${_H_FILE_NAME}") 92 | 93 | add_custom_command( 94 | OUTPUT ${_H_FILE_NAME} 95 | COMMAND iree-compile ${_COMPILER_ARGS} 96 | DEPENDS iree-compile ${_MLIR_SRC} 97 | ) 98 | 99 | set(_EMITC_LIB_NAME "${_PACKAGE_NAME}_${_MODULE_NAME}") 100 | add_library(${_EMITC_LIB_NAME} 101 | ${_H_FILE_NAME} 102 | ) 103 | target_compile_definitions(${_EMITC_LIB_NAME} PUBLIC EMITC_IMPLEMENTATION=\"${_H_FILE_NAME}\") 104 | SET_TARGET_PROPERTIES( 105 | ${_EMITC_LIB_NAME} 106 | PROPERTIES 107 | LINKER_LANGUAGE C 108 | ) 109 | add_library(${_PACKAGE_NS}::${_MODULE_NAME} ALIAS ${_EMITC_LIB_NAME}) 110 | 111 | else() # bytecode module path 112 | # Generate the embed data with the bytecode module. 113 | set(_MODULE_NAME "${_RULE_NAME}") 114 | if(NOT _RULE_C_IDENTIFIER) 115 | set(_RULE_C_IDENTIFIER "${_PACKAGE_NAME}_${_RULE_NAME}") 116 | endif() 117 | iree_bytecode_module( 118 | NAME 119 | ${_MODULE_NAME} 120 | SRC 121 | "${_MLIR_SRC}" 122 | FLAGS 123 | ${_COMPILER_ARGS} 124 | C_IDENTIFIER 125 | "${_RULE_C_IDENTIFIER}" 126 | PUBLIC 127 | ) 128 | endif(_RULE_EMITC) 129 | endfunction() 130 | -------------------------------------------------------------------------------- /cmake/springbok_modules.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | include(CMakeParseArguments) 16 | 17 | # springbok_modules() 18 | # 19 | # A wrapper for the springbok_bytecode_module and springbok_c_module to apply common iree-compile flags 20 | # Parameters: 21 | # NAME: Name of target. 22 | # SRC: Source file to compile into a bytecode module. Support relative path and 23 | # URL. 24 | # FLAGS: Flags to pass to the translation tool (list of strings). 25 | # C_IDENTIFIER: Identifier to use for generate c embed code. 26 | # If omitted then no C embed code will be generated. 27 | # RVV_OFF: Indicate RVV is OFF (default: ON) 28 | # VMVX: Compile VMVX backend 29 | # INLINE_HAL: Use inline HAL. 30 | # 31 | # Examples: 32 | # springbok_modules( 33 | # NAME 34 | # mobilenet_v1 35 | # SRC 36 | # "https://storage.googleapis.com/tfhub-lite-models/tensorflow/lite-model/mobilenet_v1_0.25_224_quantized/1/default/1.tflite" 37 | # C_IDENTIFIER 38 | # "samples_quant_model_mobilenet_v1" 39 | # FLAGS 40 | # "-iree-input-type=tosa" 41 | # "-riscv-v-vector-bits-min=512" 42 | # "-riscv-v-fixed-length-vector-lmul-max=8" 43 | # ) 44 | # 45 | # springbok_modules( 46 | # NAME 47 | # simple_float_mul 48 | # SRC 49 | # "simple_float_mul.mlir" 50 | # C_IDENTIFIER 51 | # "samples_simple_vec_mul_simple_float_mul" 52 | # FLAGS 53 | # "-iree-input-type=mhlo" 54 | # ) 55 | # 56 | 57 | function(springbok_modules) 58 | cmake_parse_arguments( 59 | _RULE 60 | "RVV_OFF;VMVX;INLINE_HAL" 61 | "NAME;SRC;C_IDENTIFIER" 62 | "FLAGS" 63 | ${ARGN} 64 | ) 65 | 66 | if (${_RULE_RVV_OFF}) 67 | set(_RVV_OFF_ARG "RVV_OFF") 68 | endif() 69 | 70 | string(REGEX REPLACE "[ \t\r\n]" "" _RULE_SRC_TRIM ${_RULE_SRC}) 71 | string(REGEX MATCH "^https:" _RULE_SRC_URL ${_RULE_SRC_TRIM}) 72 | if (_RULE_SRC_URL) 73 | get_filename_component(_INPUT_EXT "${_RULE_SRC_TRIM}" LAST_EXT) 74 | set(_INPUT_FILENAME "${_RULE_NAME}${_INPUT_EXT}") 75 | find_program(_WGET wget HINT "$ENV{PATH}" REQUIRED) 76 | add_custom_command( 77 | OUTPUT 78 | ${_INPUT_FILENAME} 79 | COMMAND 80 | ${_WGET} -q -P "${CMAKE_CURRENT_BINARY_DIR}" -O "${_INPUT_FILENAME}" 81 | "${_RULE_SRC_TRIM}" 82 | COMMENT 83 | "Download ${_INPUT_FILENAME} from ${_RULE_SRC_TRIM}" 84 | ) 85 | set(_INPUT_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/${_INPUT_FILENAME}") 86 | else() 87 | set(_INPUT_FILENAME ${_RULE_SRC_TRIM}) 88 | endif() 89 | 90 | if (${_RULE_INLINE_HAL}) 91 | set(_INLINE_HAL_ARG "INLINE_HAL") 92 | endif() 93 | 94 | springbok_static_module( 95 | NAME 96 | "${_RULE_NAME}_bytecode_module_static" 97 | SRC 98 | "${_INPUT_FILENAME}" 99 | C_IDENTIFIER 100 | "${_RULE_C_IDENTIFIER}_bytecode_module_static" 101 | FLAGS 102 | ${_RULE_FLAGS} 103 | "${_RVV_OFF_ARG}" 104 | "${_INLINE_HAL_ARG}" 105 | DEPENDS 106 | "${_INPUT_FILENAME}" 107 | ) 108 | 109 | springbok_static_module( 110 | NAME 111 | "${_RULE_NAME}_c_module_static" 112 | SRC 113 | "${_INPUT_FILENAME}" 114 | FLAGS 115 | ${_RULE_FLAGS} 116 | "${_RVV_OFF_ARG}" 117 | "${_INLINE_HAL_ARG}" 118 | EMITC 119 | DEPENDS 120 | "${_INPUT_FILENAME}" 121 | ) 122 | 123 | if (${_RULE_VMVX}) 124 | springbok_vmvx_module( 125 | NAME 126 | "${_RULE_NAME}_bytecode_module_vmvx" 127 | SRC 128 | "${_INPUT_FILENAME}" 129 | C_IDENTIFIER 130 | "${_RULE_C_IDENTIFIER}_bytecode_module_vmvx" 131 | FLAGS 132 | ${_RULE_FLAGS} 133 | DEPENDS 134 | "${_INPUT_FILENAME}" 135 | "${_INLINE_HAL_ARG}" 136 | ) 137 | 138 | springbok_vmvx_module( 139 | NAME 140 | "${_RULE_NAME}_c_module_vmvx" 141 | SRC 142 | "${_INPUT_FILENAME}" 143 | FLAGS 144 | ${_RULE_FLAGS} 145 | "${_INLINE_HAL_ARG}" 146 | EMITC 147 | DEPENDS 148 | "${_INPUT_FILENAME}" 149 | ) 150 | endif() 151 | 152 | endfunction() 153 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION 3.13.4) 16 | 17 | #------------------------------------------------------------------------------- 18 | # Project configuration 19 | #------------------------------------------------------------------------------- 20 | 21 | project(iree-riscv32) 22 | 23 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 24 | 25 | list(APPEND CMAKE_MODULE_PATH 26 | ${CMAKE_CURRENT_LIST_DIR}/cmake/ 27 | ) 28 | 29 | set(IREE_SOURCE_DIR "third_party/iree" CACHE PATH 30 | "IREE source code path. (default: third_party/iree/)") 31 | 32 | include_directories(BEFORE SYSTEM ${CMAKE_CURRENT_LIST_DIR}) 33 | include_directories(BEFORE SYSTEM ${CMAKE_CURRENT_BINARY_DIR}) 34 | 35 | # Use nano spec header and libraries. 36 | include_directories(BEFORE SYSTEM "${RISCV_TOOLCHAIN_ROOT}/riscv32-unknown-elf/include/newlib-nano/") 37 | link_directories(BEFORE "${RISCV_TOOLCHAIN_ROOT}/riscv32-unknown-elf/lib/newlib-nano/") 38 | 39 | #------------------------------------------------------------------------------- 40 | # Springbok-specific settings 41 | #------------------------------------------------------------------------------- 42 | set(DTCM_LENGTH "16M" CACHE STRING "DTCM Length (default: 16M)") 43 | add_link_options("LINKER:--defsym=__dtcm_length__=${DTCM_LENGTH}") 44 | set(ITCM_LENGTH "1M" CACHE STRING "ITCM (I-mem) Length (default: 1M)") 45 | add_link_options("LINKER:--defsym=__itcm_length__=${ITCM_LENGTH}") 46 | set(STACK_SIZE "10K" CACHE STRING "Stack size (default: 10K)") 47 | add_link_options("LINKER:--defsym=__stack_size__=${STACK_SIZE}") 48 | set(SPRINGBOK_LINKER_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/springbok/springbok.ld" CACHE PATH "Springbok linker script path (default: springbok.ld)") 49 | set(BUILD_WITH_SPRINGBOK ON CACHE BOOL "Build the target with springbok BSP (default: ON)") 50 | 51 | #------------------------------------------------------------------------------- 52 | # IREE-specific settings 53 | #------------------------------------------------------------------------------- 54 | set(IREE_BUILD_COMPILER OFF) 55 | set(IREE_ENABLE_MLIR OFF) 56 | set(IREE_BUILD_SAMPLES OFF) 57 | set(IREE_ENABLE_THREADING OFF) 58 | set(IREE_BUILD_TESTS OFF) 59 | set(IREE_BUILD_BINDINGS_TFLITE OFF) 60 | set(IREE_HAL_DRIVER_LOCAL_SYNC ON CACHE BOOL "" FORCE) 61 | set(IREE_HAL_EXECUTABLE_LOADER_DEFAULTS OFF CACHE BOOL "" FORCE) 62 | set(IREE_HAL_EXECUTABLE_LOADER_VMVX_MODULE ON CACHE BOOL "" FORCE) 63 | set(IREE_HAL_DRIVER_DEFAULTS OFF CACHE BOOL "" FORCE) 64 | 65 | #------------------------------------------------------------------------------- 66 | # IREE-specific definitions 67 | #------------------------------------------------------------------------------- 68 | set(SPRINGBOK_CONFIG_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/springbok_config.h") 69 | add_definitions(-DFLATCC_USE_GENERIC_ALIGNED_ALLOC) 70 | add_definitions(-DIREE_PLATFORM_GENERIC) 71 | add_definitions(-DIREE_SYNCHRONIZATION_DISABLE_UNSAFE=1) 72 | add_definitions(-DIREE_FILE_IO_ENABLE=0) 73 | add_definitions(-DIREE_USER_CONFIG_H="${SPRINGBOK_CONFIG_HEADER}") 74 | 75 | # The project does a cmake hack here -- at the executable linkage stage, we 76 | # append the logging library (and springbok BSP). Any logging library update 77 | # (libspringbok.a) only gets rebuilt during executable 78 | # linkage, but not during library compilation. 79 | # 80 | # However, an explicit include path gets added here across all targets so the 81 | # header files can be found during compilation. 82 | 83 | # Springbok BSP-related setting 84 | add_subdirectory(springbok springbok) 85 | include(riscv_springbok) 86 | include_directories(springbok/include) 87 | 88 | message(STATUS "Include IREE source at ${IREE_SOURCE_DIR}") 89 | # Build IREE runtime libraries. 90 | add_subdirectory(${IREE_SOURCE_DIR} iree) 91 | 92 | # Apply IREE's CMake variables and build options so we can use IREE build 93 | # functions properly in this project. 94 | set(IREE_ROOT_DIR "${IREE_SOURCE_DIR}" CACHE PATH "IREE Root directory") 95 | include(springbok_ops) 96 | 97 | include(springbok_static_module) 98 | include(springbok_vmvx_module) 99 | include(springbok_modules) 100 | include(iree_model_input) 101 | # softmax op (and mfcc) requires floorf implementation in libm. Use the nano 102 | # version. 103 | find_library(m m 104 | PATHS 105 | "${RISCV_TOOLCHAIN_ROOT}/riscv32-unknown-elf/lib/newlib-nano/" 106 | REQUIRED) 107 | link_libraries(m) 108 | # Add the included directory here. 109 | add_subdirectory(samples) 110 | -------------------------------------------------------------------------------- /samples/simple_vec_mul/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #------------------------------------------------------------------------------- 16 | # Build the mlir bytecode modules with iree-compile. Note the last two flags 17 | # are for RVV support. 18 | # https://github.com/llvm/llvm-project/blob/0eeab8b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp#L30-L51 19 | #------------------------------------------------------------------------------- 20 | 21 | springbok_modules( 22 | NAME 23 | simple_float_mul 24 | SRC 25 | "simple_float_mul.mlir" 26 | C_IDENTIFIER 27 | "samples_simple_vec_mul_simple_float_mul" 28 | FLAGS 29 | "-iree-input-type=mhlo" 30 | "-riscv-v-fixed-length-vector-lmul-max=8" 31 | VMVX 32 | INLINE_HAL 33 | ) 34 | 35 | springbok_modules( 36 | NAME 37 | simple_int_mul 38 | SRC 39 | "simple_int_mul.mlir" 40 | C_IDENTIFIER 41 | "samples_simple_vec_mul_simple_int_mul" 42 | FLAGS 43 | "-iree-input-type=mhlo" 44 | "-riscv-v-fixed-length-vector-lmul-max=8" 45 | VMVX 46 | INLINE_HAL 47 | ) 48 | 49 | #------------------------------------------------------------------------------- 50 | # Binaries to execute the MLIR bytecode modules 51 | #------------------------------------------------------------------------------- 52 | 53 | # Different util libraries available: 54 | # util_static: static library using regular HAL 55 | # util_vmvx: vmvx using regular HAL 56 | # util_static_inline: static library using inline HAL 57 | # util_vmvx_inline: vmvx using inline HAL 58 | 59 | # If the program requires a larger stack size, add 60 | # 61 | # LINKOPTS 62 | # "LINKER:--defsym=__stack_size__=" 63 | # 64 | # to increase it. 65 | 66 | iree_cc_binary( 67 | NAME 68 | simple_float_vec_mul_bytecode_vmvx 69 | SRCS 70 | "float_vec.c" 71 | DEPS 72 | ::simple_float_mul_bytecode_module_vmvx_c 73 | samples::util::util_vmvx_inline 74 | LINKOPTS 75 | "LINKER:--defsym=__stack_size__=20k" 76 | COPTS 77 | "-DBUILD_VMVX" 78 | ) 79 | 80 | iree_cc_binary( 81 | NAME 82 | simple_float_vec_mul_emitc_vmvx 83 | SRCS 84 | "float_vec.c" 85 | DEPS 86 | ::simple_float_mul_c_module_vmvx_emitc 87 | samples::util::util_vmvx_inline 88 | LINKOPTS 89 | "LINKER:--defsym=__stack_size__=20k" 90 | COPTS 91 | "-DBUILD_EMITC" 92 | "-DBUILD_VMVX" 93 | ) 94 | 95 | iree_cc_binary( 96 | NAME 97 | simple_float_vec_mul_bytecode_static 98 | SRCS 99 | "float_vec.c" 100 | DEPS 101 | ::simple_float_mul_bytecode_module_static_c 102 | ::simple_float_mul_bytecode_module_static_lib 103 | iree::vm::bytecode_module 104 | samples::util::util_static_inline 105 | LINKOPTS 106 | "LINKER:--defsym=__stack_size__=20k" 107 | ) 108 | 109 | iree_cc_binary( 110 | NAME 111 | simple_float_vec_mul_emitc_static 112 | SRCS 113 | "float_vec.c" 114 | DEPS 115 | ::simple_float_mul_c_module_static_emitc 116 | ::simple_float_mul_c_module_static_lib 117 | samples::util::util_static_inline 118 | LINKOPTS 119 | "LINKER:--defsym=__stack_size__=20k" 120 | COPTS 121 | "-DBUILD_EMITC" 122 | ) 123 | 124 | iree_cc_binary( 125 | NAME 126 | simple_int_vec_mul_bytecode_vmvx 127 | SRCS 128 | "int_vec.c" 129 | DEPS 130 | ::simple_int_mul_bytecode_module_vmvx_c 131 | samples::util::util_vmvx_inline 132 | LINKOPTS 133 | "LINKER:--defsym=__stack_size__=20k" 134 | COPTS 135 | "-DBUILD_VMVX" 136 | ) 137 | 138 | iree_cc_binary( 139 | NAME 140 | simple_int_vec_mul_emitc_vmvx 141 | SRCS 142 | "int_vec.c" 143 | DEPS 144 | ::simple_int_mul_c_module_vmvx_emitc 145 | samples::util::util_vmvx_inline 146 | LINKOPTS 147 | "LINKER:--defsym=__stack_size__=20k" 148 | COPTS 149 | "-DBUILD_EMITC" 150 | "-DBUILD_VMVX" 151 | ) 152 | 153 | iree_cc_binary( 154 | NAME 155 | simple_int_vec_mul_bytecode_static 156 | SRCS 157 | "int_vec.c" 158 | DEPS 159 | ::simple_int_mul_bytecode_module_static_c 160 | ::simple_int_mul_bytecode_module_static_lib 161 | iree::vm::bytecode_module 162 | samples::util::util_static_inline 163 | LINKOPTS 164 | "LINKER:--defsym=__stack_size__=20k" 165 | ) 166 | 167 | iree_cc_binary( 168 | NAME 169 | simple_int_vec_mul_emitc_static 170 | SRCS 171 | "int_vec.c" 172 | DEPS 173 | ::simple_int_mul_c_module_static_emitc 174 | ::simple_int_mul_c_module_static_lib 175 | samples::util::util_static_inline 176 | LINKOPTS 177 | "LINKER:--defsym=__stack_size__=20k" 178 | COPTS 179 | "-DBUILD_EMITC" 180 | ) 181 | -------------------------------------------------------------------------------- /cmake/springbok_static_module.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # springbok_static_module() 15 | # 16 | # A modified version of iree_static_linker_test to apply common iree-compile flags 17 | # Parameters: 18 | # NAME: Name of target. 19 | # SRC: Source file to compile into a bytecode module. Support relative path. 20 | # C_IDENTIFIER: Identifier to use for generate c embed code. 21 | # FLAGS: Flags to pass to the translation tool (list of strings). 22 | # DEPENDS: List of other targets and files required for this binary. 23 | # RVV_OFF: Indicate RVV is OFF (default: ON) 24 | # EMITC: Uses EmitC to output C code instead of VM bytecode. 25 | # INLINE_HAL: Use inline HAL. 26 | # 27 | # Examples: 28 | # springbok_static_module( 29 | # NAME 30 | # simple_float_mul_c_module_static 31 | # SRC 32 | # "simple_float_mul.mlir" 33 | # C_IDENTIFIER 34 | # "simple_float_mul" 35 | # FLAGS 36 | # "-iree-input-type=mhlo" 37 | # RVV_OFF 38 | # EMITC 39 | # ) 40 | # 41 | function(springbok_static_module) 42 | cmake_parse_arguments( 43 | _RULE 44 | "RVV_OFF;EMITC;INLINE_HAL" 45 | "NAME;SRC;C_IDENTIFIER" 46 | "FLAGS;DEPENDS" 47 | ${ARGN} 48 | ) 49 | 50 | set(_MLIR_SRC "${_RULE_SRC}") 51 | string(FIND "${_RULE_SRC}" ".tflite" _IS_TFLITE REVERSE) 52 | if(${_IS_TFLITE} GREATER 0) 53 | find_program(IREE_IMPORT_TFLITE_TOOL "iree-import-tflite" REQUIRED) 54 | set(_MLIR_SRC "${CMAKE_CURRENT_BINARY_DIR}/${_RULE_NAME}.mlir") 55 | get_filename_component(_SRC_PATH "${_RULE_SRC}" REALPATH) 56 | set(_ARGS "${_SRC_PATH}") 57 | list(APPEND _ARGS "-o") 58 | list(APPEND _ARGS "${_RULE_NAME}.mlir") 59 | # Only add the custom_command here. The output is passed to 60 | # iree_bytecode_module as the source. 61 | add_custom_command( 62 | OUTPUT 63 | "${_RULE_NAME}.mlir" 64 | COMMAND 65 | ${IREE_IMPORT_TFLITE_TOOL} 66 | ${_ARGS} 67 | DEPENDS 68 | ${IREE_IMPORT_TFLITE_TOOL} 69 | ${_RULE_DEPENDS} 70 | ) 71 | endif() 72 | 73 | iree_package_name(_PACKAGE_NAME) 74 | iree_package_ns(_PACKAGE_NS) 75 | 76 | set(_CPU_FEATURES "+m,+f,+zvl512b,+zve32x") 77 | if (${_RULE_RVV_OFF}) 78 | set(_CPU_FEATURES "+m,+f") 79 | endif() 80 | 81 | # Set common iree-compile flags 82 | set(_COMPILER_ARGS ${_RULE_FLAGS}) 83 | list(APPEND _COMPILER_ARGS "--iree-hal-target-backends=llvm-cpu") 84 | list(APPEND _COMPILER_ARGS "--iree-llvm-debug-symbols=false") 85 | list(APPEND _COMPILER_ARGS "--iree-vm-bytecode-module-strip-source-map=true") 86 | list(APPEND _COMPILER_ARGS "--iree-vm-emit-polyglot-zip=false") 87 | list(APPEND _COMPILER_ARGS "--iree-llvm-target-triple=riscv32-pc-linux-elf") 88 | list(APPEND _COMPILER_ARGS "--iree-llvm-target-cpu=generic-rv32") 89 | list(APPEND _COMPILER_ARGS "--iree-llvm-target-cpu-features=${_CPU_FEATURES}") 90 | list(APPEND _COMPILER_ARGS "--iree-llvm-target-abi=ilp32") 91 | list(APPEND _COMPILER_ARGS "--iree-llvm-link-embedded=false") 92 | if (${_RULE_INLINE_HAL}) 93 | list(APPEND _COMPILER_ARGS "--iree-execution-model=inline-dynamic") 94 | endif() 95 | 96 | if(_RULE_EMITC) 97 | set(_O_FILE_NAME "${_RULE_NAME}_c.o") 98 | set(_H_FILE_NAME "${_RULE_NAME}_emitc.h") 99 | set(_MODULE_NAME "${_RULE_NAME}_emitc") 100 | 101 | get_filename_component(_MLIR_SRC "${_MLIR_SRC}" REALPATH) 102 | list(APPEND _COMPILER_ARGS "--output-format=vm-c") 103 | list(APPEND _COMPILER_ARGS "--iree-vm-target-index-bits=32") 104 | list(APPEND _COMPILER_ARGS "--iree-llvm-link-static") 105 | list(APPEND _COMPILER_ARGS "--iree-llvm-static-library-output-path=${_O_FILE_NAME}") 106 | list(APPEND _COMPILER_ARGS "${_MLIR_SRC}") 107 | list(APPEND _COMPILER_ARGS "-o") 108 | list(APPEND _COMPILER_ARGS "${_H_FILE_NAME}") 109 | 110 | set(_OUTPUT_FILES "${_H_FILE_NAME}") 111 | string(REPLACE ".o" ".h" _STATIC_HDR_PATH "${_O_FILE_NAME}") 112 | list(APPEND _OUTPUT_FILES "${_O_FILE_NAME}" "${_STATIC_HDR_PATH}") 113 | 114 | add_custom_command( 115 | OUTPUT ${_OUTPUT_FILES} 116 | COMMAND iree-compile ${_COMPILER_ARGS} 117 | DEPENDS iree-compile ${_MLIR_SRC} 118 | ) 119 | 120 | set(_EMITC_LIB_NAME "${_PACKAGE_NAME}_${_MODULE_NAME}") 121 | add_library(${_EMITC_LIB_NAME} 122 | STATIC 123 | ${_H_FILE_NAME} 124 | ) 125 | target_compile_definitions(${_EMITC_LIB_NAME} PUBLIC EMITC_IMPLEMENTATION=\"${_H_FILE_NAME}\") 126 | SET_TARGET_PROPERTIES( 127 | ${_EMITC_LIB_NAME} 128 | PROPERTIES 129 | LINKER_LANGUAGE C 130 | ) 131 | add_library(${_PACKAGE_NS}::${_MODULE_NAME} ALIAS ${_EMITC_LIB_NAME}) 132 | 133 | else() # bytecode module path 134 | # Generate the embed data with the bytecode module. 135 | set(_O_FILE_NAME "${_RULE_NAME}.o") 136 | set(_H_FILE_NAME "${_RULE_NAME}.h") 137 | set(_MODULE_NAME "${_RULE_NAME}") 138 | if(NOT _RULE_C_IDENTIFIER) 139 | set(_RULE_C_IDENTIFIER "${_PACKAGE_NAME}_${_RULE_NAME}") 140 | endif() 141 | 142 | iree_bytecode_module( 143 | NAME 144 | ${_MODULE_NAME} 145 | SRC 146 | "${_MLIR_SRC}" 147 | FLAGS 148 | ${_COMPILER_ARGS} 149 | STATIC_LIB_PATH 150 | "${_O_FILE_NAME}" 151 | C_IDENTIFIER 152 | "${_RULE_C_IDENTIFIER}" 153 | PUBLIC 154 | ) 155 | endif(_RULE_EMITC) 156 | 157 | set(_NAME "${_RULE_NAME}_lib") 158 | set(_LIB_NAME "${_PACKAGE_NAME}_${_NAME}") 159 | add_library(${_LIB_NAME} 160 | STATIC 161 | ${_O_FILE_NAME} 162 | ) 163 | SET_TARGET_PROPERTIES( 164 | ${_LIB_NAME} 165 | PROPERTIES 166 | LINKER_LANGUAGE C 167 | ) 168 | 169 | # Set alias for this static library to be used later in the function. 170 | add_library(${_PACKAGE_NS}::${_NAME} ALIAS ${_LIB_NAME}) 171 | endfunction() 172 | -------------------------------------------------------------------------------- /springbok/crt0.S: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | .section .text._start 16 | .align 2 17 | .globl _start 18 | _start: 19 | ############################################### 20 | # Put all scalar registers into a known state # 21 | ############################################### 22 | la sp, _stack_ptr 23 | la gp, _global_pointer 24 | mv tp, zero 25 | mv t1, zero 26 | mv t2, zero 27 | mv s0, zero 28 | mv s1, zero 29 | mv a1, zero 30 | mv a2, zero 31 | mv a3, zero 32 | mv a4, zero 33 | mv a5, zero 34 | mv a6, zero 35 | mv a7, zero 36 | mv s2, zero 37 | mv s3, zero 38 | mv s4, zero 39 | mv s5, zero 40 | mv s6, zero 41 | mv s7, zero 42 | mv s8, zero 43 | mv s9, zero 44 | mv s10, zero 45 | mv s11, zero 46 | mv t3, zero 47 | mv t4, zero 48 | mv t5, zero 49 | mv t6, zero 50 | 51 | #ifndef LIBSPRINGBOK_NO_VECTOR_SUPPORT 52 | ############################################### 53 | # Put all vector registers into a known state # 54 | ############################################### 55 | # Set vector extension to "initial" 56 | csrr a0, mstatus 57 | ori a0, a0, 0x600 58 | addi a0, a0, -0x200 59 | csrw mstatus, a0 60 | 61 | # Set lmul=8 and clear the register file 62 | vsetvli t0, zero, e8, m8, tu, mu 63 | vmv.v.i v0, 0 64 | vmv.v.i v8, 0 65 | vmv.v.i v16, 0 66 | vmv.v.i v24, 0 67 | 68 | # Set lmul=1 69 | vsetvli t0, zero, e8, m1, tu, mu 70 | 71 | # Set vector extension to "clean" 72 | xori a0, a0, 0x600 73 | csrw mstatus, a0 74 | #endif 75 | 76 | #ifndef LIBSPRINGBOK_NO_FLOAT_SUPPORT 77 | ############################################################### 78 | # Reset all other CSRs, and perform any other processor setup # 79 | ############################################################### 80 | # Enable floating point unit 81 | csrr a0, mstatus 82 | li a1, 0x2000 83 | or a0, a0, a1 84 | csrw mstatus, a0 85 | #endif 86 | 87 | #ifndef LIBSPRINGBOK_NO_EXCEPTION_SUPPORT 88 | la a0, exception_handler 89 | csrw mtvec, a0 90 | #endif 91 | 92 | ############################################################# 93 | # Set up stack sentinels # 94 | ############################################################# 95 | jal ra, _setup_stack_sentinels 96 | 97 | ########################## 98 | # Register fini handlers # 99 | ########################## 100 | la a0, __libc_fini_array 101 | call atexit 102 | 103 | ################################## 104 | # Perform C initialization calls # 105 | ################################## 106 | call __libc_init_array 107 | 108 | ############# 109 | # Call main # 110 | ############# 111 | li a0, 0 #argv 112 | li a1, 0 #argc 113 | li a2, 0 #envp 114 | la ra, main 115 | jalr ra, ra 116 | # Save main's return value into s0 117 | mv s0, a0 118 | 119 | ###################### 120 | # Call C destructors # 121 | ###################### 122 | li a1, 0 123 | call __call_exitprocs 124 | 125 | # Don't clear the stack if the program returned from main 126 | j 1f 127 | 128 | _exit: 129 | # Save _exit's return value 130 | mv s0, a0 131 | 132 | # Clear the stack 133 | la sp, _stack_ptr 134 | 1: 135 | ########################################################################## 136 | # Verify stack sentinels are unchanged and that sp is where we expect it # 137 | ########################################################################## 138 | # Check the stack, and fix it if it's broken 139 | jal ra, _check_stack 140 | 141 | # Was the stack corrupted? 142 | beq a0, zero, 1f 143 | 144 | # The stack was corrupted! 145 | # These strings are stored in instruction memory like 146 | # this so they can't ever be corrupted. 147 | li t0, 0x63617473 # "stac" 148 | li t1, 0x6f63206b # "k co" 149 | li t2, 0x70757272 # "rrup" 150 | li t3, 0x00646574 # "ted\0" 151 | addi sp, sp, -16 152 | sw t0, 0(sp) 153 | sw t1, 4(sp) 154 | sw t2, 8(sp) 155 | sw t3, 12(sp) 156 | li t4, 0 # ERROR logging level 157 | .word 0x00A10EFB # simprint t4, sp, a0 (encoded as custom3) 158 | addi sp, sp, 16 159 | 1: 160 | 161 | # Restore the application's return value 162 | mv a0, s0 163 | 164 | # Print main's return value 165 | # These strings are stored in instruction memory like 166 | # this so they can't ever be corrupted. 167 | li t0, 0x6e69616d # "main" 168 | li t1, 0x74657220 # " ret" 169 | li t2, 0x656e7275 # "urne" 170 | li t3, 0x00203a64 # "d: \0" 171 | addi sp, sp, -16 172 | sw t0, 0(sp) 173 | sw t1, 4(sp) 174 | sw t2, 8(sp) 175 | sw t3, 12(sp) 176 | li t4, 2 # INFO logging level 177 | .word 0x00A10EFB # simprint t4, sp, a0 (encoded as custom3) 178 | addi sp, sp, 16 179 | 180 | _finish: 181 | #ifndef LIBSPRINGBOK_NO_EXCEPTION_SUPPORT 182 | # Store the application's return value and machine exception program 183 | # counter onto the stack 184 | addi sp, sp, -8 185 | sw a0, 0(sp) 186 | csrr t0, mepc 187 | sw t0, 4(sp) 188 | #else 189 | # Store the application's return value onto the stack 190 | addi sp, sp, -4 191 | sw a0, 0(sp) 192 | #endif 193 | 1: 194 | .word 0x0000307B # finish (encoded as custom3) 195 | j 1b 196 | 197 | _setup_stack_sentinels: 198 | ####################################### 199 | # Write our stack sentinels to memory # 200 | ####################################### 201 | la a0, _stack_start_sentinel 202 | li a1, 0xCAFEF00D 203 | sw a1, 0(a0) 204 | sw a1, 4(a0) 205 | sw a1, 8(a0) 206 | sw a1, 12(a0) 207 | sw a1, 16(a0) 208 | sw a1, 20(a0) 209 | sw a1, 24(a0) 210 | sw a1, 28(a0) 211 | sw a1, 32(a0) 212 | sw a1, 36(a0) 213 | sw a1, 40(a0) 214 | sw a1, 44(a0) 215 | sw a1, 48(a0) 216 | sw a1, 52(a0) 217 | sw a1, 56(a0) 218 | sw a1, 60(a0) 219 | 220 | la a0, _stack_end_sentinel 221 | li a1, 0xDECAFBAD 222 | sw a1, 0(a0) 223 | sw a1, 4(a0) 224 | sw a1, 8(a0) 225 | sw a1, 12(a0) 226 | sw a1, 16(a0) 227 | sw a1, 20(a0) 228 | sw a1, 24(a0) 229 | sw a1, 28(a0) 230 | sw a1, 32(a0) 231 | sw a1, 36(a0) 232 | sw a1, 40(a0) 233 | sw a1, 44(a0) 234 | sw a1, 48(a0) 235 | sw a1, 52(a0) 236 | sw a1, 56(a0) 237 | sw a1, 60(a0) 238 | ret 239 | 240 | _check_stack: 241 | ######################################################################## 242 | # Check that our stack sentinels are there and that the stack is empty # 243 | ######################################################################## 244 | # repair the stack pointer if it's broken 245 | mv a0, sp 246 | la sp, _stack_ptr 247 | bne a0, sp, 2f 248 | 249 | la a0, _stack_start_sentinel 250 | addi a1, a0, 64 251 | li a2, 0xCAFEF00D 252 | 1: 253 | lw a3, 0(a0) 254 | bne a2, a3, 2f 255 | addi a0, a0, 4 256 | bne a0, a1, 1b 257 | 258 | la a0, _stack_end_sentinel 259 | addi a1, a0, 64 260 | li a2, 0xDECAFBAD 261 | 1: 262 | lw a3, 0(a0) 263 | bne a2, a3, 2f 264 | addi a0, a0, 4 265 | bne a0, a1, 1b 266 | # stack is fine 267 | mv a0, zero 268 | ret 269 | # stack corruption! 270 | 2: li a0, 1 271 | ret 272 | 273 | #ifndef LIBSPRINGBOK_NO_EXCEPTION_SUPPORT 274 | .weak exception_handler 275 | exception_handler: 276 | # Exception occurred 277 | # These strings are stored in instruction memory like 278 | # this so they can't ever be corrupted. 279 | li t0, 0x65637845 # "Exce" 280 | li t1, 0x6f697470 # "ptio" 281 | li t2, 0x636f206e # "n oc" 282 | li t3, 0x72727563 # "curr" 283 | li t4, 0x00006465 # "ed\0\0" 284 | addi sp, sp, -20 285 | sw t0, 0(sp) 286 | sw t1, 4(sp) 287 | sw t2, 8(sp) 288 | sw t3, 12(sp) 289 | sw t4, 16(sp) 290 | csrr a0, mcause 291 | li t6, 0 # ERROR logging level 292 | .word 0x00A10FFB # simprint t6, sp, a0 (encoded as custom3) 293 | addi sp, sp, 20 294 | # Store mcause as the reture value 295 | mv s0, a0 296 | call print_csrs 297 | # Restore the return value to be used in _finish 298 | mv a0, s0 299 | # Clear the stack 300 | la sp, _stack_ptr 301 | j _finish 302 | 303 | .weak print_csrs 304 | print_csrs: 305 | mret 306 | #endif 307 | -------------------------------------------------------------------------------- /springbok/springbok.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include "springbok.h" 17 | 18 | #ifndef LIBSPRINGBOK_NO_EXCEPTION_SUPPORT 19 | 20 | extern "C" void print_csrs(void) { 21 | uint32_t mcause; 22 | uint32_t mepc; 23 | uint32_t mtval; 24 | uint32_t misa; 25 | uint32_t mtvec; 26 | uint32_t mhartid; 27 | uint32_t marchid; 28 | uint32_t mvendorid; 29 | uint32_t mimpid; 30 | __asm__ volatile("csrr %[MCAUSE], mcause" 31 | : [MCAUSE] "=r"(mcause):); 32 | __asm__ volatile("csrr %[MEPC], mepc" 33 | : [MEPC] "=r"(mepc):); 34 | __asm__ volatile("csrr %[MTVAL], mtval" 35 | : [MTVAL] "=r"(mtval):); 36 | __asm__ volatile("csrr %[MISA], misa" 37 | : [MISA] "=r"(misa):); 38 | __asm__ volatile("csrr %[MTVEC], mtvec" 39 | : [MTVEC] "=r"(mtvec):); 40 | __asm__ volatile("csrr %[MHARTID], mhartid" 41 | : [MHARTID] "=r"(mhartid):); 42 | __asm__ volatile("csrr %[MARCHID], marchid" 43 | : [MARCHID] "=r"(marchid):); 44 | __asm__ volatile("csrr %[MVENDORID], mvendorid" 45 | : [MVENDORID] "=r"(mvendorid):); 46 | __asm__ volatile("csrr %[MIMPID], mimpid" 47 | : [MIMPID] "=r"(mimpid):); 48 | LOG_ERROR("MCAUSE:\t\t0x%08X", static_cast(mcause)); 49 | LOG_ERROR("MEPC:\t\t0x%08X", static_cast(mepc)); 50 | LOG_ERROR("MTVAL:\t\t0x%08X", static_cast(mtval)); 51 | LOG_ERROR("MISA:\t\t0x%08X", static_cast(misa)); 52 | LOG_ERROR("MTVEC:\t\t0x%08X", static_cast(mtvec)); 53 | LOG_ERROR("MHARTID:\t\t0x%08X", static_cast(mhartid)); 54 | LOG_ERROR("MARCHID:\t\t0x%08X", static_cast(marchid)); 55 | LOG_ERROR("MVENDORID:\t0x%08X", static_cast(mvendorid)); 56 | LOG_ERROR("MIMPID:\t\t0x%08X", static_cast(mimpid)); 57 | } 58 | 59 | #endif 60 | 61 | #ifndef LIBSPRINGBOK_NO_FLOAT_SUPPORT 62 | 63 | // Helper function for float_to_str. Copies a string into the output buffer. 64 | static void print_str(char *buffer, const int len, int *l, const char *str) { 65 | for (int i = 0; str[i] != '\0'; i++) { 66 | if (*l < len) { 67 | buffer[*l] = str[i]; 68 | } 69 | (*l)++; 70 | } 71 | } 72 | 73 | // Helper function for float_to_str. Copies a fixed-point decimal number up to 74 | // 16 digits long into the output buffer. 75 | static void print_fp_num(char *buffer, const int len, int *l, uint64_t abs_value, 76 | const bool negative, const int fixed_point) { 77 | uint8_t digits[16]; 78 | int i; 79 | 80 | for(i = 0; i < 16; i++) { 81 | digits[i] = abs_value % 10; 82 | abs_value /= 10; 83 | } 84 | for(i = 15; i > fixed_point; i--) { 85 | if (digits[i]) { 86 | break; 87 | } 88 | } 89 | if (negative) { 90 | if ((*l) < len) { 91 | buffer[*l] = '-'; 92 | } 93 | (*l)++; 94 | } 95 | for(; i >= 0; i--) { 96 | if(i == fixed_point-1) { 97 | if((*l) < len) { 98 | buffer[*l] = '.'; 99 | } 100 | (*l)++; 101 | } 102 | if((*l) < len) { 103 | buffer[*l] = digits[i] + '0'; 104 | } 105 | (*l)++; 106 | } 107 | } 108 | 109 | // This function converts a floating point value into a string. It doesn't rely 110 | // on any external library functions to do so, including string manipulation 111 | // functions. It's (probably) not good enough for production and may have bugs. 112 | // Always prints at least 7 significant figures, which is just slightly less 113 | // precise than single precision. 114 | // 115 | // Usage: 116 | // [Code] 117 | // int main(void) { 118 | // const float sorta_pi = 3.141592653589f; 119 | // int chars_needed = float_to_str(0, NULL, sorta_pi); 120 | // char *buffer = new char[chars_needed]; 121 | // float_to_str(chars_needed, buffer, sorta_pi); 122 | // printf("Pi is ~%s, %d characters printed\n", buffer, chars_needed); 123 | // delete[] buffer; 124 | // return 0; 125 | // } 126 | // 127 | // [Output] 128 | // Pi is 3.141592, 9 characters printed 129 | extern "C" int float_to_str(const int len, char *buffer, const float value) { 130 | if (buffer == NULL && len != 0) { 131 | // Bad inputs 132 | LOG_ERROR("float_to_str handed null buffer with non-zero length! len:%d", 133 | len); 134 | return 0; 135 | } 136 | 137 | int l = 0; 138 | 139 | union { 140 | float value; 141 | uint32_t raw; 142 | } conv = { .value = value }; 143 | 144 | const uint32_t raw_v = conv.raw; 145 | const uint32_t raw_absv = raw_v & UINT32_C(0x7FFFFFFF); 146 | const float absv = value < 0? -value : value; 147 | 148 | if (raw_absv > UINT32_C(0x7F800000)) { 149 | // NaN 150 | print_str(buffer, len, &l, "[NaN]"); 151 | 152 | } else if (raw_absv == UINT32_C(0x7F800000)) { 153 | // Infinity 154 | if (value > 0) { 155 | print_str(buffer, len, &l, "[+INF]"); 156 | } else { 157 | print_str(buffer, len, &l, "[-INF]"); 158 | } 159 | 160 | } else if (absv >= 1.f && absv < 10000000.f) { 161 | // Convert to 7.6 decimal fixed point and print 162 | print_fp_num(buffer, len, &l, static_cast(absv * 1000000.f), value < 0, 6); 163 | 164 | } else if (absv > 0) { 165 | // Scientific notation 166 | 167 | // The powers of ten from 10^-45 to 10^38 rounded downward and cast to 168 | // binary32. Each stored value holds the property of being the next value 169 | // lower or equal to the associated power of ten. 170 | const uint32_t kRawBucketStart[84] = { 171 | 0x00000000, 0x00000007, 0x00000047, 0x000002c9, 0x00001be0, 0x000116c2, 0x000ae397, 0x006ce3ee, 172 | 0x02081cea, 0x03aa2424, 0x0554ad2d, 0x0704ec3c, 0x08a6274b, 0x0a4fb11e, 0x0c01ceb3, 0x0da2425f, 173 | 0x0f4ad2f7, 0x10fd87b5, 0x129e74d1, 0x14461206, 0x15f79687, 0x179abe14, 0x19416d9a, 0x1af1c900, 174 | 0x1c971da0, 0x1e3ce508, 0x1fec1e4a, 0x219392ee, 0x233877aa, 0x24e69594, 0x26901d7c, 0x283424dc, 175 | 0x29e12e13, 0x2b8cbccc, 0x2d2febff, 0x2edbe6fe, 0x3089705f, 0x322bcc77, 0x33d6bf94, 0x358637bd, 176 | 0x3727c5ac, 0x38d1b717, 0x3a83126e, 0x3c23d70a, 0x3dcccccc, 0x3f7fffff, 0x411fffff, 0x42c7ffff, 177 | 0x4479ffff, 0x461c3fff, 0x47c34fff, 0x497423ff, 0x4b18967f, 0x4cbebc1f, 0x4e6e6b27, 0x501502f8, 178 | 0x51ba43b7, 0x5368d4a5, 0x551184e7, 0x56b5e620, 0x58635fa9, 0x5a0e1bc9, 0x5bb1a2bc, 0x5d5e0b6b, 179 | 0x5f0ac723, 0x60ad78eb, 0x6258d726, 0x64078678, 0x65a96816, 0x6753c21b, 0x69045951, 0x6aa56fa5, 180 | 0x6c4ecb8f, 0x6e013f39, 0x6fa18f07, 0x7149f2c9, 0x72fc6f7c, 0x749dc5ad, 0x76453719, 0x77f684df, 181 | 0x799a130b, 0x7b4097ce, 0x7cf0bdc2, 0x7e967699, 182 | }; 183 | // The inverse powers of ten from 10^45 to 10^-38. The 32 values from each 184 | // edge are scaled up and down by 2^32 to keep them from becoming 185 | // denormalized or infinity. Since this is a power of 2, it will not affect 186 | // numerical accuracy. 187 | const uint32_t kRawBucketScale[84] = { 188 | 0x7a335dbf, 0x788f7e32, 0x76e596b7, 0x7537abc6, 0x7392efd1, 0x71eb194f, 0x703c143f, 0x6e967699, 189 | 0x6cf0bdc2, 0x6b4097cf, 0x699a130c, 0x67f684df, 0x66453719, 0x649dc5ae, 0x62fc6f7c, 0x6149f2ca, 190 | 0x5fa18f08, 0x5e013f3a, 0x5c4ecb8f, 0x5aa56fa6, 0x59045952, 0x5753c21c, 0x55a96816, 0x54078678, 191 | 0x5258d726, 0x50ad78ec, 0x4f0ac723, 0x4d5e0b6b, 0x4bb1a2bc, 0x4a0e1bca, 0x48635faa, 0x46b5e621, 192 | 0x551184e7, 0x5368d4a5, 0x51ba43b7, 0x501502f9, 0x4e6e6b28, 0x4cbebc20, 0x4b189680, 0x49742400, 193 | 0x47c35000, 0x461c4000, 0x447a0000, 0x42c80000, 0x41200000, 0x3f800000, 0x3dcccccd, 0x3c23d70b, 194 | 0x3a83126f, 0x38d1b718, 0x3727c5ad, 0x358637be, 0x43d6bf95, 0x422bcc78, 0x40897060, 0x3edbe6ff, 195 | 0x3d2febff, 0x3b8cbccc, 0x39e12e13, 0x383424dd, 0x36901d7d, 0x34e69595, 0x333877aa, 0x319392ef, 196 | 0x2fec1e4a, 0x2e3ce509, 0x2c971da1, 0x2af1c900, 0x29416d9a, 0x279abe15, 0x25f79687, 0x24461206, 197 | 0x229e74d2, 0x20fd87b5, 0x1f4ad2f8, 0x1da24260, 0x1c01ceb3, 0x1a4fb11f, 0x18a6274b, 0x1704ec3d, 198 | 0x1554ad2e, 0x13aa2425, 0x12081cea, 0x1059c7dc, 199 | }; 200 | const float *bucket_start = reinterpret_cast(kRawBucketStart); 201 | const float *bucket_scale = reinterpret_cast(kRawBucketScale); 202 | 203 | // Search and find the first smaller power of 10. 204 | int e; 205 | for(e = 38; e >= -45; e--) { 206 | if (bucket_start[e+45] < absv) { 207 | break; 208 | } 209 | } 210 | const int abs_e = e < 0 ? -e : e; 211 | 212 | // Prescale by 2^32 if the power of 10 is too large or small. 213 | float scaled_absv = absv; 214 | if (e < -45+32) { 215 | scaled_absv *= 4294967296.f; // exactly 2^32 216 | } else if (e >= 39-32) { 217 | scaled_absv *= 0.00000000023283064365386962890625; // exactly 2^-32 218 | } 219 | 220 | // Scale by the inverse power of 10. The scales by 2^32 will cancel out 221 | // and provide a value in the range of [1, 10). 222 | scaled_absv *= bucket_scale[e+45]; 223 | 224 | // Print as a signed 1.6 decimal fixed-point value with signed exponent. 225 | print_fp_num(buffer, len, &l, static_cast(scaled_absv * 1000000.f), value < 0, 6); 226 | print_str(buffer, len, &l, "e"); 227 | print_fp_num(buffer, len, &l, abs_e, e < 0, 0); 228 | 229 | } else { 230 | // Exactly 0 231 | print_fp_num(buffer, len, &l, 0, false, 0); 232 | } 233 | 234 | // Add a null terminator, even if there isn't room. 235 | if (l < len) { 236 | buffer[l] = '\0'; 237 | } else if (len > 0) { 238 | buffer[len-1] = '\0'; 239 | } 240 | l++; 241 | 242 | // Return the number of characters needed for display. 243 | return l; 244 | } 245 | 246 | #else // defined(LIBSPRINGBOK_NO_FLOAT_SUPPORT) 247 | 248 | extern "C" int float_to_str(const int len, char *buffer, const float value) { 249 | // Dummy function since float support is disabled in libspringbok 250 | LOG_ERROR("float_to_str is disabled because libspringbok was compiled without float support"); 251 | return 0; 252 | } 253 | 254 | #endif 255 | -------------------------------------------------------------------------------- /samples/util/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // An example based on iree/samples/simple_embedding. 18 | 19 | #include "samples/util/util.h" 20 | 21 | #include 22 | 23 | #include "iree/modules/hal/inline/module.h" 24 | #include "iree/modules/hal/loader/module.h" 25 | #include "samples/device/device.h" 26 | 27 | typedef struct { 28 | uint32_t return_code; // Populated in crt0.S 29 | uint32_t epc; // Populated in crt0.S 30 | uint32_t length; 31 | } OutputHeader; 32 | 33 | OutputHeader output_header; 34 | 35 | extern const MlModel kModel; 36 | 37 | // Create context that will hold the module state across invocations. 38 | static iree_status_t create_context(iree_vm_instance_t *instance, 39 | iree_hal_device_t **device, 40 | iree_vm_context_t **context) { 41 | iree_allocator_t host_allocator = iree_allocator_system(); 42 | iree_status_t result = iree_vm_instance_create(host_allocator, &instance); 43 | 44 | #if defined(BUILD_INLINE_HAL) 45 | IREE_RETURN_IF_ERROR(iree_hal_module_register_inline_types(instance)); 46 | #elif defined(BUILD_LOADER_HAL) 47 | IREE_RETURN_IF_ERROR(iree_hal_module_register_loader_types(instance)); 48 | #else 49 | IREE_RETURN_IF_ERROR(iree_hal_module_register_all_types(instance)); 50 | #endif 51 | 52 | iree_hal_executable_loader_t *loader = NULL; 53 | if (iree_status_is_ok(result)) { 54 | result = create_sample_device(host_allocator, device, &loader); 55 | } 56 | 57 | // Load bytecode or C module. 58 | iree_vm_module_t *module = NULL; 59 | if (iree_status_is_ok(result)) { 60 | result = create_module(instance, &module); 61 | } 62 | 63 | #if defined(BUILD_INLINE_HAL) || defined(BUILD_LOADER_HAL) 64 | // Create hal_inline_module 65 | iree_vm_module_t *hal_inline_module = NULL; 66 | if (iree_status_is_ok(result)) { 67 | result = iree_hal_inline_module_create( 68 | instance, IREE_HAL_INLINE_MODULE_FLAG_NONE, 69 | iree_hal_device_allocator(*device), host_allocator, &hal_inline_module); 70 | } 71 | #endif 72 | #if defined(BUILD_INLINE_HAL) 73 | iree_vm_module_t *modules[] = {hal_inline_module, module}; 74 | #elif defined(BUILD_LOADER_HAL) 75 | // Create hal_loader_module 76 | iree_vm_module_t *hal_loader_module = NULL; 77 | if (iree_status_is_ok(result)) { 78 | result = iree_hal_loader_module_create(instance, IREE_HAL_MODULE_FLAG_NONE, 79 | /*loader_count=*/1, &loader, 80 | host_allocator, &hal_loader_module); 81 | } 82 | iree_vm_module_t *modules[] = {hal_inline_module, hal_loader_module, module}; 83 | #else 84 | // Create hal_module 85 | iree_vm_module_t *hal_module = NULL; 86 | if (iree_status_is_ok(result)) { 87 | result = 88 | iree_hal_module_create(instance, *device, IREE_HAL_MODULE_FLAG_NONE, 89 | host_allocator, &hal_module); 90 | } 91 | iree_vm_module_t *modules[] = {hal_module, module}; 92 | #endif 93 | iree_hal_executable_loader_release(loader); 94 | 95 | // Allocate a context that will hold the module state across invocations. 96 | if (iree_status_is_ok(result)) { 97 | result = iree_vm_context_create_with_modules( 98 | instance, IREE_VM_CONTEXT_FLAG_NONE, IREE_ARRAYSIZE(modules), 99 | &modules[0], host_allocator, context); 100 | } 101 | #if defined(BUILD_INLINE_HAL) || defined(BUILD_LOADER_HAL) 102 | iree_vm_module_release(hal_inline_module); 103 | #else 104 | iree_vm_module_release(hal_module); 105 | #endif 106 | #if defined(BUILD_LOADER_HAL) 107 | iree_vm_module_release(hal_loader_module); 108 | #endif 109 | iree_vm_module_release(module); 110 | return result; 111 | } 112 | 113 | // Prepare the input buffers and buffer_views based on the data type. They must 114 | // be released by the caller. 115 | static iree_status_t prepare_input_hal_buffer_views( 116 | const MlModel *model, iree_hal_device_t *device, void **arg_buffers, 117 | iree_hal_buffer_view_t **arg_buffer_views) { 118 | iree_status_t result = iree_ok_status(); 119 | 120 | // Prepare the input buffer, and populate the initial value. 121 | // The input buffer must be released by the caller. 122 | iree_const_byte_span_t *byte_span[MAX_MODEL_INPUT_NUM] = {NULL}; 123 | result = load_input_data(model, arg_buffers, byte_span); 124 | 125 | // Wrap buffers in shaped buffer views. 126 | // The buffers can be mapped on the CPU and that can also be used 127 | // on the device. Not all devices support this, but the ones we have now do. 128 | 129 | iree_hal_buffer_params_t buffer_params = { 130 | .type = 131 | IREE_HAL_MEMORY_TYPE_HOST_LOCAL | IREE_HAL_MEMORY_TYPE_DEVICE_VISIBLE, 132 | .access = IREE_HAL_MEMORY_ACCESS_READ, 133 | .usage = IREE_HAL_BUFFER_USAGE_DEFAULT}; 134 | for (int i = 0; i < model->num_input; ++i) { 135 | if (iree_status_is_ok(result)) { 136 | result = iree_hal_buffer_view_allocate_buffer( 137 | iree_hal_device_allocator(device), model->num_input_dim[i], 138 | model->input_shape[i], model->hal_element_type, 139 | IREE_HAL_ENCODING_TYPE_DENSE_ROW_MAJOR, buffer_params, *byte_span[i], 140 | &(arg_buffer_views[i])); 141 | } 142 | if (byte_span[i] != NULL) { 143 | free(byte_span[i]); 144 | } 145 | } 146 | return result; 147 | } 148 | 149 | iree_status_t run(const MlModel *model) { 150 | iree_vm_instance_t *instance = NULL; 151 | iree_hal_device_t *device = NULL; 152 | iree_vm_context_t *context = NULL; 153 | // create context 154 | iree_status_t result = create_context(instance, &device, &context); 155 | 156 | // Lookup the entry point function. 157 | // Note that we use the synchronous variant which operates on pure type/shape 158 | // erased buffers. 159 | iree_vm_function_t main_function; 160 | if (iree_status_is_ok(result)) { 161 | result = (iree_vm_context_resolve_function( 162 | context, iree_make_cstring_view(model->entry_func), &main_function)); 163 | } 164 | 165 | // Prepare the input buffers. 166 | void *arg_buffers[MAX_MODEL_INPUT_NUM] = {NULL}; 167 | iree_hal_buffer_view_t *arg_buffer_views[MAX_MODEL_INPUT_NUM] = {NULL}; 168 | if (iree_status_is_ok(result)) { 169 | result = prepare_input_hal_buffer_views(model, device, arg_buffers, 170 | arg_buffer_views); 171 | } 172 | 173 | // Setup call inputs with our buffers. 174 | iree_vm_list_t *inputs = NULL; 175 | if (iree_status_is_ok(result)) { 176 | result = iree_vm_list_create( 177 | /*element_type=*/NULL, /*capacity=*/model->num_input, 178 | iree_allocator_system(), &inputs); 179 | } 180 | iree_vm_ref_t arg_buffer_view_ref; 181 | for (int i = 0; i < model->num_input; ++i) { 182 | arg_buffer_view_ref = iree_hal_buffer_view_move_ref(arg_buffer_views[i]); 183 | if (iree_status_is_ok(result)) { 184 | result = iree_vm_list_push_ref_move(inputs, &arg_buffer_view_ref); 185 | } 186 | } 187 | 188 | // Prepare outputs list to accept the results from the invocation. 189 | // The output vm list is allocated statically. 190 | iree_vm_list_t *outputs = NULL; 191 | if (iree_status_is_ok(result)) { 192 | result = iree_vm_list_create( 193 | /*element_type=*/NULL, 194 | /*capacity=*/1, iree_allocator_system(), &outputs); 195 | } 196 | 197 | // Invoke the function. 198 | if (iree_status_is_ok(result)) { 199 | result = iree_vm_invoke(context, main_function, IREE_VM_CONTEXT_FLAG_NONE, 200 | /*policy=*/NULL, inputs, outputs, 201 | iree_allocator_system()); 202 | } 203 | 204 | // Validate output and gather buffers. 205 | iree_hal_buffer_mapping_t mapped_memories[MAX_MODEL_OUTPUTS] = {{0}}; 206 | for (int index_output = 0; index_output < model->num_output; index_output++) { 207 | iree_hal_buffer_view_t *ret_buffer_view = NULL; 208 | if (iree_status_is_ok(result)) { 209 | // Get the result buffers from the invocation. 210 | ret_buffer_view = (iree_hal_buffer_view_t *)iree_vm_list_get_ref_deref( 211 | outputs, index_output, iree_hal_buffer_view_get_descriptor()); 212 | if (ret_buffer_view == NULL) { 213 | result = iree_make_status(IREE_STATUS_NOT_FOUND, 214 | "can't find return buffer view"); 215 | } 216 | } 217 | if (iree_status_is_ok(result)) { 218 | result = iree_hal_buffer_map_range( 219 | iree_hal_buffer_view_buffer(ret_buffer_view), 220 | IREE_HAL_MAPPING_MODE_SCOPED, IREE_HAL_MEMORY_ACCESS_READ, 0, 221 | IREE_WHOLE_BUFFER, &mapped_memories[index_output]); 222 | } 223 | 224 | if (iree_status_is_ok(result)) { 225 | if (index_output > model->num_output || 226 | mapped_memories[index_output].contents.data_length / 227 | model->output_size_bytes != 228 | model->output_length[index_output]) { 229 | result = 230 | iree_make_status(IREE_STATUS_UNKNOWN, "output length mismatches"); 231 | } 232 | } 233 | } 234 | 235 | // Post-process memory into model output. 236 | if (iree_status_is_ok(result)) { 237 | uint32_t length = 0; 238 | result = process_output(model, mapped_memories, &length); 239 | output_header.length = length; 240 | } 241 | 242 | for (int index_output = 0; index_output < model->num_output; index_output++) { 243 | if (mapped_memories[index_output].contents.data != NULL) { 244 | iree_hal_buffer_unmap_range(&mapped_memories[index_output]); 245 | } 246 | } 247 | iree_vm_list_release(inputs); 248 | iree_vm_list_release(outputs); 249 | for (int i = 0; i < model->num_input; ++i) { 250 | if (arg_buffers[i] != NULL) { 251 | free(arg_buffers[i]); 252 | } 253 | } 254 | iree_vm_context_release(context); 255 | IREE_IGNORE_ERROR(iree_hal_allocator_statistics_fprint( 256 | stdout, iree_hal_device_allocator(device))); 257 | iree_hal_device_release(device); 258 | iree_vm_instance_release(instance); 259 | return result; 260 | } 261 | 262 | int main() { 263 | const MlModel *model_ptr = &kModel; 264 | const iree_status_t result = run(model_ptr); 265 | int ret = (int)iree_status_code(result); 266 | if (!iree_status_is_ok(result)) { 267 | iree_status_fprint(stderr, result); 268 | iree_status_free(result); 269 | } else { 270 | LOG_INFO("%s finished successfully", model_ptr->model_name); 271 | } 272 | 273 | return ret; 274 | } 275 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /sim/config/infrastructure/SpringbokRiscV32.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | using System; 16 | using System.Linq; 17 | using System.Text; 18 | 19 | using Antmicro.Renode.Core; 20 | using Antmicro.Renode.Core.Structure.Registers; 21 | using Antmicro.Renode.Logging; 22 | using Antmicro.Renode.Peripherals.Bus; 23 | using Antmicro.Renode.Peripherals.Memory; 24 | using Antmicro.Renode.Peripherals.Timers; 25 | using Antmicro.Renode.Utilities; 26 | using Antmicro.Renode.Utilities.Binding; 27 | 28 | using Endianess = ELFSharp.ELF.Endianess; 29 | 30 | namespace Antmicro.Renode.Peripherals.CPU 31 | { 32 | public class SpringbokRiscV32 : RiscV32 33 | { 34 | public SpringbokRiscV32(Core.Machine machine, 35 | uint hartId = 0, 36 | PrivilegeArchitecture privilegeArchitecture = PrivilegeArchitecture.Priv1_11, 37 | Endianess endianness = Endianess.LittleEndian, 38 | string cpuType = "rv32imfv") 39 | : base(null, cpuType, machine, hartId, privilegeArchitecture, endianness) 40 | { 41 | RegisterCustomCSRs(); 42 | 43 | // funct7 ------- 44 | // rs2 ----- 45 | // rs1 ----- 46 | // funct3 --- 47 | // rd ----- 48 | InstallCustomInstruction(pattern: "-------------------------1111011", handler: HandleSpringbokCustom3); // custom-3 49 | 50 | Reset(); 51 | // Placing these before reset results in them being reset (this is not intended behavior) 52 | // These should be moved withing Tlib out of the reset function. 53 | VectorRegisterLength = 512; 54 | VectorElementMaxWidth = 32; 55 | } 56 | 57 | public override void Reset() 58 | { 59 | base.Reset(); 60 | 61 | // This core comes out of reset paused. 62 | this.IsHalted = true; 63 | 64 | if(ControlBlockRegistered) 65 | { 66 | ControlBlock.Reset(); 67 | } 68 | } 69 | 70 | public void RegisterControlBlock(SpringbokRiscV32_ControlBlock controlBlock) 71 | { 72 | ControlBlock = controlBlock; 73 | ControlBlockRegistered = true; 74 | } 75 | 76 | private SpringbokRiscV32_ControlBlock ControlBlock; 77 | private bool ControlBlockRegistered = false; 78 | 79 | private void HandleSpringbokCustom3(UInt64 opcode) 80 | { 81 | int rd = (int)BitHelper.GetValue(opcode, 7, 5); 82 | int funct3 = (int)BitHelper.GetValue(opcode, 12, 3); 83 | int rs1 = (int)BitHelper.GetValue(opcode, 15, 5); 84 | int rs2 = (int)BitHelper.GetValue(opcode, 20, 5); 85 | 86 | switch(funct3) 87 | { 88 | case 0: 89 | // simprint 90 | // rd is logging level 91 | // rs1 is pointer to null-terminated string to print 92 | // rs2 is number to print 93 | int levelNum = (int)(X[rd].RawValue); 94 | LogLevel level = LogLevel.Error; 95 | 96 | switch(levelNum) 97 | { 98 | case 0: 99 | level = LogLevel.Error; 100 | break; 101 | case 1: 102 | level = LogLevel.Warning; 103 | break; 104 | case 2: 105 | level = LogLevel.Info; 106 | break; 107 | case 3: 108 | level = LogLevel.Debug; 109 | break; 110 | case 4: 111 | level = LogLevel.Noisy; 112 | break; 113 | default: 114 | this.Log(LogLevel.Error, "Unrecognized logging level for simprint instruction! {0}: {1}", rd, levelNum); 115 | return; 116 | } 117 | 118 | uint messagePtr = (uint)(X[rs1].RawValue); 119 | uint number = (uint)(X[rs2].RawValue); 120 | 121 | byte[] messageArray = new byte[256]; 122 | 123 | for(int i = 0; i < 255; i++) 124 | { 125 | messageArray[i] = (byte)(ReadByteFromBus(messagePtr++) & 127); // Just in case we read garbage, let's restrict it to ASCII garbage. 126 | if(messageArray[i] == 0) 127 | { 128 | break; 129 | } 130 | } 131 | 132 | String message = Encoding.ASCII.GetString(messageArray).TrimEnd((Char)0); 133 | 134 | this.Log(level, "simprint: \"{0}\", {1} (0x{1:X})", message, number); 135 | 136 | break; 137 | case 1: 138 | // xcount 139 | switch(rs1) 140 | { 141 | case 0: 142 | // icount 143 | X[rd] = ExecutedInstructions; 144 | break; 145 | case 1: 146 | // ccount 147 | // Renode simulates one cycle per instruction 148 | X[rd] = ExecutedInstructions; 149 | break; 150 | default: 151 | this.Log(LogLevel.Error, "xcount: unrecognized source: {0} (0x{0:X})", rs1); 152 | break; 153 | } 154 | break; 155 | case 2: 156 | // hostreq 157 | if(ControlBlockRegistered) 158 | { 159 | ControlBlock.ExecHostReq(); 160 | } 161 | break; 162 | case 3: 163 | // finish 164 | if(ControlBlockRegistered) 165 | { 166 | ControlBlock.ExecFinish(); 167 | } 168 | break; 169 | default: 170 | // Unrecognized 171 | this.Log(LogLevel.Error, "custom-3: unrecognized funct3: {0} (0x{0:X})", funct3); 172 | break; 173 | } 174 | } 175 | 176 | private void RegisterCustomCSRs() 177 | { 178 | // validate only privilege level when accessing CSRs 179 | // do not validate rw bit as VexRiscv custom CSRs do not follow the standard 180 | CSRValidation = CSRValidationLevel.None; 181 | 182 | RegisterCSR((ulong)CSRs.InstructionCount, () => InstructionCountCSRRead("InstructionCount"), value => { }); 183 | RegisterCSR((ulong)CSRs.CycleCount, () => InstructionCountCSRRead("CycleCount"), value => { }); 184 | } 185 | 186 | private ulong InstructionCountCSRRead(string name) 187 | { 188 | this.Log(LogLevel.Noisy, "Reading instruction count CSR {0} 0x{1:X}", name, ExecutedInstructions); 189 | ulong count = ExecutedInstructions; 190 | return count; 191 | } 192 | 193 | private enum CSRs 194 | { 195 | InstructionCount = 0x7C0, 196 | CycleCount = 0x7C1, 197 | } 198 | } 199 | 200 | public class SpringbokRiscV32_ControlBlock : 201 | IDoubleWordPeripheral, 202 | IProvidesRegisterCollection, 203 | IKnownSize 204 | { 205 | 206 | public SpringbokRiscV32_ControlBlock(Machine machine, 207 | SpringbokRiscV32 core, 208 | MappedMemory imem, 209 | MappedMemory dmem) 210 | { 211 | Machine = machine; 212 | Core = core; 213 | IMem = imem; 214 | DMem = dmem; 215 | 216 | HostReqIRQ = new GPIO(); 217 | FinishIRQ = new GPIO(); 218 | InstructionFaultIRQ = new GPIO(); 219 | DataFaultIRQ = new GPIO(); 220 | 221 | Core.RegisterControlBlock(this); 222 | 223 | RegistersCollection = new DoubleWordRegisterCollection(this); 224 | DefineRegisters(); 225 | 226 | Reset(); 227 | } 228 | 229 | public void Reset() 230 | { 231 | mode = Mode.Freeze | Mode.SwReset; 232 | RegistersCollection.Reset(); 233 | } 234 | 235 | private void DefineRegisters() 236 | { 237 | Registers.IntrState.Define32(this) 238 | .WithValueField(0, 4, 239 | writeCallback: (_, value) => { 240 | this.Log(LogLevel.Noisy, "Got {0} to clear IRQ pending bits", value); 241 | irqsPending = irqsPending & ~(InterruptBits)value; 242 | IrqUpdate(); 243 | }, 244 | valueProviderCallback: (_) => { 245 | return (uint)irqsPending; 246 | }) 247 | ; 248 | 249 | Registers.IntrEnable.Define32(this) 250 | .WithValueField(0, 4, 251 | writeCallback: (_, value) => { 252 | this.Log(LogLevel.Noisy, "Got {0} to write IRQ enable bits", value); 253 | irqsEnabled = (InterruptBits)value & InterruptBits.Mask; 254 | IrqUpdate(); 255 | }, 256 | valueProviderCallback: (_) => { 257 | return (uint)irqsEnabled; 258 | }) 259 | ; 260 | 261 | Registers.IntrTest.Define32(this) 262 | .WithValueField(0, 4, 263 | writeCallback: (_, value) => { 264 | this.Log(LogLevel.Noisy, "Got {0} to set IRQ pending bits", value); 265 | irqsPending = irqsPending | ((InterruptBits)value & InterruptBits.Mask); 266 | IrqUpdate(); 267 | }) 268 | ; 269 | 270 | Registers.Control.Define32(this, resetValue: 0x00000003) 271 | .WithValueField(0, 19, name: "FREEZE_VC_RESET_PC_START", writeCallback: (_, val) => 272 | { 273 | Mode newMode = (Mode)val & Mode.Mask; 274 | 275 | // Pause the core when either freeze or swreset is asserted. 276 | if ((mode == Mode.Run) && (newMode != Mode.Run)) 277 | { 278 | this.Log(LogLevel.Noisy, "Pausing core."); 279 | Core.IsHalted = true; 280 | } 281 | 282 | // Trigger the core's reset when SwReset is deasserted. 283 | if (((mode & Mode.SwReset) != 0) && ((newMode & Mode.SwReset) == 0)) 284 | { 285 | this.Log(LogLevel.Noisy, "Resetting core."); 286 | Core.Reset(); 287 | ulong startAddress = (val & ~(ulong)Mode.Mask) + Machine.SystemBus.GetRegistrationPoints(IMem, Core).First().Range.StartAddress; 288 | this.Log(LogLevel.Noisy, "Setting PC to 0x{0:X}.", startAddress); 289 | Core.PC = startAddress; 290 | } 291 | 292 | // Unpause the core when both freeze and SwReset are deasserted. 293 | if ((mode != Mode.Run) && (newMode == Mode.Run)) 294 | { 295 | this.Log(LogLevel.Noisy, "Resuming core."); 296 | Core.IsHalted = false; 297 | 298 | Core.Resume(); 299 | } 300 | 301 | this.mode = newMode; 302 | }) 303 | .WithIgnoredBits(19, 32 - 19); 304 | 305 | // To-do: Not sure how to implement disablable memory banks. 306 | Registers.MemoryBankControl.Define32(this) 307 | .WithValueField(0, 4, out InstructionMemoryEnable, name: "I_MEM_ENABLE") 308 | .WithValueField(4, 8, out DataMemoryEnable, name: "D_MEM_ENABLE") 309 | .WithIgnoredBits(12, 32 - 12); 310 | 311 | // To-do: Not sure how to implement memory access range checks. 312 | Registers.ErrorStatus.Define32(this) 313 | .WithFlag(0, name: "I_MEM_OUT_OF_RANGE") 314 | .WithFlag(1, name: "D_MEM_OUT_OF_RANGE") 315 | .WithValueField(2, 4, out InstructionMemoryDisableAccess, name: "I_MEM_DISABLE_ACCESS") 316 | .WithValueField(6, 8, out DataMemoryDisableAccess, name: "D_MEM_DISABLE_ACCESS") 317 | .WithIgnoredBits(14, 32 - 14); 318 | 319 | Registers.InitStart.Define32(this) 320 | .WithValueField(0, 22, out InitStartAddress, name: "ADDRESS") 321 | .WithFlag(22, out InitMemSelect, name: "IMEM_DMEM_SEL") 322 | .WithIgnoredBits(23, 32 - 23); 323 | 324 | Registers.InitEnd.Define32(this) 325 | .WithValueField(0, 22, out InitEndAddress, name: "ADDRESS") 326 | .WithFlag(22, name: "VALID", mode: FieldMode.Read | FieldMode.Write, writeCallback: (_, val) => 327 | { 328 | // If valid, do the memory clear. 329 | if (val) 330 | { 331 | InitStatusPending.Value = true; 332 | InitStatusDone.Value = false; 333 | Machine.LocalTimeSource.ExecuteInNearestSyncedState( __ => { 334 | if (InitMemSelect.Value) 335 | { 336 | var instructionPageMask = ~((ulong)(InstructionPageSize - 1)); 337 | for(ulong writeAddress = InitStartAddress.Value & instructionPageMask; 338 | writeAddress < ((InitEndAddress.Value + InstructionPageSize - 1) & instructionPageMask); 339 | writeAddress += InstructionPageSize) 340 | { 341 | IMem.WriteBytes((long)writeAddress, InstructionErasePattern, 0, InstructionPageSize); 342 | } 343 | } 344 | else 345 | { 346 | var dataPageMask = ~((ulong)(DataPageSize - 1)); 347 | for(ulong writeAddress = InitStartAddress.Value & dataPageMask; 348 | writeAddress < ((InitEndAddress.Value + DataPageSize - 1) & dataPageMask); 349 | writeAddress += DataPageSize) 350 | { 351 | DMem.WriteBytes((long)writeAddress, DataErasePattern, 0, DataPageSize); 352 | } 353 | } 354 | InitStatusPending.Value = false; 355 | InitStatusDone.Value = true; 356 | } ); 357 | } 358 | }) 359 | .WithIgnoredBits(23, 32 - 23); 360 | Registers.InitStatus.Define32(this) 361 | .WithFlag(0, out InitStatusPending, name: "INIT_PENDING") 362 | .WithFlag(1, out InitStatusDone, name: "INIT_DONE") 363 | .WithIgnoredBits(2, 32 - 2); 364 | } 365 | 366 | public virtual uint ReadDoubleWord(long offset) 367 | { 368 | return RegistersCollection.Read(offset); 369 | 370 | } 371 | 372 | public virtual void WriteDoubleWord(long offset, uint value) 373 | { 374 | RegistersCollection.Write(offset, value); 375 | } 376 | 377 | public void ExecHostReq() 378 | { 379 | // Pause the core and trigger a host interrupt signaling a request 380 | if (mode == Mode.Run) 381 | { 382 | this.Log(LogLevel.Noisy, "Pausing core for host request."); 383 | } 384 | else 385 | { 386 | this.Log(LogLevel.Error, "Pausing core for host request, but core was not expected to be running. Did you clear IsHalted manually?"); 387 | } 388 | Core.IsHalted = true; 389 | mode = Mode.Freeze; 390 | irqsPending |= InterruptBits.HostReq; 391 | IrqUpdate(); 392 | } 393 | 394 | public void ExecFinish() 395 | { 396 | // Pause, reset the core (actual reset occurs when SwReset is cleared) and trigger a host interrupt indicating completion 397 | if (mode == Mode.Run) 398 | { 399 | this.Log(LogLevel.Noisy, "Pausing and resetting core for host completion notification."); 400 | } 401 | else 402 | { 403 | this.Log(LogLevel.Error, "Pausing and resetting core for host completion notification, but core was not expected to be running. Did you clear IsHalted manually?"); 404 | } 405 | Core.IsHalted = true; 406 | mode = Mode.Freeze | Mode.SwReset; 407 | irqsPending |= InterruptBits.Finish; 408 | IrqUpdate(); 409 | } 410 | 411 | private void ExecFault(FaultType faultType) 412 | { 413 | // Pause, reset the core (actual reset occurs when SwReset is cleared) and trigger a host interrupt indicating a fault 414 | if (mode == Mode.Run) 415 | { 416 | this.Log(LogLevel.Noisy, "Pausing and resetting core for fault notification."); 417 | } 418 | else 419 | { 420 | this.Log(LogLevel.Error, "Pausing and resetting core for fault notification, but core was not expected to be running. Did you clear IsHalted manually?"); 421 | } 422 | Core.IsHalted = true; 423 | mode = Mode.Freeze | Mode.SwReset; 424 | switch (faultType) 425 | { 426 | case FaultType.InstructionFetch: 427 | irqsPending |= InterruptBits.InstructionFault; 428 | IrqUpdate(); 429 | return; 430 | case FaultType.DataAccess: 431 | irqsPending |= InterruptBits.DataFault; 432 | IrqUpdate(); 433 | return; 434 | default: 435 | this.Log(LogLevel.Error, "Unknown fault type!"); 436 | return; 437 | } 438 | } 439 | 440 | public DoubleWordRegisterCollection RegistersCollection { get; private set; } 441 | 442 | public GPIO HostReqIRQ { get; } 443 | public GPIO FinishIRQ { get; } 444 | public GPIO InstructionFaultIRQ { get; } 445 | public GPIO DataFaultIRQ { get; } 446 | 447 | private InterruptBits irqsEnabled; 448 | private InterruptBits irqsPending; 449 | 450 | private void IrqUpdate() 451 | { 452 | InterruptBits irqsPassed = irqsEnabled & irqsPending; 453 | HostReqIRQ.Set((irqsPassed & InterruptBits.HostReq) != 0); 454 | FinishIRQ.Set((irqsPassed & InterruptBits.Finish) != 0); 455 | InstructionFaultIRQ.Set((irqsPassed & InterruptBits.InstructionFault) != 0); 456 | DataFaultIRQ.Set((irqsPassed & InterruptBits.DataFault) != 0); 457 | } 458 | 459 | // To-do: Set the erase pattern to what the hardware actually does. 0x5A is 460 | // only for debugging purposes. 461 | private const int InstructionPageSize = 4; 462 | private readonly byte[] InstructionErasePattern = (byte[])Enumerable.Repeat((byte)0x5A, InstructionPageSize).ToArray(); 463 | private const int DataPageSize = 64; 464 | private readonly byte[] DataErasePattern = (byte[])Enumerable.Repeat((byte)0x5A, DataPageSize).ToArray(); 465 | 466 | // Disable unused variable warnings. These warnings will go away on their 467 | // their own when each register's behavior is implemented. 468 | #pragma warning disable 414 469 | private IValueRegisterField InstructionMemoryEnable; 470 | private IValueRegisterField DataMemoryEnable; 471 | private IValueRegisterField InstructionMemoryDisableAccess; 472 | private IValueRegisterField DataMemoryDisableAccess; 473 | private IValueRegisterField InitStartAddress; 474 | private IFlagRegisterField InitMemSelect; 475 | private IValueRegisterField InitEndAddress; 476 | private IFlagRegisterField InitStatusPending; 477 | private IFlagRegisterField InitStatusDone; 478 | #pragma warning restore 414 479 | 480 | private Mode mode; 481 | private readonly Machine Machine; 482 | private readonly SpringbokRiscV32 Core; 483 | private readonly MappedMemory IMem; 484 | private readonly MappedMemory DMem; 485 | 486 | // Length of register space. 487 | public long Size => 0x400; 488 | private enum Registers 489 | { 490 | IntrState = 0x00, 491 | IntrEnable = 0x04, 492 | IntrTest = 0x08, 493 | Control = 0x0C, 494 | MemoryBankControl = 0x10, 495 | ErrorStatus = 0x14, 496 | InitStart = 0x18, 497 | InitEnd = 0x1C, 498 | InitStatus = 0x20, 499 | }; 500 | [Flags] 501 | private enum Mode 502 | { 503 | Run = 0x00, 504 | Freeze = 0x01, 505 | SwReset = 0x02, 506 | Mask = 0x03, 507 | }; 508 | private enum FaultType 509 | { 510 | InstructionFetch, 511 | DataAccess, 512 | }; 513 | [Flags] 514 | private enum InterruptBits 515 | { 516 | HostReq = 1, 517 | Finish = 2, 518 | InstructionFault = 4, 519 | DataFault = 8, 520 | Mask = 15, 521 | }; 522 | } 523 | 524 | } 525 | --------------------------------------------------------------------------------