├── .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 |
--------------------------------------------------------------------------------